Change priority for request token source lookup. Header token now takes priority over form field token.

This commit is contained in:
Kiran Challa 2016-05-18 16:54:13 -07:00
parent f65c3db6ef
commit 3595452af7
2 changed files with 45 additions and 67 deletions

View File

@ -44,8 +44,16 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
var cookieToken = httpContext.Request.Cookies[_options.CookieName];
// We want to delay reading the form as much as possible, for example in case of large file uploads,
// request token could be part of the header.
StringValues requestToken;
if (httpContext.Request.HasFormContentType)
if (_options.HeaderName != null)
{
requestToken = httpContext.Request.Headers[_options.HeaderName];
}
// Fall back to reading form instead
if (requestToken.Count == 0 && httpContext.Request.HasFormContentType)
{
// Check the content-type before accessing the form collection to make sure
// we report errors gracefully.
@ -53,12 +61,6 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
requestToken = form[_options.FormFieldName];
}
// Fall back to header if the form value was not provided.
if (requestToken.Count == 0 && _options.HeaderName != null)
{
requestToken = httpContext.Request.Headers[_options.HeaderName];
}
return new AntiforgeryTokenSet(requestToken, cookieToken, _options.FormFieldName, _options.HeaderName);
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
@ -99,39 +100,15 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
}
[Fact]
public async Task GetRequestTokens_NonFormContentType_HeaderDisabled_ReturnsNullToken()
{
// Arrange
var httpContext = GetHttpContext("cookie-name", "cookie-value");
httpContext.Request.ContentType = "application/json";
// Will not be accessed
httpContext.Request.Form = null;
var options = new AntiforgeryOptions()
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = null,
};
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
// Act
var tokenSet = await tokenStore.GetRequestTokensAsync(httpContext);
// Assert
Assert.Equal("cookie-value", tokenSet.CookieToken);
Assert.Null(tokenSet.RequestToken);
}
[Fact]
public async Task GetRequestTokens_FormContentType_FallbackHeaderToken()
public async Task GetRequestTokens_HeaderTokenTakensPriority_OverFormToken()
{
// Arrange
var httpContext = GetHttpContext("cookie-name", "cookie-value");
httpContext.Request.ContentType = "application/x-www-form-urlencoded";
httpContext.Request.Form = FormCollection.Empty;
httpContext.Request.Form = new FormCollection(new Dictionary<string, StringValues>
{
{ "form-field-name", "form-value" },
}); // header value has priority.
httpContext.Request.Headers.Add("header-name", "header-value");
var options = new AntiforgeryOptions()
@ -151,6 +128,34 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
Assert.Equal("header-value", tokens.RequestToken);
}
[Fact]
public async Task GetRequestTokens_NoHeaderToken_FallsBackToFormToken()
{
// Arrange
var httpContext = GetHttpContext("cookie-name", "cookie-value");
httpContext.Request.ContentType = "application/x-www-form-urlencoded";
httpContext.Request.Form = new FormCollection(new Dictionary<string, StringValues>
{
{ "form-field-name", "form-value" },
});
var options = new AntiforgeryOptions()
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = "header-name",
};
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
// Act
var tokens = await tokenStore.GetRequestTokensAsync(httpContext);
// Assert
Assert.Equal("cookie-value", tokens.CookieToken);
Assert.Equal("form-value", tokens.RequestToken);
}
[Fact]
public async Task GetRequestTokens_NonFormContentType_UsesHeaderToken()
{
@ -180,7 +185,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
}
[Fact]
public async Task GetRequestTokens_NonFormContentType_NoHeaderToken_ReturnsNullToken()
public async Task GetRequestTokens_NoHeaderToken_NonFormContentType_ReturnsNullToken()
{
// Arrange
var httpContext = GetHttpContext("cookie-name", "cookie-value");
@ -207,7 +212,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
}
[Fact]
public async Task GetRequestTokens_BothFieldsEmpty_ReturnsNullTokens()
public async Task GetRequestTokens_BothHeaderValueAndFormFieldsEmpty_ReturnsNullTokens()
{
// Arrange
var httpContext = GetHttpContext("cookie-name", "cookie-value");
@ -231,35 +236,6 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
Assert.Null(tokenSet.RequestToken);
}
[Fact]
public async Task GetFormToken_FormFieldIsValid_ReturnsToken()
{
// Arrange
var httpContext = GetHttpContext("cookie-name", "cookie-value");
httpContext.Request.ContentType = "application/x-www-form-urlencoded";
httpContext.Request.Form = new FormCollection(new Dictionary<string, StringValues>
{
{ "form-field-name", "form-value" },
});
httpContext.Request.Headers.Add("header-name", "header-value"); // form value has priority.
var options = new AntiforgeryOptions()
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = "header-name",
};
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
// Act
var tokens = await tokenStore.GetRequestTokensAsync(httpContext);
// Assert
Assert.Equal("cookie-value", tokens.CookieToken);
Assert.Equal("form-value", tokens.RequestToken);
}
[Theory]
[InlineData(true, true)]
[InlineData(false, null)]