Revert "Added SetAntiForgeryCookieAndHeader method that sets cookie token and header"
This reverts commit 951ed05893.
This commit is contained in:
parent
951ed05893
commit
c8a13087a6
|
|
@ -97,14 +97,5 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
Validate(context, antiForgeryTokenSet.CookieToken, antiForgeryTokenSet.FormToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates and sets an anti-forgery cookie if one is not available or not valid. Also sets response headers.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP context associated with the current call.</param>
|
||||
public void SetCookieTokenAndHeader([NotNull] HttpContext context)
|
||||
{
|
||||
_worker.SetCookieTokenAndHeader(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,8 +102,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
var tokenSet = GetTokens(httpContext, oldCookieToken);
|
||||
var newCookieToken = tokenSet.CookieToken;
|
||||
var formToken = tokenSet.FormToken;
|
||||
if (newCookieToken != null)
|
||||
{
|
||||
// If a new cookie was generated, persist it.
|
||||
_tokenStore.SaveCookieToken(httpContext, newCookieToken);
|
||||
}
|
||||
|
||||
SaveCookieTokenAndHeader(httpContext, newCookieToken);
|
||||
if (!_config.SuppressXFrameOptionsHeader)
|
||||
{
|
||||
// Adding X-Frame-Options header to prevent ClickJacking. See
|
||||
// http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-10
|
||||
// for more information.
|
||||
httpContext.Response.Headers.Set("X-Frame-Options", "SAMEORIGIN");
|
||||
}
|
||||
|
||||
// <input type="hidden" name="__AntiForgeryToken" value="..." />
|
||||
var retVal = new TagBuilder("input");
|
||||
|
|
@ -132,11 +143,15 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
private AntiForgeryTokenSetInternal GetTokens(HttpContext httpContext, AntiForgeryToken oldCookieToken)
|
||||
{
|
||||
var newCookieToken = ValidateAndGenerateNewToken(oldCookieToken);
|
||||
if (newCookieToken != null)
|
||||
AntiForgeryToken newCookieToken = null;
|
||||
if (!_validator.IsCookieTokenValid(oldCookieToken))
|
||||
{
|
||||
oldCookieToken = newCookieToken;
|
||||
// Need to make sure we're always operating with a good cookie token.
|
||||
oldCookieToken = newCookieToken = _generator.GenerateCookieToken();
|
||||
}
|
||||
|
||||
Debug.Assert(_validator.IsCookieTokenValid(oldCookieToken));
|
||||
|
||||
var formToken = _generator.GenerateFormToken(
|
||||
httpContext,
|
||||
ExtractIdentity(httpContext),
|
||||
|
|
@ -189,54 +204,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
deserializedFormToken);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates and sets an anti-forgery cookie if one is not available or not valid. Also sets response headers.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP context associated with the current call.</param>
|
||||
public void SetCookieTokenAndHeader([NotNull] HttpContext httpContext)
|
||||
{
|
||||
CheckSSLConfig(httpContext);
|
||||
|
||||
var oldCookieToken = GetCookieTokenNoThrow(httpContext);
|
||||
var newCookieToken = ValidateAndGenerateNewToken(oldCookieToken);
|
||||
|
||||
SaveCookieTokenAndHeader(httpContext, newCookieToken);
|
||||
}
|
||||
|
||||
// This method returns null if oldCookieToken is valid.
|
||||
private AntiForgeryToken ValidateAndGenerateNewToken(AntiForgeryToken oldCookieToken)
|
||||
{
|
||||
if (!_validator.IsCookieTokenValid(oldCookieToken))
|
||||
{
|
||||
// Need to make sure we're always operating with a good cookie token.
|
||||
var newCookieToken = _generator.GenerateCookieToken();
|
||||
Debug.Assert(_validator.IsCookieTokenValid(newCookieToken));
|
||||
return newCookieToken;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SaveCookieTokenAndHeader(
|
||||
[NotNull] HttpContext httpContext,
|
||||
AntiForgeryToken newCookieToken)
|
||||
{
|
||||
if (newCookieToken != null)
|
||||
{
|
||||
// Persist the new cookie if it is not null.
|
||||
_tokenStore.SaveCookieToken(httpContext, newCookieToken);
|
||||
}
|
||||
|
||||
if (!_config.SuppressXFrameOptionsHeader)
|
||||
{
|
||||
// Adding X-Frame-Options header to prevent ClickJacking. See
|
||||
// http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-10
|
||||
// for more information.
|
||||
httpContext.Response.Headers.Set("X-Frame-Options", "SAMEORIGIN");
|
||||
}
|
||||
}
|
||||
|
||||
private class AntiForgeryTokenSetInternal
|
||||
{
|
||||
public AntiForgeryToken FormToken { get; set; }
|
||||
|
|
|
|||
|
|
@ -561,10 +561,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <returns>A<see cref="Task{HtmlString}"/> that represents the asynchronous flush operation and on
|
||||
/// completion returns a <see cref="HtmlString.Empty"/>.</returns>
|
||||
/// <remarks>The value returned is a token value that allows FlushAsync to work directly in an HTML
|
||||
/// section. However the value does not represent the rendered content.
|
||||
/// This method also writes out headers, so any modifications to headers must be done before FulshAsync is
|
||||
/// called. For example, call <see cref="SetAntiForgeryCookieAndHeader"/> to send anti-forgery cookie token
|
||||
/// and X-Frame-Options header to client before this method flushes headers out. </remarks>
|
||||
/// section. However the value does not represent the rendered content.</remarks>
|
||||
public async Task<HtmlString> FlushAsync()
|
||||
{
|
||||
// If there are active writing scopes then we should throw. Cannot flush content that has the potential to
|
||||
|
|
@ -620,20 +617,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
PageExecutionContext?.EndContext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets anti-forgery cookie and X-Frame-Options header on the response.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="HtmlString"/> that returns a <see cref="HtmlString.Empty"/>.</returns>
|
||||
/// <remarks> Call this method to send anti-forgery cookie token and X-Frame-Options header to client
|
||||
/// before <see cref="FlushAsync"/> flushes the headers. </remarks>
|
||||
public virtual HtmlString SetAntiForgeryCookieAndHeader()
|
||||
{
|
||||
var antiForgery = Context.RequestServices.GetRequiredService<AntiForgery>();
|
||||
antiForgery.SetCookieTokenAndHeader(Context);
|
||||
|
||||
return HtmlString.Empty;
|
||||
}
|
||||
|
||||
private void EnsureMethodCanBeInvoked(string methodName)
|
||||
{
|
||||
if (PreviousSectionWriters == null)
|
||||
|
|
|
|||
|
|
@ -379,29 +379,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
context.TokenProvider.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, "SAMEORIGIN")]
|
||||
[InlineData(true, null)]
|
||||
public void SetCookieTokenAndHeader_AddsXFrameOptionsHeader(bool suppressXFrameOptions, string expectedHeaderValue)
|
||||
{
|
||||
// Arrange
|
||||
var options = new AntiForgeryOptions()
|
||||
{
|
||||
SuppressXFrameOptionsHeader = suppressXFrameOptions
|
||||
};
|
||||
|
||||
// Genreate a new cookie.
|
||||
var context = GetAntiForgeryWorkerContext(options, useOldCookie: false, isOldCookieValid: false);
|
||||
var worker = GetAntiForgeryWorker(context);
|
||||
|
||||
// Act
|
||||
worker.SetCookieTokenAndHeader(context.HttpContext.Object);
|
||||
|
||||
// Assert
|
||||
var xFrameOptions = context.HttpContext.Object.Response.Headers["X-Frame-Options"];
|
||||
Assert.Equal(expectedHeaderValue, xFrameOptions);
|
||||
}
|
||||
|
||||
private AntiForgeryWorker GetAntiForgeryWorker(AntiForgeryWorkerContext context)
|
||||
{
|
||||
return new AntiForgeryWorker(
|
||||
|
|
|
|||
|
|
@ -234,117 +234,5 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
Assert.Equal("The required anti-forgery form field \"__RequestVerificationToken\" is not present.",
|
||||
exception.ExceptionMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetCookieAndHeaderBeforeFlushAsync_GeneratesCookieTokenAndHeader()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Account/FlushAsyncLogin");
|
||||
|
||||
// Assert
|
||||
var header = Assert.Single(response.Headers.GetValues("X-Frame-Options"));
|
||||
Assert.Equal("SAMEORIGIN", header);
|
||||
|
||||
var setCookieHeader = response.Headers.GetValues("Set-Cookie").ToArray();
|
||||
|
||||
var cookie = Assert.Single(setCookieHeader);
|
||||
Assert.True(cookie.StartsWith("__RequestVerificationToken"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetCookieAndHeaderBeforeFlushAsync_PostToForm()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// do a get response.
|
||||
var getResponse = await client.GetAsync("http://localhost/Account/FlushAsyncLogin");
|
||||
var resposneBody = await getResponse.Content.ReadAsStringAsync();
|
||||
|
||||
var formToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(resposneBody, "Account/FlushAsyncLogin");
|
||||
var cookieToken = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/FlushAsyncLogin");
|
||||
request.Headers.Add("Cookie", "__RequestVerificationToken=" + cookieToken);
|
||||
var nameValueCollection = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string,string>("__RequestVerificationToken", formToken),
|
||||
new KeyValuePair<string,string>("UserName", "test"),
|
||||
new KeyValuePair<string,string>("Password", "password"),
|
||||
};
|
||||
|
||||
request.Content = new FormUrlEncodedContent(nameValueCollection);
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("OK", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FlushAsyncBeforeAntiForgery_CookieAndHeaderNotInResponse()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Account/FlushWithoutUpdatingHeader");
|
||||
|
||||
// Assert
|
||||
IEnumerable<string> returnList;
|
||||
Assert.False(response.Headers.TryGetValues("Set-Cookie", out returnList));
|
||||
Assert.False(response.Headers.TryGetValues("X-Frame-Options", out returnList));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FlushAsyncBeforeAntiForgery_PostToForm()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// do a get response.
|
||||
var getResponse = await client.GetAsync("http://localhost/Account/FlushWithoutUpdatingHeader");
|
||||
var resposneBody = await getResponse.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert - 1
|
||||
IEnumerable<string> returnList;
|
||||
Assert.False(getResponse.Headers.TryGetValues("Set-Cookie", out returnList));
|
||||
Assert.False(getResponse.Headers.TryGetValues("X-Frame-Options", out returnList));
|
||||
|
||||
var formToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(
|
||||
resposneBody,
|
||||
"Account/FlushWithoutUpdatingHeader");
|
||||
|
||||
var request = new HttpRequestMessage(
|
||||
HttpMethod.Post,
|
||||
"http://localhost/Account/FlushWithoutUpdatingHeader");
|
||||
|
||||
var nameValueCollection = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string,string>("__RequestVerificationToken", formToken),
|
||||
new KeyValuePair<string,string>("UserName", "test"),
|
||||
new KeyValuePair<string,string>("Password", "password"),
|
||||
};
|
||||
|
||||
request.Content = new FormUrlEncodedContent(nameValueCollection);
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert - 2
|
||||
var exception = response.GetServerException();
|
||||
Assert.Equal("The required anti-forgery cookie \"__RequestVerificationToken\" is not present.",
|
||||
exception.ExceptionMessage);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -31,41 +31,5 @@ namespace AntiForgeryWebSite
|
|||
{
|
||||
return "OK";
|
||||
}
|
||||
|
||||
// GET: /Account/FlushAsyncLogin
|
||||
[AllowAnonymous]
|
||||
public ActionResult FlushAsyncLogin(string returnUrl = null)
|
||||
{
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
// POST: /Account/FlushAsyncLogin
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public string FlushAsyncLogin(LoginViewModel model)
|
||||
{
|
||||
return "OK";
|
||||
}
|
||||
|
||||
// GET: /Account/FlushWithoutUpdatingHeader
|
||||
[AllowAnonymous]
|
||||
public ActionResult FlushWithoutUpdatingHeader(string returnUrl = null)
|
||||
{
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
// POST: /Account/FlushWithoutUpdatingHeader
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public string FlushWithoutUpdatingHeader(LoginViewModel model)
|
||||
{
|
||||
return "OK";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
@model AntiForgeryWebSite.LoginViewModel
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Log in";
|
||||
Layout = "/Views/Shared/_FlushAsyncLayout.cshtml";
|
||||
}
|
||||
|
||||
@section Login
|
||||
{
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<section id="loginForm">
|
||||
@using (Html.BeginForm("FlushAsyncLogin", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<h4>Use a local account to log in.</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary(true)
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2", ClAsS = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.UserName, new { @class = "...", cLass = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.UserName)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.Password)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Log in" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
@model AntiForgeryWebSite.LoginViewModel
|
||||
|
||||
@await FlushAsync()
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<section id="loginForm">
|
||||
@using (Html.BeginForm("FlushWithoutUpdatingHeader", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<h4>Use a local account to log in.</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary(true)
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2", ClAsS = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.UserName, new { @class = "...", cLass = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.UserName)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.Password)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Log in" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>@ViewBag.Title – AntiForgery Functional Tests</title>
|
||||
</head>
|
||||
@SetAntiForgeryCookieAndHeader()
|
||||
@await FlushAsync()
|
||||
|
||||
<body>
|
||||
@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })
|
||||
<div class="container body-content">
|
||||
@RenderBody()
|
||||
@await RenderSectionAsync("Login", required: false)
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue