This change adds support for retrieving an antiforgery CSRF token via a
configurable header in addition to the form field. This helps with doing
ajax requests in a 1st-party SPA when using cookie auth, and is similar to
functionality provided by a bunch of different frameworks.

In this change there's also a bunch of churn due to avoiding the term
'form' in favor of 'request' and 'session' in favor of 'cookie'. Where
code and error message now mention 'form' they specifically mean
form-encoded content.
This commit is contained in:
Ryan Nowak 2015-12-15 10:45:05 -08:00
Родитель b69aef3c51
Коммит 3280ff6ac5
18 изменённых файлов: 370 добавлений и 191 удалений

Просмотреть файл

@ -40,7 +40,7 @@ namespace AntiforgerySample
</html>";
var tokenSet = _antiforgery.GetAndStoreTokens(context);
await context.Response.WriteAsync(string.Format(page, _options.FormFieldName, tokenSet.FormToken));
await context.Response.WriteAsync(string.Format(page, _options.FormFieldName, tokenSet.RequestToken));
}
else if (context.Request.Method == "POST")
{

Просмотреть файл

@ -11,16 +11,17 @@ namespace Microsoft.AspNet.Antiforgery
public class AntiforgeryOptions
{
private const string AntiforgeryTokenFieldName = "__RequestVerificationToken";
private const string AntiforgertyTokenHeaderName = "RequestVerificationToken";
private string _cookieName;
private string _headerName = AntiforgertyTokenHeaderName;
private string _formFieldName = AntiforgeryTokenFieldName;
/// <summary>
/// Specifies the name of the cookie that is used by the antiforgery
/// system.
/// Specifies the name of the cookie that is used by the antiforgery system.
/// </summary>
/// <remarks>
/// If an explicit name is not provided, the system will automatically
/// generate a name.
/// If an explicit name is not provided, the system will automatically generate a name.
/// </remarks>
public string CookieName
{
@ -59,6 +60,16 @@ namespace Microsoft.AspNet.Antiforgery
}
}
/// <summary>
/// Specifies the name of the header value that is used by the antiforgery system. If <c>null</c> then
/// antiforgery validation will only consider form data.
/// </summary>
public string HeaderName
{
get { return _headerName; }
set { _headerName = value; }
}
/// <summary>
/// Specifies whether SSL is required for the antiforgery system
/// to operate. If this setting is 'true' and a non-SSL request

Просмотреть файл

@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Antiforgery
public BinaryBlob ClaimUid { get; set; }
public bool IsSessionToken { get; set; }
public bool IsCookieToken { get; set; }
public BinaryBlob SecurityToken
{

Просмотреть файл

@ -6,23 +6,23 @@ using System;
namespace Microsoft.AspNet.Antiforgery
{
/// <summary>
/// The antiforgery token pair (cookie and form token) for a request.
/// The antiforgery token pair (cookie and request token) for a request.
/// </summary>
public class AntiforgeryTokenSet
{
/// <summary>
/// Creates the antiforgery token pair (cookie and form token) for a request.
/// Creates the antiforgery token pair (cookie and request token) for a request.
/// </summary>
/// <param name="formToken">The token that is supplied in the request form body.</param>
/// <param name="requestToken">The token that is supplied in the request.</param>
/// <param name="cookieToken">The token that is supplied in the request cookie.</param>
public AntiforgeryTokenSet(string formToken, string cookieToken)
public AntiforgeryTokenSet(string requestToken, string cookieToken)
{
if (string.IsNullOrEmpty(formToken))
if (string.IsNullOrEmpty(requestToken))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(formToken));
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(requestToken));
}
FormToken = formToken;
RequestToken = requestToken;
// Cookie Token is allowed to be null in the case when the old cookie is valid
// and there is no new cookieToken generated.
@ -30,9 +30,9 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// The token that is supplied in the request form body.
/// The token that is supplied in the request.
/// </summary>
public string FormToken { get; private set; }
public string RequestToken { get; private set; }
/// The cookie token is allowed to be null.
/// This would be the case when the old cookie token is still valid.

Просмотреть файл

@ -45,14 +45,14 @@ namespace Microsoft.AspNet.Antiforgery
var tokenSet = GetAndStoreTokens(context);
// Though FormToken normally contains only US-ASCII letters, numbers, '-', and '_', must assume the
// Though RequestToken normally contains only US-ASCII letters, numbers, '-', and '_', must assume the
// IAntiforgeryTokenSerializer implementation has been overridden. Similarly, users may choose a
// FormFieldName containing almost any character.
var content = new HtmlContentBuilder()
.AppendHtml("<input name=\"")
.Append(_options.FormFieldName)
.AppendHtml("\" type=\"hidden\" value=\"")
.Append(tokenSet.FormToken)
.Append(tokenSet.RequestToken)
.AppendHtml("\" />");
return content;
@ -122,22 +122,22 @@ namespace Microsoft.AspNet.Antiforgery
nameof(antiforgeryTokenSet));
}
if (string.IsNullOrEmpty(antiforgeryTokenSet.FormToken))
if (string.IsNullOrEmpty(antiforgeryTokenSet.RequestToken))
{
throw new ArgumentException(
Resources.Antiforgery_FormToken_MustBeProvided_Generic,
Resources.Antiforgery_RequestToken_MustBeProvided_Generic,
nameof(antiforgeryTokenSet));
}
// Extract cookie & form tokens
// Extract cookie & request tokens
var deserializedCookieToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.CookieToken);
var deserializedFormToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.FormToken);
var deserializedRequestToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.RequestToken);
// Validate
_tokenGenerator.ValidateTokens(
context,
deserializedCookieToken,
deserializedFormToken);
deserializedRequestToken);
}
/// <inheritdoc />
@ -225,7 +225,7 @@ namespace Microsoft.AspNet.Antiforgery
{
cookieToken = newCookieToken;
}
var formToken = _tokenGenerator.GenerateFormToken(
var requestToken = _tokenGenerator.GenerateRequestToken(
context,
cookieToken);
@ -233,7 +233,7 @@ namespace Microsoft.AspNet.Antiforgery
{
// Note : The new cookie would be null if the old cookie is valid.
CookieToken = cookieToken,
FormToken = formToken,
RequestToken = requestToken,
IsNewCookieToken = newCookieToken != null
};
}
@ -241,13 +241,13 @@ namespace Microsoft.AspNet.Antiforgery
private AntiforgeryTokenSet Serialize(AntiforgeryTokenSetInternal tokenSet)
{
return new AntiforgeryTokenSet(
tokenSet.FormToken != null ? _tokenSerializer.Serialize(tokenSet.FormToken) : null,
tokenSet.RequestToken != null ? _tokenSerializer.Serialize(tokenSet.RequestToken) : null,
tokenSet.CookieToken != null ? _tokenSerializer.Serialize(tokenSet.CookieToken) : null);
}
private class AntiforgeryTokenSetInternal
{
public AntiforgeryToken FormToken { get; set; }
public AntiforgeryToken RequestToken { get; set; }
public AntiforgeryToken CookieToken { get; set; }

Просмотреть файл

@ -27,11 +27,11 @@ namespace Microsoft.AspNet.Antiforgery
return new AntiforgeryToken()
{
// SecurityToken will be populated automatically.
IsSessionToken = true
IsCookieToken = true
};
}
public AntiforgeryToken GenerateFormToken(
public AntiforgeryToken GenerateRequestToken(
HttpContext httpContext,
AntiforgeryToken cookieToken)
{
@ -42,10 +42,10 @@ namespace Microsoft.AspNet.Antiforgery
Debug.Assert(IsCookieTokenValid(cookieToken));
var formToken = new AntiforgeryToken()
var requestToken = new AntiforgeryToken()
{
SecurityToken = cookieToken.SecurityToken,
IsSessionToken = false
IsCookieToken = false
};
var isIdentityAuthenticated = false;
@ -55,23 +55,23 @@ namespace Microsoft.AspNet.Antiforgery
if (identity != null && identity.IsAuthenticated)
{
isIdentityAuthenticated = true;
formToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(identity));
if (formToken.ClaimUid == null)
requestToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(identity));
if (requestToken.ClaimUid == null)
{
formToken.Username = identity.Name;
requestToken.Username = identity.Name;
}
}
// populate AdditionalData
if (_additionalDataProvider != null)
{
formToken.AdditionalData = _additionalDataProvider.GetAdditionalData(httpContext);
requestToken.AdditionalData = _additionalDataProvider.GetAdditionalData(httpContext);
}
if (isIdentityAuthenticated
&& string.IsNullOrEmpty(formToken.Username)
&& formToken.ClaimUid == null
&& string.IsNullOrEmpty(formToken.AdditionalData))
&& string.IsNullOrEmpty(requestToken.Username)
&& requestToken.ClaimUid == null
&& string.IsNullOrEmpty(requestToken.AdditionalData))
{
// Application says user is authenticated, but we have no identifier for the user.
throw new InvalidOperationException(
@ -84,46 +84,46 @@ namespace Microsoft.AspNet.Antiforgery
nameof(DefaultAntiforgeryAdditionalDataProvider)));
}
return formToken;
return requestToken;
}
public bool IsCookieTokenValid(AntiforgeryToken cookieToken)
{
return (cookieToken != null && cookieToken.IsSessionToken);
return (cookieToken != null && cookieToken.IsCookieToken);
}
public void ValidateTokens(
HttpContext httpContext,
AntiforgeryToken sessionToken,
AntiforgeryToken fieldToken)
AntiforgeryToken cookieToken,
AntiforgeryToken requestToken)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (sessionToken == null)
if (cookieToken == null)
{
throw new ArgumentNullException(
nameof(sessionToken),
nameof(cookieToken),
Resources.Antiforgery_CookieToken_MustBeProvided_Generic);
}
if (fieldToken == null)
if (requestToken == null)
{
throw new ArgumentNullException(
nameof(fieldToken),
Resources.Antiforgery_FormToken_MustBeProvided_Generic);
nameof(requestToken),
Resources.Antiforgery_RequestToken_MustBeProvided_Generic);
}
// Do the tokens have the correct format?
if (!sessionToken.IsSessionToken || fieldToken.IsSessionToken)
if (!cookieToken.IsCookieToken || requestToken.IsCookieToken)
{
throw new InvalidOperationException(Resources.AntiforgeryToken_TokensSwapped);
}
// Are the security tokens embedded in each incoming token identical?
if (!Equals(sessionToken.SecurityToken, fieldToken.SecurityToken))
if (!Equals(cookieToken.SecurityToken, requestToken.SecurityToken))
{
throw new InvalidOperationException(Resources.AntiforgeryToken_SecurityTokenMismatch);
}
@ -148,24 +148,24 @@ namespace Microsoft.AspNet.Antiforgery
currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
if (!string.Equals(fieldToken.Username,
if (!string.Equals(requestToken.Username,
currentUsername,
(useCaseSensitiveUsernameComparison) ?
StringComparison.Ordinal :
StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
Resources.FormatAntiforgeryToken_UsernameMismatch(fieldToken.Username, currentUsername));
Resources.FormatAntiforgeryToken_UsernameMismatch(requestToken.Username, currentUsername));
}
if (!Equals(fieldToken.ClaimUid, currentClaimUid))
if (!Equals(requestToken.ClaimUid, currentClaimUid))
{
throw new InvalidOperationException(Resources.AntiforgeryToken_ClaimUidMismatch);
}
// Is the AdditionalData valid?
if (_additionalDataProvider != null &&
!_additionalDataProvider.ValidateAdditionalData(httpContext, fieldToken.AdditionalData))
!_additionalDataProvider.ValidateAdditionalData(httpContext, requestToken.AdditionalData))
{
throw new InvalidOperationException(Resources.AntiforgeryToken_AdditionalDataCheckFailed);
}

