Add Header support

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
parent b69aef3c51
commit 3280ff6ac5
18 changed files with 370 additions and 191 deletions

View File

@ -40,7 +40,7 @@ namespace AntiforgerySample
</html>"; </html>";
var tokenSet = _antiforgery.GetAndStoreTokens(context); 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") else if (context.Request.Method == "POST")
{ {

View File

@ -11,16 +11,17 @@ namespace Microsoft.AspNet.Antiforgery
public class AntiforgeryOptions public class AntiforgeryOptions
{ {
private const string AntiforgeryTokenFieldName = "__RequestVerificationToken"; private const string AntiforgeryTokenFieldName = "__RequestVerificationToken";
private const string AntiforgertyTokenHeaderName = "RequestVerificationToken";
private string _cookieName; private string _cookieName;
private string _headerName = AntiforgertyTokenHeaderName;
private string _formFieldName = AntiforgeryTokenFieldName; private string _formFieldName = AntiforgeryTokenFieldName;
/// <summary> /// <summary>
/// Specifies the name of the cookie that is used by the antiforgery /// Specifies the name of the cookie that is used by the antiforgery system.
/// system.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If an explicit name is not provided, the system will automatically /// If an explicit name is not provided, the system will automatically generate a name.
/// generate a name.
/// </remarks> /// </remarks>
public string CookieName 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> /// <summary>
/// Specifies whether SSL is required for the antiforgery system /// Specifies whether SSL is required for the antiforgery system
/// to operate. If this setting is 'true' and a non-SSL request /// to operate. If this setting is 'true' and a non-SSL request

View File

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

View File

@ -6,23 +6,23 @@ using System;
namespace Microsoft.AspNet.Antiforgery namespace Microsoft.AspNet.Antiforgery
{ {
/// <summary> /// <summary>
/// The antiforgery token pair (cookie and form token) for a request. /// The antiforgery token pair (cookie and request token) for a request.
/// </summary> /// </summary>
public class AntiforgeryTokenSet public class AntiforgeryTokenSet
{ {
/// <summary> /// <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> /// </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> /// <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 // Cookie Token is allowed to be null in the case when the old cookie is valid
// and there is no new cookieToken generated. // and there is no new cookieToken generated.
@ -30,9 +30,9 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <summary>
/// The token that is supplied in the request form body. /// The token that is supplied in the request.
/// </summary> /// </summary>
public string FormToken { get; private set; } public string RequestToken { get; private set; }
/// The cookie token is allowed to be null. /// The cookie token is allowed to be null.
/// This would be the case when the old cookie token is still valid. /// This would be the case when the old cookie token is still valid.

View File

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

View File

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

View File

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

View File

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

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Antiforgery
/// </summary> /// </summary>
/// <param name="context">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="context">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="antiforgeryTokenSet"> /// <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> /// </param>
void ValidateTokens(HttpContext context, AntiforgeryTokenSet antiforgeryTokenSet); void ValidateTokens(HttpContext context, AntiforgeryTokenSet antiforgeryTokenSet);

View File

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

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Antiforgery
AntiforgeryToken GetCookieToken(HttpContext httpContext); AntiforgeryToken GetCookieToken(HttpContext httpContext);
/// <summary> /// <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. /// not present.
/// </summary> /// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> for the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> for the current request.</param>

View File

@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <summary>
/// The antiforgery cookie token and form field token do not match. /// The antiforgery cookie token and request token do not match.
/// </summary> /// </summary>
internal static string AntiforgeryToken_SecurityTokenMismatch internal static string AntiforgeryToken_SecurityTokenMismatch
{ {
@ -83,7 +83,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <summary>
/// The antiforgery cookie token and form field token do not match. /// The antiforgery cookie token and request token do not match.
/// </summary> /// </summary>
internal static string FormatAntiforgeryToken_SecurityTokenMismatch() internal static string FormatAntiforgeryToken_SecurityTokenMismatch()
{ {
@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <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> /// </summary>
internal static string AntiforgeryToken_TokensSwapped internal static string AntiforgeryToken_TokensSwapped
{ {
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <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> /// </summary>
internal static string FormatAntiforgeryToken_TokensSwapped() internal static string FormatAntiforgeryToken_TokensSwapped()
{ {
@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <summary>
/// The cookie token must be provided. /// The required antiforgery cookie token must be provided.
/// </summary> /// </summary>
internal static string Antiforgery_CookieToken_MustBeProvided_Generic internal static string Antiforgery_CookieToken_MustBeProvided_Generic
{ {
@ -163,7 +163,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <summary>
/// The cookie token must be provided. /// The required antiforgery cookie token must be provided.
/// </summary> /// </summary>
internal static string FormatAntiforgery_CookieToken_MustBeProvided_Generic() internal static string FormatAntiforgery_CookieToken_MustBeProvided_Generic()
{ {
@ -187,19 +187,51 @@ namespace Microsoft.AspNet.Antiforgery
} }
/// <summary> /// <summary>
/// The form token must be provided. /// The required antiforgery header value "{0}" is not present.
/// </summary> /// </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> /// <summary>
/// The form token must be provided. /// The required antiforgery header value "{0}" is not present.
/// </summary> /// </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> /// <summary>

View File

@ -131,10 +131,10 @@
<value>The antiforgery token could not be decrypted.</value> <value>The antiforgery token could not be decrypted.</value>
</data> </data>
<data name="AntiforgeryToken_SecurityTokenMismatch" xml:space="preserve"> <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>
<data name="AntiforgeryToken_TokensSwapped" xml:space="preserve"> <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>
<data name="AntiforgeryToken_UsernameMismatch" xml:space="preserve"> <data name="AntiforgeryToken_UsernameMismatch" xml:space="preserve">
<value>The provided antiforgery token was meant for user "{0}", but the current user is "{1}".</value> <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> <value>The required antiforgery cookie "{0}" is not present.</value>
</data> </data>
<data name="Antiforgery_CookieToken_MustBeProvided_Generic" xml:space="preserve"> <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>
<data name="Antiforgery_FormToken_MustBeProvided" xml:space="preserve"> <data name="Antiforgery_FormToken_MustBeProvided" xml:space="preserve">
<value>The required antiforgery form field "{0}" is not present.</value> <value>The required antiforgery form field "{0}" is not present.</value>
</data> </data>
<data name="Antiforgery_FormToken_MustBeProvided_Generic" xml:space="preserve"> <data name="Antiforgery_HeaderToken_MustBeProvided" xml:space="preserve">
<value>The form token must be provided.</value> <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>
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve"> <data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
<value>Value cannot be null or empty.</value> <value>Value cannot be null or empty.</value>

View File

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

View File

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

View File

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

View File

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

View File

@ -187,7 +187,7 @@ namespace Microsoft.AspNet.Antiforgery
} }
[Fact] [Fact]
public async Task GetRequestTokens_NonFormContentType_Throws() public async Task GetRequestTokens_NonFormContentType_HeaderDisabled_Throws()
{ {
// Arrange // Arrange
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
@ -204,6 +204,7 @@ namespace Microsoft.AspNet.Antiforgery
{ {
CookieName = "cookie-name", CookieName = "cookie-name",
FormFieldName = "form-field-name", FormFieldName = "form-field-name",
HeaderName = null,
}; };
var tokenStore = new DefaultAntiforgeryTokenStore( var tokenStore = new DefaultAntiforgeryTokenStore(
@ -219,7 +220,110 @@ namespace Microsoft.AspNet.Antiforgery
} }
[Fact] [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 // Arrange
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
@ -234,6 +338,7 @@ namespace Microsoft.AspNet.Antiforgery
{ {
CookieName = "cookie-name", CookieName = "cookie-name",
FormFieldName = "form-field-name", FormFieldName = "form-field-name",
HeaderName = "header-name",
}; };
var tokenStore = new DefaultAntiforgeryTokenStore( var tokenStore = new DefaultAntiforgeryTokenStore(
@ -245,7 +350,10 @@ namespace Microsoft.AspNet.Antiforgery
async () => await tokenStore.GetRequestTokensAsync(httpContext)); async () => await tokenStore.GetRequestTokensAsync(httpContext));
// Assert // 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] [Fact]
@ -262,11 +370,13 @@ namespace Microsoft.AspNet.Antiforgery
{ {
{ "cookie-name", "cookie-value" }, { "cookie-name", "cookie-value" },
}); });
httpContext.Request.Headers.Add("header-name", "header-value"); // form value has priority.
var options = new AntiforgeryOptions() var options = new AntiforgeryOptions()
{ {
CookieName = "cookie-name", CookieName = "cookie-name",
FormFieldName = "form-field-name", FormFieldName = "form-field-name",
HeaderName = "header-name",
}; };
var tokenStore = new DefaultAntiforgeryTokenStore( var tokenStore = new DefaultAntiforgeryTokenStore(
@ -278,7 +388,7 @@ namespace Microsoft.AspNet.Antiforgery
// Assert // Assert
Assert.Equal("cookie-value", tokens.CookieToken); Assert.Equal("cookie-value", tokens.CookieToken);
Assert.Equal("form-value", tokens.FormToken); Assert.Equal("form-value", tokens.RequestToken);
} }
[Theory] [Theory]