Просмотреть файл

@ -56,8 +56,8 @@ namespace Microsoft.AspNet.Antiforgery
/* The serialized format of the anti-XSRF token is as follows:
* Version: 1 byte integer
* SecurityToken: 16 byte binary blob
* IsSessionToken: 1 byte Boolean
* [if IsSessionToken != true]
* IsCookieToken: 1 byte Boolean
* [if IsCookieToken != true]
* +- IsClaimsBased: 1 byte Boolean
* | [if IsClaimsBased = true]
* | `- ClaimUid: 32 byte binary blob
@ -78,9 +78,9 @@ namespace Microsoft.AspNet.Antiforgery
var securityTokenBytes = reader.ReadBytes(AntiforgeryToken.SecurityTokenBitLength / 8);
deserializedToken.SecurityToken =
new BinaryBlob(AntiforgeryToken.SecurityTokenBitLength, securityTokenBytes);
deserializedToken.IsSessionToken = reader.ReadBoolean();
deserializedToken.IsCookieToken = reader.ReadBoolean();
if (!deserializedToken.IsSessionToken)
if (!deserializedToken.IsCookieToken)
{
var isClaimsBased = reader.ReadBoolean();
if (isClaimsBased)
@ -119,9 +119,9 @@ namespace Microsoft.AspNet.Antiforgery
{
writer.Write(TokenVersion);
writer.Write(token.SecurityToken.GetData());
writer.Write(token.IsSessionToken);
writer.Write(token.IsCookieToken);
if (!token.IsSessionToken)
if (!token.IsCookieToken)
{
if (token.ClaimUid != null)
{

Просмотреть файл

@ -7,10 +7,10 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Antiforgery
{
// Saves anti-XSRF tokens split between HttpRequest.Cookies and HttpRequest.Form
public class DefaultAntiforgeryTokenStore : IAntiforgeryTokenStore
{
private readonly AntiforgeryOptions _options;
@ -72,23 +72,43 @@ namespace Microsoft.AspNet.Antiforgery
Resources.FormatAntiforgery_CookieToken_MustBeProvided(_options.CookieName));
}
if (!httpContext.Request.HasFormContentType)
StringValues requestToken;
if (httpContext.Request.HasFormContentType)
{
// Check the content-type before accessing the form collection to make sure
// we throw gracefully.
throw new InvalidOperationException(
Resources.FormatAntiforgery_FormToken_MustBeProvided(_options.FormFieldName));
var form = await httpContext.Request.ReadFormAsync();
requestToken = form[_options.FormFieldName];
}
var form = await httpContext.Request.ReadFormAsync();
var formField = form[_options.FormFieldName];
if (string.IsNullOrEmpty(formField))
// Fall back to header if the form value was not provided.
if (requestToken.Count == 0 && _options.HeaderName != null)
{
throw new InvalidOperationException(
Resources.FormatAntiforgery_FormToken_MustBeProvided(_options.FormFieldName));
requestToken = httpContext.Request.Headers[_options.HeaderName];
}
return new AntiforgeryTokenSet(formField, requestCookie);
if (requestToken.Count == 0)
{
if (_options.HeaderName == null)
{
var message = Resources.FormatAntiforgery_FormToken_MustBeProvided(_options.FormFieldName);
throw new InvalidOperationException(message);
}
else if (!httpContext.Request.HasFormContentType)
{
var message = Resources.FormatAntiforgery_HeaderToken_MustBeProvided(_options.HeaderName);
throw new InvalidOperationException(message);
}
else
{
var message = Resources.FormatAntiforgery_RequestToken_MustBeProvided(
_options.FormFieldName,
_options.HeaderName);
throw new InvalidOperationException(message);
}
}
return new AntiforgeryTokenSet(requestToken, requestCookie);
}
public void SaveCookieToken(HttpContext httpContext, AntiforgeryToken token)

Просмотреть файл

@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Antiforgery
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="antiforgeryTokenSet">
/// The <see cref="AntiforgeryTokenSet"/> (cookie and form token) for this request.
/// The <see cref="AntiforgeryTokenSet"/> (cookie and request token) for this request.
/// </param>
void ValidateTokens(HttpContext context, AntiforgeryTokenSet antiforgeryTokenSet);

Просмотреть файл

@ -13,9 +13,9 @@ namespace Microsoft.AspNet.Antiforgery
// Generates a new random cookie token.
AntiforgeryToken GenerateCookieToken();
// Given a cookie token, generates a corresponding form token.
// Given a cookie token, generates a corresponding request token.
// The incoming cookie token must be valid.
AntiforgeryToken GenerateFormToken(
AntiforgeryToken GenerateRequestToken(
HttpContext httpContext,
AntiforgeryToken cookieToken);
@ -23,10 +23,10 @@ namespace Microsoft.AspNet.Antiforgery
// If it is not, the caller must call GenerateCookieToken() before calling GenerateFormToken().
bool IsCookieTokenValid(AntiforgeryToken cookieToken);
// Validates a (cookie, form) token pair.
// Validates a (cookie, request) token pair.
void ValidateTokens(
HttpContext httpContext,
AntiforgeryToken cookieToken,
AntiforgeryToken formToken);
AntiforgeryToken requestToken);
}
}

Просмотреть файл

@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Antiforgery
AntiforgeryToken GetCookieToken(HttpContext httpContext);
/// <summary>
/// Gets the cookie and form tokens from the request. Will throw an exception if either token is
/// Gets the cookie and request tokens from the request. Will throw an exception if either token is
/// not present.
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> for the current request.</param>

Просмотреть файл

@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// The antiforgery cookie token and form field token do not match.
/// The antiforgery cookie token and request token do not match.
/// </summary>
internal static string AntiforgeryToken_SecurityTokenMismatch
{
@ -83,7 +83,7 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// The antiforgery cookie token and form field token do not match.
/// The antiforgery cookie token and request token do not match.
/// </summary>
internal static string FormatAntiforgeryToken_SecurityTokenMismatch()
{
@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// Validation of the provided antiforgery token failed. The cookie token and the form token were swapped.
/// Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.
/// </summary>
internal static string AntiforgeryToken_TokensSwapped
{
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// Validation of the provided antiforgery token failed. The cookie token and the form token were swapped.
/// Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.
/// </summary>
internal static string FormatAntiforgeryToken_TokensSwapped()
{
@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// The cookie token must be provided.
/// The required antiforgery cookie token must be provided.
/// </summary>
internal static string Antiforgery_CookieToken_MustBeProvided_Generic
{
@ -163,7 +163,7 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// The cookie token must be provided.
/// The required antiforgery cookie token must be provided.
/// </summary>
internal static string FormatAntiforgery_CookieToken_MustBeProvided_Generic()
{
@ -187,19 +187,51 @@ namespace Microsoft.AspNet.Antiforgery
}
/// <summary>
/// The form token must be provided.
/// The required antiforgery header value "{0}" is not present.
/// </summary>
internal static string Antiforgery_FormToken_MustBeProvided_Generic
internal static string Antiforgery_HeaderToken_MustBeProvided
{
get { return GetString("Antiforgery_FormToken_MustBeProvided_Generic"); }
get { return GetString("Antiforgery_HeaderToken_MustBeProvided"); }
}
/// <summary>
/// The form token must be provided.
/// The required antiforgery header value "{0}" is not present.
/// </summary>
internal static string FormatAntiforgery_FormToken_MustBeProvided_Generic()
internal static string FormatAntiforgery_HeaderToken_MustBeProvided(object p0)
{
return GetString("Antiforgery_FormToken_MustBeProvided_Generic");
return string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_HeaderToken_MustBeProvided"), p0);
}
/// <summary>
/// The required antiforgery request token was not provided in either form field "{0}" or header value "{1}".
/// </summary>
internal static string Antiforgery_RequestToken_MustBeProvided
{
get { return GetString("Antiforgery_RequestToken_MustBeProvided"); }
}
/// <summary>
/// The required antiforgery request token was not provided in either form field "{0}" or header value "{1}".
/// </summary>
internal static string FormatAntiforgery_RequestToken_MustBeProvided(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_RequestToken_MustBeProvided"), p0, p1);
}
/// <summary>
/// The required antiforgery request token must be provided.
/// </summary>
internal static string Antiforgery_RequestToken_MustBeProvided_Generic
{
get { return GetString("Antiforgery_RequestToken_MustBeProvided_Generic"); }
}
/// <summary>
/// The required antiforgery request token must be provided.
/// </summary>
internal static string FormatAntiforgery_RequestToken_MustBeProvided_Generic()
{
return GetString("Antiforgery_RequestToken_MustBeProvided_Generic");
}
/// <summary>

Просмотреть файл

@ -131,10 +131,10 @@
<value>The antiforgery token could not be decrypted.</value>
</data>
<data name="AntiforgeryToken_SecurityTokenMismatch" xml:space="preserve">
<value>The antiforgery cookie token and form field token do not match.</value>
<value>The antiforgery cookie token and request token do not match.</value>
</data>
<data name="AntiforgeryToken_TokensSwapped" xml:space="preserve">
<value>Validation of the provided antiforgery token failed. The cookie token and the form token were swapped.</value>
<value>Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.</value>
</data>
<data name="AntiforgeryToken_UsernameMismatch" xml:space="preserve">
<value>The provided antiforgery token was meant for user "{0}", but the current user is "{1}".</value>
@ -147,13 +147,19 @@
<value>The required antiforgery cookie "{0}" is not present.</value>
</data>
<data name="Antiforgery_CookieToken_MustBeProvided_Generic" xml:space="preserve">
<value>The cookie token must be provided.</value>
<value>The required antiforgery cookie token must be provided.</value>
</data>
<data name="Antiforgery_FormToken_MustBeProvided" xml:space="preserve">
<value>The required antiforgery form field "{0}" is not present.</value>
</data>
<data name="Antiforgery_FormToken_MustBeProvided_Generic" xml:space="preserve">
<value>The form token must be provided.</value>
<data name="Antiforgery_HeaderToken_MustBeProvided" xml:space="preserve">
<value>The required antiforgery header value "{0}" is not present.</value>
</data>
<data name="Antiforgery_RequestToken_MustBeProvided" xml:space="preserve">
<value>The required antiforgery request token was not provided in either form field "{0}" or header value "{1}".</value>
</data>
<data name="Antiforgery_RequestToken_MustBeProvided_Generic" xml:space="preserve">
<value>The required antiforgery request token must be provided.</value>
</data>
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
<value>Value cannot be null or empty.</value>

Просмотреть файл

@ -45,21 +45,21 @@ namespace Microsoft.AspNet.Antiforgery
}
[Fact]
public void IsSessionTokenProperty()
public void IsCookieTokenProperty()
{
// Arrange
var token = new AntiforgeryToken();
// Act & assert - 1
Assert.False(token.IsSessionToken);
Assert.False(token.IsCookieToken);
// Act & assert - 2
token.IsSessionToken = true;
Assert.True(token.IsSessionToken);
token.IsCookieToken = true;
Assert.True(token.IsCookieToken);
// Act & assert - 3
token.IsSessionToken = false;
Assert.False(token.IsSessionToken);
token.IsCookieToken = false;
Assert.False(token.IsCookieToken);
}
[Fact]

Просмотреть файл

@ -289,7 +289,7 @@ namespace Microsoft.AspNet.Antiforgery
// Assert
Assert.Equal("serialized-new-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
Assert.Equal("serialized-form-token", tokenset.RequestToken);
}
[Fact]
@ -316,7 +316,7 @@ namespace Microsoft.AspNet.Antiforgery
// Assert
Assert.Equal("serialized-new-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
Assert.Equal("serialized-form-token", tokenset.RequestToken);
}
[Fact]
@ -334,7 +334,7 @@ namespace Microsoft.AspNet.Antiforgery
// Assert
Assert.Equal("serialized-old-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
Assert.Equal("serialized-form-token", tokenset.RequestToken);
}
[Fact]
@ -356,7 +356,7 @@ namespace Microsoft.AspNet.Antiforgery
t => t.SaveCookieToken(It.IsAny<HttpContext>(), It.IsAny<AntiforgeryToken>()), Times.Never);
Assert.Equal("serialized-old-cookie-token", tokenSet.CookieToken);
Assert.Equal("serialized-form-token", tokenSet.FormToken);
Assert.Equal("serialized-form-token", tokenSet.RequestToken);
}
[Fact]
@ -377,7 +377,7 @@ namespace Microsoft.AspNet.Antiforgery
t => t.SaveCookieToken(It.IsAny<HttpContext>(), It.IsAny<AntiforgeryToken>()), Times.Once);
Assert.Equal("serialized-new-cookie-token", tokenSet.CookieToken);
Assert.Equal("serialized-form-token", tokenSet.FormToken);
Assert.Equal("serialized-form-token", tokenSet.RequestToken);
}
[Fact]
@ -391,13 +391,13 @@ namespace Microsoft.AspNet.Antiforgery
.Returns(context.TestTokenSet.OldCookieToken);
context.TokenSerializer
.Setup(o => o.Deserialize("form-token"))
.Returns(context.TestTokenSet.FormToken);
.Returns(context.TestTokenSet.RequestToken);
context.TokenGenerator
.Setup(o => o.ValidateTokens(
context.HttpContext,
context.TestTokenSet.OldCookieToken,
context.TestTokenSet.FormToken))
context.TestTokenSet.RequestToken))
.Throws(new InvalidOperationException("my-message"));
context.TokenStore = null;
var antiforgery = GetAntiforgery(context);
@ -421,13 +421,13 @@ namespace Microsoft.AspNet.Antiforgery
.Returns(context.TestTokenSet.OldCookieToken);
context.TokenSerializer
.Setup(o => o.Deserialize("form-token"))
.Returns(context.TestTokenSet.FormToken);
.Returns(context.TestTokenSet.RequestToken);
context.TokenGenerator
.Setup(o => o.ValidateTokens(
context.HttpContext,
context.TestTokenSet.OldCookieToken,
context.TestTokenSet.FormToken))
context.TestTokenSet.RequestToken))
.Verifiable();
context.TokenStore = null;
var antiforgery = GetAntiforgery(context);
@ -455,7 +455,7 @@ namespace Microsoft.AspNet.Antiforgery
// Assert
var trimmed = exception.Message.Substring(0, exception.Message.IndexOf(Environment.NewLine));
Assert.Equal("The cookie token must be provided.", trimmed);
Assert.Equal("The required antiforgery cookie token must be provided.", trimmed);
}
[Fact]
@ -468,7 +468,7 @@ namespace Microsoft.AspNet.Antiforgery
.Setup(o => o.ValidateTokens(
context.HttpContext,
context.TestTokenSet.OldCookieToken,
context.TestTokenSet.FormToken))
context.TestTokenSet.RequestToken))
.Throws(new InvalidOperationException("my-message"));
var antiforgery = GetAntiforgery(context);
@ -489,7 +489,7 @@ namespace Microsoft.AspNet.Antiforgery
.Setup(o => o.ValidateTokens(
context.HttpContext,
context.TestTokenSet.OldCookieToken,
context.TestTokenSet.FormToken))
context.TestTokenSet.RequestToken))
.Verifiable();
var antiforgery = GetAntiforgery(context);
@ -567,7 +567,7 @@ namespace Microsoft.AspNet.Antiforgery
bool saveNewCookie = true)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var formToken = testTokenSet.FormToken;
var formToken = testTokenSet.RequestToken;
var mockTokenStore = new Mock<IAntiforgeryTokenStore>(MockBehavior.Strict);
mockTokenStore.Setup(o => o.GetCookieToken(context))
.Returns(oldCookieToken);
@ -591,7 +591,7 @@ namespace Microsoft.AspNet.Antiforgery
{
var oldCookieToken = testTokenSet.OldCookieToken;
var newCookieToken = testTokenSet.NewCookieToken;
var formToken = testTokenSet.FormToken;
var formToken = testTokenSet.RequestToken;
var mockSerializer = new Mock<IAntiforgeryTokenSerializer>(MockBehavior.Strict);
mockSerializer.Setup(o => o.Serialize(formToken))
.Returns(testTokenSet.FormTokenString);
@ -613,7 +613,7 @@ namespace Microsoft.AspNet.Antiforgery
{
// Arrange
var httpContext = GetHttpContext();
var testTokenSet = GetTokenSet(isOldCookieTokenSessionToken: true, isNewCookieSessionToken: true);
var testTokenSet = GetTokenSet();
var mockSerializer = GetTokenSerializer(testTokenSet);
@ -621,10 +621,10 @@ namespace Microsoft.AspNet.Antiforgery
var mockGenerator = new Mock<IAntiforgeryTokenGenerator>(MockBehavior.Strict);
mockGenerator
.Setup(o => o.GenerateFormToken(
.Setup(o => o.GenerateRequestToken(
httpContext,
useOldCookie ? testTokenSet.OldCookieToken : testTokenSet.NewCookieToken))
.Returns(testTokenSet.FormToken);
.Returns(testTokenSet.RequestToken);
mockGenerator
.Setup(o => o.GenerateCookieToken())
@ -649,22 +649,22 @@ namespace Microsoft.AspNet.Antiforgery
};
}
private TestTokenSet GetTokenSet(bool isOldCookieTokenSessionToken = true, bool isNewCookieSessionToken = true)
private TestTokenSet GetTokenSet()
{
return new TestTokenSet()
{
FormToken = new AntiforgeryToken() { IsSessionToken = false },
RequestToken = new AntiforgeryToken() { IsCookieToken = false },
FormTokenString = "serialized-form-token",
OldCookieToken = new AntiforgeryToken() { IsSessionToken = isOldCookieTokenSessionToken },
OldCookieToken = new AntiforgeryToken() { IsCookieToken = true },
OldCookieTokenString = "serialized-old-cookie-token",
NewCookieToken = new AntiforgeryToken() { IsSessionToken = isNewCookieSessionToken },
NewCookieToken = new AntiforgeryToken() { IsCookieToken = true },
NewCookieTokenString = "serialized-new-cookie-token",
};
}
private class TestTokenSet
{
public AntiforgeryToken FormToken { get; set; }
public AntiforgeryToken RequestToken { get; set; }
public string FormTokenString { get; set; }

Просмотреть файл

@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Antiforgery
public void GenerateFormToken_AnonymousUser()
{
// Arrange
var cookieToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
Assert.False(httpContext.User.Identity.IsAuthenticated);
@ -41,12 +41,12 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, cookieToken);
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.False(fieldToken.IsCookieToken);
Assert.Empty(fieldToken.Username);
Assert.Null(fieldToken.ClaimUid);
Assert.Empty(fieldToken.AdditionalData);
@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Antiforgery
// Arrange
var cookieToken = new AntiforgeryToken()
{
IsSessionToken = true
IsCookieToken = true
};
var httpContext = new DefaultHttpContext();
@ -73,7 +73,7 @@ namespace Microsoft.AspNet.Antiforgery
// Act & assert
var exception = Assert.Throws<InvalidOperationException>(
() => tokenProvider.GenerateFormToken(httpContext, cookieToken));
() => tokenProvider.GenerateRequestToken(httpContext, cookieToken));
Assert.Equal(
"The provided identity of type " +
$"'{typeof(MyAuthenticatedIdentityWithoutUsername).FullName}' " +
@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Antiforgery
public void GenerateFormToken_AuthenticatedWithoutUsername_WithAdditionalData()
{
// Arrange
var cookieToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());
@ -106,12 +106,12 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, cookieToken);
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.False(fieldToken.IsCookieToken);
Assert.Empty(fieldToken.Username);
Assert.Null(fieldToken.ClaimUid);
Assert.Equal("additional-data", fieldToken.AdditionalData);
@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Antiforgery
public void GenerateFormToken_ClaimsBasedIdentity()
{
// Arrange
var cookieToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var identity = GetAuthenticatedIdentity("some-identity");
var httpContext = new DefaultHttpContext();
@ -144,12 +144,12 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, cookieToken);
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.False(fieldToken.IsCookieToken);
Assert.Equal("", fieldToken.Username);
Assert.Equal(expectedClaimUid, fieldToken.ClaimUid);
Assert.Equal("", fieldToken.AdditionalData);
@ -159,7 +159,7 @@ namespace Microsoft.AspNet.Antiforgery
public void GenerateFormToken_RegularUserWithUsername()
{
// Arrange
var cookieToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var httpContext = new DefaultHttpContext();
var mockIdentity = new Mock<ClaimsIdentity>();
@ -177,12 +177,12 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, cookieToken);
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.False(fieldToken.IsCookieToken);
Assert.Equal("my-username", fieldToken.Username);
Assert.Null(fieldToken.ClaimUid);
Assert.Empty(fieldToken.AdditionalData);
@ -194,7 +194,7 @@ namespace Microsoft.AspNet.Antiforgery
// Arrange
var cookieToken = new AntiforgeryToken()
{
IsSessionToken = false
IsCookieToken = false
};
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
@ -230,7 +230,7 @@ namespace Microsoft.AspNet.Antiforgery
// Arrange
var cookieToken = new AntiforgeryToken()
{
IsSessionToken = true
IsCookieToken = true
};
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
@ -246,13 +246,13 @@ namespace Microsoft.AspNet.Antiforgery
[Fact]
public void ValidateTokens_SessionTokenMissing()
public void ValidateTokens_CookieTokenMissing()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
var fieldtoken = new AntiforgeryToken() { IsSessionToken = false };
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
claimUidExtractor: null,
@ -263,7 +263,7 @@ namespace Microsoft.AspNet.Antiforgery
() => tokenProvider.ValidateTokens(httpContext, null, fieldtoken));
var trimmed = ex.Message.Substring(0, ex.Message.IndexOf(Environment.NewLine));
Assert.Equal(@"The cookie token must be provided.", trimmed);
Assert.Equal(@"The required antiforgery cookie token must be provided.", trimmed);
}
[Fact]
@ -273,7 +273,7 @@ namespace Microsoft.AspNet.Antiforgery
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
claimUidExtractor: null,
@ -281,21 +281,21 @@ namespace Microsoft.AspNet.Antiforgery
// Act & assert
var ex = Assert.Throws<ArgumentNullException>(
() => tokenProvider.ValidateTokens(httpContext, sessionToken, null));
() => tokenProvider.ValidateTokens(httpContext, cookieToken, null));
var trimmed = ex.Message.Substring(0, ex.Message.IndexOf(Environment.NewLine));
Assert.Equal("The form token must be provided.", trimmed);
Assert.Equal("The required antiforgery request token must be provided.", trimmed);
}
[Fact]
public void ValidateTokens_FieldAndSessionTokensSwapped()
public void ValidateTokens_FieldAndCookieTokensSwapped()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiforgeryToken() { IsSessionToken = false };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
claimUidExtractor: null,
@ -307,27 +307,27 @@ namespace Microsoft.AspNet.Antiforgery
() => tokenProvider.ValidateTokens(httpContext, fieldtoken, fieldtoken));
Assert.Equal(
"Validation of the provided antiforgery token failed. " +
@"The cookie token and the form token were swapped.",
@"The cookie token and the request token were swapped.",
ex1.Message);
var ex2 =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, sessionToken, sessionToken));
() => tokenProvider.ValidateTokens(httpContext, cookieToken, cookieToken));
Assert.Equal(
"Validation of the provided antiforgery token failed. " +
@"The cookie token and the form token were swapped.",
@"The cookie token and the request token were swapped.",
ex2.Message);
}
[Fact]
public void ValidateTokens_FieldAndSessionTokensHaveDifferentSecurityKeys()
public void ValidateTokens_FieldAndCookieTokensHaveDifferentSecurityKeys()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiforgeryToken() { IsSessionToken = false };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
claimUidExtractor: null,
@ -335,9 +335,9 @@ namespace Microsoft.AspNet.Antiforgery
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken));
() => tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken));
Assert.Equal(
@"The antiforgery cookie token and form field token do not match.",
@"The antiforgery cookie token and request token do not match.",
exception.Message);
}
@ -352,12 +352,12 @@ namespace Microsoft.AspNet.Antiforgery
var identity = GetAuthenticatedIdentity(identityUsername);
httpContext.User = new ClaimsPrincipal(identity);
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
SecurityToken = cookieToken.SecurityToken,
Username = embeddedUsername,
IsSessionToken = false
IsCookieToken = false
};
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
@ -370,7 +370,7 @@ namespace Microsoft.AspNet.Antiforgery
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken));
() => tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken));
Assert.Equal(
@"The provided antiforgery token was meant for user """ + embeddedUsername +
@""", but the current user is """ + identityUsername + @""".",
@ -385,11 +385,11 @@ namespace Microsoft.AspNet.Antiforgery
var identity = GetAuthenticatedIdentity("the-user");
httpContext.User = new ClaimsPrincipal(identity);
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
IsSessionToken = false,
SecurityToken = cookieToken.SecurityToken,
IsCookieToken = false,
ClaimUid = new BinaryBlob(256)
};
@ -404,7 +404,7 @@ namespace Microsoft.AspNet.Antiforgery
// Act & assert
var exception = Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken));
() => tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken));
Assert.Equal(
@"The provided antiforgery token was meant for a different claims-based user than the current user.",
exception.Message);
@ -418,12 +418,12 @@ namespace Microsoft.AspNet.Antiforgery
var identity = new ClaimsIdentity();
httpContext.User = new ClaimsPrincipal(identity);
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
SecurityToken = cookieToken.SecurityToken,
Username = String.Empty,
IsSessionToken = false,
IsCookieToken = false,
AdditionalData = "some-additional-data"
};
@ -437,7 +437,7 @@ namespace Microsoft.AspNet.Antiforgery
// Act & assert
var exception = Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken));
() => tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken));
Assert.Equal(@"The provided antiforgery token failed a custom data check.", exception.Message);
}
@ -449,12 +449,12 @@ namespace Microsoft.AspNet.Antiforgery
var identity = new ClaimsIdentity();
httpContext.User = new ClaimsPrincipal(identity);
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
SecurityToken = cookieToken.SecurityToken,
Username = String.Empty,
IsSessionToken = false,
IsCookieToken = false,
AdditionalData = "some-additional-data"
};
@ -467,7 +467,7 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken);
tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
@ -481,12 +481,12 @@ namespace Microsoft.AspNet.Antiforgery
var identity = GetAuthenticatedIdentity("the-user");
httpContext.User = new ClaimsPrincipal(identity);
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
SecurityToken = cookieToken.SecurityToken,
Username = "THE-USER",
IsSessionToken = false,
IsCookieToken = false,
AdditionalData = "some-additional-data"
};
@ -499,7 +499,7 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken);
tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
@ -513,11 +513,11 @@ namespace Microsoft.AspNet.Antiforgery
var identity = GetAuthenticatedIdentity("the-user");
httpContext.User = new ClaimsPrincipal(identity);
var sessionToken = new AntiforgeryToken() { IsSessionToken = true };
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
var fieldtoken = new AntiforgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
IsSessionToken = false,
SecurityToken = cookieToken.SecurityToken,
IsCookieToken = false,
ClaimUid = new BinaryBlob(256)
};
@ -530,7 +530,7 @@ namespace Microsoft.AspNet.Antiforgery
additionalDataProvider: null);
// Act
tokenProvider.ValidateTokens(httpContext, sessionToken, fieldtoken);
tokenProvider.ValidateTokens(httpContext, cookieToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!

Просмотреть файл

@ -26,18 +26,18 @@ namespace Microsoft.AspNet.Antiforgery
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "01" // IsSessionToken
+ "01" // IsCookieToken
+ "00" // (WRONG!) Too much data in stream
)]
[InlineData(
"02" // (WRONG! - must be 0x01) Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "01" // IsSessionToken
+ "01" // IsCookieToken
)]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "00" // IsSessionToken
+ "00" // IsCookieToken
+ "00" // IsClaimsBased
+ "05" // Username length header
+ "0000" // (WRONG!) Too little data in stream
@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Antiforgery
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "00" // IsSessionToken
//+ "00" // IsCookieToken
//+ "01" // IsClaimsBased
//+ "6F1648E97249AA58754036A67E248CF044F07ECFB0ED387556CE029A4F9A40E0" // ClaimUid
//+ "05" // AdditionalData length header
@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Antiforgery
var token = new AntiforgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = false,
IsCookieToken = false,
ClaimUid = _claimUid,
AdditionalData = "€47"
};
@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Antiforgery
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "00" // IsSessionToken
//+ "00" // IsCookieToken
//+ "00" // IsClaimsBased
//+ "08" // Username length header
//+ "4AC3A972C3B46D65" // Username ("Jérôme") as UTF8
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Antiforgery
var token = new AntiforgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = false,
IsCookieToken = false,
Username = "Jérôme",
AdditionalData = "€47"
};
@ -114,18 +114,18 @@ namespace Microsoft.AspNet.Antiforgery
}
[Fact]
public void Serialize_SessionToken_TokenRoundTripSuccessful()
public void Serialize_CookieToken_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new DefaultAntiforgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "01"; // IsSessionToken
//+ "01"; // IsCookieToken
var token = new AntiforgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = true
IsCookieToken = true
};
// Act
@ -178,7 +178,7 @@ namespace Microsoft.AspNet.Antiforgery
Assert.NotNull(actual);
Assert.Equal(expected.AdditionalData, actual.AdditionalData);
Assert.Equal(expected.ClaimUid, actual.ClaimUid);
Assert.Equal(expected.IsSessionToken, actual.IsSessionToken);
Assert.Equal(expected.IsCookieToken, actual.IsCookieToken);
Assert.Equal(expected.SecurityToken, actual.SecurityToken);
Assert.Equal(expected.Username, actual.Username);
}

Просмотреть файл

@ -187,7 +187,7 @@ namespace Microsoft.AspNet.Antiforgery
}
[Fact]
public async Task GetRequestTokens_NonFormContentType_Throws()
public async Task GetRequestTokens_NonFormContentType_HeaderDisabled_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -204,6 +204,7 @@ namespace Microsoft.AspNet.Antiforgery
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = null,
};
var tokenStore = new DefaultAntiforgeryTokenStore(
@ -219,7 +220,110 @@ namespace Microsoft.AspNet.Antiforgery
}
[Fact]
public async Task GetRequestTokens_FormFieldIsEmpty_Throws()
public async Task GetRequestTokens_FormContentType_FallbackHeaderToken()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = "application/json";
// Will not be accessed
httpContext.Request.ContentType = "application/x-www-form-urlencoded";
httpContext.Request.Form = new FormCollection(new Dictionary<string, StringValues>());
httpContext.Request.Cookies = new RequestCookieCollection(new Dictionary<string, string>()
{
{ "cookie-name", "cookie-value" },
});
httpContext.Request.Headers.Add("header-name", "header-value");
var options = new AntiforgeryOptions()
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = "header-name",
};
var tokenStore = new DefaultAntiforgeryTokenStore(
optionsAccessor: new TestOptionsManager(options),
tokenSerializer: new DefaultAntiforgeryTokenSerializer(new EphemeralDataProtectionProvider()));
// Act
var tokens = await tokenStore.GetRequestTokensAsync(httpContext);
// Assert
Assert.Equal("cookie-value", tokens.CookieToken);
Assert.Equal("header-value", tokens.RequestToken);
}
[Fact]
public async Task GetRequestTokens_NonFormContentType_UsesHeaderToken()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = "application/json";
// Will not be accessed
httpContext.Request.Form = null;
httpContext.Request.Cookies = new RequestCookieCollection(new Dictionary<string, string>()
{
{ "cookie-name", "cookie-value" },
});
httpContext.Request.Headers.Add("header-name", "header-value");
var options = new AntiforgeryOptions()
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = "header-name",
};
var tokenStore = new DefaultAntiforgeryTokenStore(
optionsAccessor: new TestOptionsManager(options),
tokenSerializer: new DefaultAntiforgeryTokenSerializer(new EphemeralDataProtectionProvider()));
// Act
var tokens = await tokenStore.GetRequestTokensAsync(httpContext);
// Assert
Assert.Equal("cookie-value", tokens.CookieToken);
Assert.Equal("header-value", tokens.RequestToken);
}
[Fact]
public async Task GetRequestTokens_NonFormContentType_UsesHeaderToken_ThrowsOnMissingValue()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = "application/json";
// Will not be accessed
httpContext.Request.Form = null;
httpContext.Request.Cookies = new RequestCookieCollection(new Dictionary<string, string>()
{
{ "cookie-name", "cookie-value" },
});
var options = new AntiforgeryOptions()
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = "header-name",
};
var tokenStore = new DefaultAntiforgeryTokenStore(
optionsAccessor: new TestOptionsManager(options),
tokenSerializer: new DefaultAntiforgeryTokenSerializer(new EphemeralDataProtectionProvider()));
// Act
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await tokenStore.GetRequestTokensAsync(httpContext));
// Assert
Assert.Equal("The required antiforgery header value \"header-name\" is not present.", exception.Message);
}
[Fact]
public async Task GetRequestTokens_BothFieldsEmpty_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -234,6 +338,7 @@ namespace Microsoft.AspNet.Antiforgery
{
CookieName = "cookie-name",
FormFieldName = "form-field-name",
HeaderName = "header-name",
};
var tokenStore = new DefaultAntiforgeryTokenStore(
@ -245,7 +350,10 @@ namespace Microsoft.AspNet.Antiforgery
async () => await tokenStore.GetRequestTokensAsync(httpContext));
// Assert
Assert.Equal("The required antiforgery form field \"form-field-name\" is not present.", exception.Message);
Assert.Equal(
"The required antiforgery request token was not provided in either form field \"form-field-name\" " +
"or header value \"header-name\".",
exception.Message);
}
[Fact]
@ -262,11 +370,13 @@ namespace Microsoft.AspNet.Antiforgery
{
{ "cookie-name", "cookie-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(
@ -278,7 +388,7 @@ namespace Microsoft.AspNet.Antiforgery
// Assert
Assert.Equal("cookie-value", tokens.CookieToken);
Assert.Equal("form-value", tokens.FormToken);
Assert.Equal("form-value", tokens.RequestToken);
}
[Theory]