[Design] Add antiforgery middleware
This new middleware participates in authentication and acts as a filter when the request doesn't include a valid CSRF token for a POST. Any authentication middleware that you want to validate an antiforgery token should go ahead of this middleware in the pipeline (Cookies, IISIntegration). This also takes care of automatic auth (Windows) done by weblistener. Any authentication middleware that you want to ignore antiforgery should go after this middleware in the pipeline. To facilitate this, there are a few changes in the antiforgery API surface. Namely we can now pass in a principal to validate tokens. You can't pass in a principal to generate tokens - we expect you to be logged in at that poing. Also, ValidateRequestAsync(...) now checks the HTTP verb and won't validate GETs and such.
This commit is contained in:
parent
9783a7c42b
commit
4629148519
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for configuring the antiforgery middleware.
|
||||
/// </summary>
|
||||
public static class AntiforgeryBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the antiforgery middleware.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
|
||||
public static IApplicationBuilder UseAntiforgery(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<AntiforgeryMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Antiforgery.Internal;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery
|
||||
{
|
||||
/// <summary>
|
||||
/// A middleware implementation of antiforgery validation.
|
||||
/// </summary>
|
||||
public class AntiforgeryMiddleware
|
||||
{
|
||||
private readonly IAntiforgery _antiforgery;
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="AntiforgeryMiddleware"/>.
|
||||
/// </summary>
|
||||
/// <param name="next">The <see cref="RequestDelegate"/> for the next middleware.</param>
|
||||
/// <param name="antiforgery">The <see cref="IAntiforgery"/>.</param>
|
||||
public AntiforgeryMiddleware(RequestDelegate next, IAntiforgery antiforgery)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(next));
|
||||
}
|
||||
|
||||
if (antiforgery == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(antiforgery));
|
||||
}
|
||||
|
||||
_next = next;
|
||||
_antiforgery = antiforgery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the middleware for the given <paramref name="httpContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||
/// <returns>A <see cref="Task"/> which will be completed when execution of the middleware completes.</returns>
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
var handler = new AntiforgeryAuthenticationHandler(_antiforgery);
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
try
|
||||
{
|
||||
await _next(httpContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handler.Teardown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
|
@ -46,6 +47,18 @@ namespace Microsoft.AspNetCore.Antiforgery
|
|||
/// </returns>
|
||||
Task<bool> IsRequestValidAsync(HttpContext httpContext);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously returns a value indicating whether the request passes antiforgery validation. If the
|
||||
/// request uses a safe HTTP method (GET, HEAD, OPTIONS, TRACE), the antiforgery token is not validated.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||
/// <param name="principal">The claims-based principal to validate.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="Task{Boolean}"/> that, when completed, returns <c>true</c> if the is requst uses a safe HTTP
|
||||
/// method or contains a value antiforgery token, otherwise returns <c>false</c>.
|
||||
/// </returns>
|
||||
Task<bool> IsRequestValidAsync(HttpContext httpContext, ClaimsPrincipal principal);
|
||||
|
||||
/// <summary>
|
||||
/// Validates an antiforgery token that was supplied as part of the request.
|
||||
/// </summary>
|
||||
|
|
@ -55,6 +68,16 @@ namespace Microsoft.AspNetCore.Antiforgery
|
|||
/// </exception>
|
||||
Task ValidateRequestAsync(HttpContext httpContext);
|
||||
|
||||
/// <summary>
|
||||
/// Validates an antiforgery token that was supplied as part of the request.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||
/// <param name="principal">The claims-based principal to validate.</param>
|
||||
/// <exception cref="AntiforgeryValidationException">
|
||||
/// Thrown when the request does not include a valid antiforgery token.
|
||||
/// </exception>
|
||||
Task ValidateRequestAsync(HttpContext httpContext, ClaimsPrincipal principal);
|
||||
|
||||
/// <summary>
|
||||
/// Generates and stores an antiforgery cookie token if one is not available or not valid.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||
{
|
||||
public class AntiforgeryAuthenticationHandler : IAuthenticationHandler
|
||||
{
|
||||
private readonly IAntiforgery _antiforgery;
|
||||
private HttpContext _httpContext;
|
||||
private IAuthenticationHandler _priorHandler;
|
||||
|
||||
public AntiforgeryAuthenticationHandler(IAntiforgery antiforgery)
|
||||
{
|
||||
if (antiforgery == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(antiforgery));
|
||||
}
|
||||
|
||||
_antiforgery = antiforgery;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
_httpContext = httpContext;
|
||||
|
||||
var authentication = GetAuthenticationFeature(_httpContext);
|
||||
|
||||
_priorHandler = authentication.Handler;
|
||||
authentication.Handler = this;
|
||||
|
||||
if (authentication.User != null)
|
||||
{
|
||||
if (!await _antiforgery.IsRequestValidAsync(_httpContext))
|
||||
{
|
||||
// Wipe out any existing principal if we can't validate this request.
|
||||
authentication.User = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Teardown()
|
||||
{
|
||||
var authentication = GetAuthenticationFeature(_httpContext);
|
||||
authentication.Handler = _priorHandler;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task AuthenticateAsync(AuthenticateContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (_priorHandler != null)
|
||||
{
|
||||
await _priorHandler.AuthenticateAsync(context);
|
||||
|
||||
var authentication = GetAuthenticationFeature(_httpContext);
|
||||
if (context.Principal != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _antiforgery.ValidateRequestAsync(_httpContext, context.Principal);
|
||||
}
|
||||
catch (AntiforgeryValidationException ex)
|
||||
{
|
||||
context.Failed(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task ChallengeAsync(ChallengeContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (_priorHandler != null)
|
||||
{
|
||||
return _priorHandler.ChallengeAsync(context);
|
||||
}
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GetDescriptions(DescribeSchemesContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (_priorHandler != null)
|
||||
{
|
||||
_priorHandler.GetDescriptions(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SignInAsync(SignInContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (_priorHandler != null)
|
||||
{
|
||||
return _priorHandler.SignInAsync(context);
|
||||
}
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SignOutAsync(SignOutContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (_priorHandler != null)
|
||||
{
|
||||
return _priorHandler.SignOutAsync(context);
|
||||
}
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
private static IHttpAuthenticationFeature GetAuthenticationFeature(HttpContext httpContext)
|
||||
{
|
||||
var authentication = httpContext.Features.Get<IHttpAuthenticationFeature>();
|
||||
if (authentication == null)
|
||||
{
|
||||
authentication = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set(authentication);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -85,7 +86,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> IsRequestValidAsync(HttpContext httpContext)
|
||||
public Task<bool> IsRequestValidAsync(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
|
|
@ -94,13 +95,26 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
CheckSSLConfig(httpContext);
|
||||
|
||||
var method = httpContext.Request.Method;
|
||||
if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(method, "HEAD", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(method, "OPTIONS", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(method, "TRACE", StringComparison.OrdinalIgnoreCase))
|
||||
return IsRequestValidAsync(httpContext, httpContext.User);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> IsRequestValidAsync(HttpContext httpContext, ClaimsPrincipal principal)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
if (principal == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(principal));
|
||||
}
|
||||
|
||||
CheckSSLConfig(httpContext);
|
||||
|
||||
if (!IsValidationRequired(httpContext))
|
||||
{
|
||||
// Validation not needed for these request types.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +140,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
string message;
|
||||
var result = _tokenGenerator.TryValidateTokenSet(
|
||||
httpContext,
|
||||
principal,
|
||||
deserializedCookieToken,
|
||||
deserializedRequestToken,
|
||||
out message);
|
||||
|
|
@ -143,7 +158,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ValidateRequestAsync(HttpContext httpContext)
|
||||
public Task ValidateRequestAsync(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
|
|
@ -152,6 +167,29 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
CheckSSLConfig(httpContext);
|
||||
|
||||
return ValidateRequestAsync(httpContext, httpContext.User);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ValidateRequestAsync(HttpContext httpContext, ClaimsPrincipal principal)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
if (principal == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(principal));
|
||||
}
|
||||
|
||||
CheckSSLConfig(httpContext);
|
||||
|
||||
if (!IsValidationRequired(httpContext))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tokens = await _tokenStore.GetRequestTokensAsync(httpContext);
|
||||
if (tokens.CookieToken == null)
|
||||
{
|
||||
|
|
@ -180,12 +218,15 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
}
|
||||
}
|
||||
|
||||
ValidateTokens(httpContext, tokens);
|
||||
ValidateTokens(httpContext, principal, tokens);
|
||||
|
||||
_logger.ValidatedAntiforgeryToken();
|
||||
}
|
||||
|
||||
private void ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)
|
||||
private void ValidateTokens(
|
||||
HttpContext httpContext,
|
||||
ClaimsPrincipal principal,
|
||||
AntiforgeryTokenSet antiforgeryTokenSet)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(antiforgeryTokenSet.CookieToken));
|
||||
Debug.Assert(!string.IsNullOrEmpty(antiforgeryTokenSet.RequestToken));
|
||||
|
|
@ -203,6 +244,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
string message;
|
||||
if (!_tokenGenerator.TryValidateTokenSet(
|
||||
httpContext,
|
||||
principal,
|
||||
deserializedCookieToken,
|
||||
deserializedRequestToken,
|
||||
out message))
|
||||
|
|
@ -268,6 +310,21 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
}
|
||||
}
|
||||
|
||||
private bool IsValidationRequired(HttpContext httpContext)
|
||||
{
|
||||
var method = httpContext.Request.Method;
|
||||
if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(method, "HEAD", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(method, "OPTIONS", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(method, "TRACE", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Validation not needed for HTTP methods that don't mutate any state.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private AntiforgeryContext GetCookieTokens(HttpContext httpContext)
|
||||
{
|
||||
var services = httpContext.RequestServices;
|
||||
|
|
@ -340,7 +397,10 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
if (antiforgeryContext.NewRequestToken == null)
|
||||
{
|
||||
var cookieToken = antiforgeryContext.NewCookieToken ?? antiforgeryContext.CookieToken;
|
||||
antiforgeryContext.NewRequestToken = _tokenGenerator.GenerateRequestToken(httpContext, cookieToken);
|
||||
antiforgeryContext.NewRequestToken = _tokenGenerator.GenerateRequestToken(
|
||||
httpContext,
|
||||
httpContext.User,
|
||||
cookieToken);
|
||||
}
|
||||
|
||||
return antiforgeryContext;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
/// <inheritdoc />
|
||||
public AntiforgeryToken GenerateRequestToken(
|
||||
HttpContext httpContext,
|
||||
ClaimsPrincipal principal,
|
||||
AntiforgeryToken cookieToken)
|
||||
{
|
||||
if (httpContext == null)
|
||||
|
|
@ -63,11 +64,11 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
var isIdentityAuthenticated = false;
|
||||
|
||||
// populate Username and ClaimUid
|
||||
var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User);
|
||||
var authenticatedIdentity = GetAuthenticatedIdentity(principal);
|
||||
if (authenticatedIdentity != null)
|
||||
{
|
||||
isIdentityAuthenticated = true;
|
||||
requestToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User));
|
||||
requestToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(principal));
|
||||
|
||||
if (requestToken.ClaimUid == null)
|
||||
{
|
||||
|
|
@ -109,6 +110,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
/// <inheritdoc />
|
||||
public bool TryValidateTokenSet(
|
||||
HttpContext httpContext,
|
||||
ClaimsPrincipal principal,
|
||||
AntiforgeryToken cookieToken,
|
||||
AntiforgeryToken requestToken,
|
||||
out string message)
|
||||
|
|
@ -150,10 +152,10 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
var currentUsername = string.Empty;
|
||||
BinaryBlob currentClaimUid = null;
|
||||
|
||||
var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User);
|
||||
var authenticatedIdentity = GetAuthenticatedIdentity(principal);
|
||||
if (authenticatedIdentity != null)
|
||||
{
|
||||
currentClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User));
|
||||
currentClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(principal));
|
||||
if (currentClaimUid == null)
|
||||
{
|
||||
currentUsername = authenticatedIdentity.Name ?? string.Empty;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||
|
|
@ -20,9 +21,13 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
/// Generates a request token corresponding to <paramref name="cookieToken"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||
/// <param name="principal">The claims-based principal to use for token generation.</param>
|
||||
/// <param name="cookieToken">A valid cookie token.</param>
|
||||
/// <returns>An <see cref="AntiforgeryToken"/>.</returns>
|
||||
AntiforgeryToken GenerateRequestToken(HttpContext httpContext, AntiforgeryToken cookieToken);
|
||||
AntiforgeryToken GenerateRequestToken(
|
||||
HttpContext httpContext,
|
||||
ClaimsPrincipal principal,
|
||||
AntiforgeryToken cookieToken);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to validate a cookie token.
|
||||
|
|
@ -35,6 +40,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
/// Attempts to validate a cookie and request token set for the given <paramref name="httpContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||
/// <param name="principal">The claims-based principal to use for token validation.</param>
|
||||
/// <param name="cookieToken">A cookie token.</param>
|
||||
/// <param name="requestToken">A request token.</param>
|
||||
/// <param name="message">
|
||||
|
|
@ -43,6 +49,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
/// <returns><c>true</c> if the tokens are valid, otherwise <c>false</c>.</returns>
|
||||
bool TryValidateTokenSet(
|
||||
HttpContext httpContext,
|
||||
ClaimsPrincipal principal,
|
||||
AntiforgeryToken cookieToken,
|
||||
AntiforgeryToken requestToken,
|
||||
out string message);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||
{
|
||||
public static class TaskCache
|
||||
{
|
||||
public static readonly Task CompletedTask = Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.DataProtection": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.WebUtilities": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Http": "1.0.0-*",
|
||||
"Microsoft.Extensions.ObjectPool": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,382 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Antiforgery.Internal;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Builder.Internal;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication.Internal;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery
|
||||
{
|
||||
// These are really more like integration tests and just verify a bunch of different
|
||||
// reasonable combinations of authN middleware.
|
||||
public class AntiforgeryMiddlewareTest
|
||||
{
|
||||
private readonly ClaimsPrincipal LoggedInUser = new ClaimsPrincipal(new ClaimsIdentity[]
|
||||
{
|
||||
new ClaimsIdentity("Test"),
|
||||
});
|
||||
|
||||
private readonly ClaimsPrincipal LoggedInUser2 = new ClaimsPrincipal(new ClaimsIdentity[]
|
||||
{
|
||||
new ClaimsIdentity("Test"),
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public async Task AutomaticAuthentication_Anonymous()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.Use(next => new AutomaticAuthenticationMiddleware(next, null).Invoke);
|
||||
app.UseAntiforgery();
|
||||
});
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Null(context.Principal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AutomaticAuthentication_LoggedIn_WithoutToken()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.UseMiddleware<AutomaticAuthenticationMiddleware>(LoggedInUser);
|
||||
app.UseAntiforgery();
|
||||
});
|
||||
|
||||
context.Antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Null(context.Principal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AutomaticAuthentication_LoggedIn_WithValidToken()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.UseMiddleware<AutomaticAuthenticationMiddleware>(LoggedInUser);
|
||||
app.UseAntiforgery();
|
||||
});
|
||||
|
||||
context.Antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Same(LoggedInUser, context.Principal);
|
||||
}
|
||||
|
||||
// A middleware after antiforgery in the pipeline can authenticate without going through token
|
||||
// validation.
|
||||
[Fact]
|
||||
public async Task AutomaticAuthentication_LoggedIn_WithoutToken_AuthenticatedBySubsequentMiddleware()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.UseMiddleware<AutomaticAuthenticationMiddleware>(LoggedInUser);
|
||||
app.UseAntiforgery();
|
||||
app.UseMiddleware<AutomaticAuthenticationMiddleware>(LoggedInUser2);
|
||||
});
|
||||
|
||||
context.Antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Same(LoggedInUser2, context.Principal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PasiveAuthentication_Anonymous()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.Use(next => new AuthenticationHandlerMiddleware(next, null).Invoke);
|
||||
app.UseAntiforgery();
|
||||
app.UseMiddleware<CallAuthenticateMiddleware>();
|
||||
});
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Null(context.Principal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PassiveAuthentication_LoggedIn_WithoutToken()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.UseMiddleware<AuthenticationHandlerMiddleware>(LoggedInUser);
|
||||
app.UseAntiforgery();
|
||||
app.UseMiddleware<CallAuthenticateMiddleware>();
|
||||
});
|
||||
|
||||
context.Antiforgery
|
||||
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), LoggedInUser))
|
||||
.Throws(new AntiforgeryValidationException("error"));
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Null(context.Principal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PassiveAuthentication_LoggedIn_WithValidToken()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.UseMiddleware<AuthenticationHandlerMiddleware>(LoggedInUser);
|
||||
app.UseAntiforgery();
|
||||
app.UseMiddleware<CallAuthenticateMiddleware>();
|
||||
});
|
||||
|
||||
context.Antiforgery
|
||||
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), LoggedInUser))
|
||||
.Returns(TaskCache.CompletedTask);
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Same(LoggedInUser, context.Principal);
|
||||
}
|
||||
|
||||
// A middleware after antiforgery in the pipeline can authenticate without going through token
|
||||
// validation.
|
||||
[Fact]
|
||||
public async Task PassiveAuthentication_LoggedIn_WithoutToken_AuthenticatedBySubsequentMiddleware()
|
||||
{
|
||||
// Arrange
|
||||
var context = Setup((app) =>
|
||||
{
|
||||
app.UseMiddleware<AuthenticationHandlerMiddleware>(LoggedInUser);
|
||||
app.UseAntiforgery();
|
||||
app.UseMiddleware<AuthenticationHandlerMiddleware>(LoggedInUser2);
|
||||
app.UseMiddleware<CallAuthenticateMiddleware>();
|
||||
});
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
await context.AppFunc(httpContext);
|
||||
|
||||
Assert.Same(LoggedInUser2, context.Principal);
|
||||
}
|
||||
|
||||
private static IHttpAuthenticationFeature GetAuthenticationFeature(HttpContext httpContext)
|
||||
{
|
||||
var authentication = httpContext.Features.Get<IHttpAuthenticationFeature>();
|
||||
if (authentication == null)
|
||||
{
|
||||
authentication = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set(authentication);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
private static TestContext Setup(Action<IApplicationBuilder> action)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddOptions();
|
||||
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
services.AddSingleton(antiforgery.Object);
|
||||
|
||||
var result = new TestContext();
|
||||
result.Antiforgery = antiforgery;
|
||||
|
||||
var app = new ApplicationBuilder(services.BuildServiceProvider());
|
||||
action(app);
|
||||
|
||||
// Capture the logged in user 'after' the middleware so we can validate it.
|
||||
app.Run(c =>
|
||||
{
|
||||
result.Principal = GetAuthenticationFeature(c).User;
|
||||
return TaskCache.CompletedTask;
|
||||
});
|
||||
|
||||
result.AppFunc = app.Build();
|
||||
return result;
|
||||
}
|
||||
|
||||
private class TestContext
|
||||
{
|
||||
public Mock<IAntiforgery> Antiforgery { get; set; }
|
||||
|
||||
public RequestDelegate AppFunc { get; set; }
|
||||
|
||||
public ClaimsPrincipal Principal { get; set; }
|
||||
}
|
||||
|
||||
private class AutomaticAuthenticationMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ClaimsPrincipal _principal;
|
||||
|
||||
public AutomaticAuthenticationMiddleware(RequestDelegate next, ClaimsPrincipal principal)
|
||||
{
|
||||
_next = next;
|
||||
_principal = principal;
|
||||
}
|
||||
|
||||
public Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
GetAuthenticationFeature(httpContext).User = _principal;
|
||||
return _next(httpContext);
|
||||
}
|
||||
}
|
||||
|
||||
private class AuthenticationHandlerMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ClaimsPrincipal _principal;
|
||||
|
||||
public AuthenticationHandlerMiddleware(RequestDelegate next, ClaimsPrincipal principal)
|
||||
{
|
||||
_next = next;
|
||||
_principal = principal;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
var handler = new AuthenticationHandler(_principal);
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
try
|
||||
{
|
||||
await _next(httpContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await handler.TeardownAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AuthenticationHandler : IAuthenticationHandler
|
||||
{
|
||||
private readonly ClaimsPrincipal _principal;
|
||||
private IAuthenticationHandler _priorHandler;
|
||||
private HttpContext _httpContext;
|
||||
|
||||
public AuthenticationHandler(ClaimsPrincipal principal)
|
||||
{
|
||||
_principal = principal;
|
||||
}
|
||||
|
||||
public Task InitializeAsync(HttpContext httpContext)
|
||||
{
|
||||
_httpContext = httpContext;
|
||||
|
||||
var authenticationFeature = GetAuthenticationFeature(_httpContext);
|
||||
_priorHandler = authenticationFeature.Handler;
|
||||
authenticationFeature.Handler = this;
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
public Task TeardownAsync()
|
||||
{
|
||||
var authenticationFeature = GetAuthenticationFeature(_httpContext);
|
||||
authenticationFeature.Handler = _priorHandler;
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
public Task AuthenticateAsync(AuthenticateContext context)
|
||||
{
|
||||
if (_principal == null)
|
||||
{
|
||||
context.NotAuthenticated();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Authenticated(_principal, null, null);
|
||||
}
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ChallengeAsync(ChallengeContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void GetDescriptions(DescribeSchemesContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SignInAsync(SignInContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SignOutAsync(SignOutContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class CallAuthenticateMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public CallAuthenticateMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
var authenticationFeature = GetAuthenticationFeature(httpContext);
|
||||
|
||||
var authenticateContext = new AuthenticateContext("Test");
|
||||
await httpContext.Authentication.AuthenticateAsync(authenticateContext);
|
||||
|
||||
if (authenticateContext.Accepted)
|
||||
{
|
||||
authenticationFeature.User = authenticateContext.Principal;
|
||||
}
|
||||
|
||||
await _next(httpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication.Internal;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Antiforgery.Internal
|
||||
{
|
||||
public class AntiforgeryAuthenticationHandlerTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task IntializeAsync_NoOp_WhenAnonymous()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
// Act
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
// Assert
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IntializeAsync_ValidatesRequest_WhenLoggedIn()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(true)
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
authenticationFeature.User = new ClaimsPrincipal();
|
||||
|
||||
// Act
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
// Assert
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IntializeAsync_ClearsUser_WhenInvalid()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
authenticationFeature.User = new ClaimsPrincipal();
|
||||
|
||||
// Act
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
// Assert
|
||||
Assert.Null(authenticationFeature.User);
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IntializeAsync_AttachesAuthorizationHandler()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
|
||||
// Act
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
// Assert
|
||||
Assert.Same(handler, authenticationFeature.Handler);
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthenticateAsync_NoPriorHandler_NoOp()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), It.IsAny<ClaimsPrincipal>()))
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
var authenticateContext = new AuthenticateContext("Test");
|
||||
|
||||
// Act
|
||||
await handler.AuthenticateAsync(authenticateContext);
|
||||
|
||||
// Assert
|
||||
Assert.False(authenticateContext.Accepted);
|
||||
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||
antiforgery.Verify(
|
||||
a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), It.IsAny<ClaimsPrincipal>()),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthenticateAsync_PriorHandlerDoesNotAuthenticate_NoOp()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), It.IsAny<ClaimsPrincipal>()))
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
var priorHandler = new Mock<IAuthenticationHandler>(MockBehavior.Strict);
|
||||
authenticationFeature.Handler = priorHandler.Object;
|
||||
|
||||
priorHandler
|
||||
.Setup(h => h.AuthenticateAsync(It.IsAny<AuthenticateContext>()))
|
||||
.Returns(TaskCache.CompletedTask)
|
||||
.Callback<AuthenticateContext>(c => c.NotAuthenticated());
|
||||
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
var authenticateContext = new AuthenticateContext("Test");
|
||||
|
||||
// Act
|
||||
await handler.AuthenticateAsync(authenticateContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(authenticateContext.Accepted);
|
||||
Assert.Null(authenticateContext.Principal);
|
||||
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||
antiforgery.Verify(
|
||||
a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), It.IsAny<ClaimsPrincipal>()),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthenticateAsync_PriorHandlerSetsPrincipal_Valid()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
var principal = new ClaimsPrincipal();
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), principal))
|
||||
.Returns(TaskCache.CompletedTask)
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
var priorHandler = new Mock<IAuthenticationHandler>(MockBehavior.Strict);
|
||||
authenticationFeature.Handler = priorHandler.Object;
|
||||
|
||||
priorHandler
|
||||
.Setup(h => h.AuthenticateAsync(It.IsAny<AuthenticateContext>()))
|
||||
.Returns(TaskCache.CompletedTask)
|
||||
.Callback<AuthenticateContext>(c => c.Authenticated(principal, null, null));
|
||||
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
var authenticateContext = new AuthenticateContext("Test");
|
||||
|
||||
// Act
|
||||
await handler.AuthenticateAsync(authenticateContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(authenticateContext.Accepted);
|
||||
Assert.Same(principal, authenticateContext.Principal);
|
||||
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||
antiforgery.Verify(
|
||||
a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), principal),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthenticateAsync_PriorHandlerSetsPrincipal_Invalid()
|
||||
{
|
||||
// Arrange
|
||||
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||
var handler = new AntiforgeryAuthenticationHandler(antiforgery.Object);
|
||||
|
||||
var principal = new ClaimsPrincipal();
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()))
|
||||
.ReturnsAsync(false)
|
||||
.Verifiable();
|
||||
|
||||
antiforgery
|
||||
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), principal))
|
||||
.Throws(new AntiforgeryValidationException("invalid"))
|
||||
.Verifiable();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var authenticationFeature = new HttpAuthenticationFeature();
|
||||
httpContext.Features.Set<IHttpAuthenticationFeature>(authenticationFeature);
|
||||
var priorHandler = new Mock<IAuthenticationHandler>(MockBehavior.Strict);
|
||||
authenticationFeature.Handler = priorHandler.Object;
|
||||
|
||||
priorHandler
|
||||
.Setup(h => h.AuthenticateAsync(It.IsAny<AuthenticateContext>()))
|
||||
.Returns(TaskCache.CompletedTask)
|
||||
.Callback<AuthenticateContext>(c => c.Authenticated(principal, null, null));
|
||||
|
||||
await handler.InitializeAsync(httpContext);
|
||||
|
||||
var authenticateContext = new AuthenticateContext("Test");
|
||||
|
||||
// Act
|
||||
await handler.AuthenticateAsync(authenticateContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(authenticateContext.Accepted);
|
||||
Assert.Null(authenticateContext.Principal);
|
||||
Assert.NotNull(authenticateContext.Error);
|
||||
|
||||
antiforgery.Verify(a => a.IsRequestValidAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||
antiforgery.Verify(
|
||||
a => a.ValidateRequestAsync(It.IsAny<HttpContext>(), principal),
|
||||
Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,22 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
public class DefaultAntiforgeryTest
|
||||
{
|
||||
public static TheoryData<string> SafeHttpMethods => new TheoryData<string>()
|
||||
{
|
||||
"GeT",
|
||||
"HEAD",
|
||||
"options",
|
||||
"TrAcE",
|
||||
};
|
||||
|
||||
public static TheoryData<string> UnsafeHttpMethods => new TheoryData<string>()
|
||||
{
|
||||
"PUT",
|
||||
"post",
|
||||
"Delete",
|
||||
"Custom",
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task ChecksSSL_ValidateRequestAsync_Throws()
|
||||
{
|
||||
|
|
@ -36,6 +52,26 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ChecksSSL_ValidateRequestAsync_WithPrincipal_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = GetHttpContext();
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
RequireSsl = true
|
||||
};
|
||||
var antiforgery = GetAntiforgery(httpContext, options);
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => antiforgery.ValidateRequestAsync(httpContext, new ClaimsPrincipal()));
|
||||
Assert.Equal(
|
||||
@"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " +
|
||||
"but the current request is not an SSL request.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ChecksSSL_IsRequestValidAsync_Throws()
|
||||
{
|
||||
|
|
@ -57,6 +93,27 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ChecksSSL_IsRequestValidAsync_WithPrincipal_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = GetHttpContext();
|
||||
var options = new AntiforgeryOptions()
|
||||
{
|
||||
RequireSsl = true
|
||||
};
|
||||
|
||||
var antiforgery = GetAntiforgery(httpContext, options);
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => antiforgery.IsRequestValidAsync(httpContext, new ClaimsPrincipal()));
|
||||
Assert.Equal(
|
||||
@"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " +
|
||||
"but the current request is not an SSL request.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChecksSSL_GetAndStoreTokens_Throws()
|
||||
{
|
||||
|
|
@ -420,6 +477,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
context.TestTokenSet.OldCookieToken,
|
||||
context.TestTokenSet.RequestToken,
|
||||
out message))
|
||||
|
|
@ -454,6 +512,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
context.TestTokenSet.OldCookieToken,
|
||||
context.TestTokenSet.RequestToken,
|
||||
out message))
|
||||
|
|
@ -497,6 +556,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
contextAccessor.Value.CookieToken,
|
||||
contextAccessor.Value.RequestToken,
|
||||
out message))
|
||||
|
|
@ -522,10 +582,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("GeT")]
|
||||
[InlineData("HEAD")]
|
||||
[InlineData("options")]
|
||||
[InlineData("TrAcE")]
|
||||
[MemberData(nameof(SafeHttpMethods))]
|
||||
public async Task IsRequestValidAsync_SkipsAntiforgery_ForSafeHttpMethods(string httpMethod)
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -536,6 +593,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
|
|
@ -552,6 +610,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Verify(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message),
|
||||
|
|
@ -559,10 +618,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("PUT")]
|
||||
[InlineData("post")]
|
||||
[InlineData("Delete")]
|
||||
[InlineData("Custom")]
|
||||
[MemberData(nameof(UnsafeHttpMethods))]
|
||||
public async Task IsRequestValidAsync_ValidatesAntiforgery_ForNonSafeHttpMethods(string httpMethod)
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -573,6 +629,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
|
|
@ -589,6 +646,68 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IsRequestValidAsync_UsesPrincipalFromHttpContext()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateMockContext(new AntiforgeryOptions());
|
||||
context.HttpContext.Request.Method = "POST";
|
||||
|
||||
var principal = new ClaimsPrincipal();
|
||||
context.HttpContext.User = principal;
|
||||
|
||||
string message;
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
principal,
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
.Returns(true)
|
||||
.Verifiable();
|
||||
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
var result = await antiforgery.IsRequestValidAsync(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
context.TokenGenerator.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IsRequestValidAsync_UsesPassedInPrincipal()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateMockContext(new AntiforgeryOptions());
|
||||
context.HttpContext.Request.Method = "POST";
|
||||
|
||||
var principal = new ClaimsPrincipal();
|
||||
context.HttpContext.User = new ClaimsPrincipal(); // This should be ignored.
|
||||
|
||||
string message;
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
principal,
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
.Returns(true)
|
||||
.Verifiable();
|
||||
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
var result = await antiforgery.IsRequestValidAsync(context.HttpContext, principal);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
context.TokenGenerator.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateRequestAsync_FromStore_Failure()
|
||||
{
|
||||
|
|
@ -600,6 +719,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
context.TestTokenSet.OldCookieToken,
|
||||
context.TestTokenSet.RequestToken,
|
||||
out message))
|
||||
|
|
@ -632,6 +752,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
context.TestTokenSet.OldCookieToken,
|
||||
context.TestTokenSet.RequestToken,
|
||||
out message))
|
||||
|
|
@ -776,6 +897,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
contextAccessor.Value.CookieToken,
|
||||
contextAccessor.Value.RequestToken,
|
||||
out message))
|
||||
|
|
@ -799,6 +921,129 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
Times.Never);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SafeHttpMethods))]
|
||||
public async Task ValidateRequestAsync_SkipsAntiforgery_ForSafeHttpMethods(string httpMethod)
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateMockContext(new AntiforgeryOptions());
|
||||
context.HttpContext.Request.Method = httpMethod;
|
||||
|
||||
string message;
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
.Returns(false)
|
||||
.Verifiable();
|
||||
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
await antiforgery.ValidateRequestAsync(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
context.TokenGenerator
|
||||
.Verify(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message),
|
||||
Times.Never);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(UnsafeHttpMethods))]
|
||||
public async Task ValidateRequestAsync_ValidatesAntiforgery_ForNonSafeHttpMethods(string httpMethod)
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateMockContext(new AntiforgeryOptions());
|
||||
context.HttpContext.Request.Method = httpMethod;
|
||||
|
||||
string message;
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
.Returns(true)
|
||||
.Verifiable();
|
||||
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
await antiforgery.ValidateRequestAsync(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
context.TokenGenerator.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateRequestAsync_UsesPrincipalFromHttpContext()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateMockContext(new AntiforgeryOptions());
|
||||
context.HttpContext.Request.Method = "POST";
|
||||
|
||||
var principal = new ClaimsPrincipal();
|
||||
context.HttpContext.User = principal;
|
||||
|
||||
string message;
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
principal,
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
.Returns(true)
|
||||
.Verifiable();
|
||||
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
await antiforgery.ValidateRequestAsync(context.HttpContext);
|
||||
|
||||
// Assert
|
||||
context.TokenGenerator.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateRequestAsync_UsesPassedInPrincipal()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateMockContext(new AntiforgeryOptions());
|
||||
context.HttpContext.Request.Method = "POST";
|
||||
|
||||
var principal = new ClaimsPrincipal();
|
||||
context.HttpContext.User = new ClaimsPrincipal(); // This should be ignored.
|
||||
|
||||
string message;
|
||||
context.TokenGenerator
|
||||
.Setup(o => o.TryValidateTokenSet(
|
||||
context.HttpContext,
|
||||
principal,
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
It.IsAny<AntiforgeryToken>(),
|
||||
out message))
|
||||
.Returns(true)
|
||||
.Verifiable();
|
||||
|
||||
var antiforgery = GetAntiforgery(context);
|
||||
|
||||
// Act
|
||||
await antiforgery.ValidateRequestAsync(context.HttpContext, principal);
|
||||
|
||||
// Assert
|
||||
context.TokenGenerator.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, "SAMEORIGIN")]
|
||||
[InlineData(true, null)]
|
||||
|
|
@ -1045,6 +1290,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
mockGenerator
|
||||
.Setup(o => o.GenerateRequestToken(
|
||||
httpContext,
|
||||
It.IsAny<ClaimsPrincipal>(),
|
||||
useOldCookie ? testTokenSet.OldCookieToken : testTokenSet.NewCookieToken))
|
||||
.Returns(testTokenSet.RequestToken);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = false };
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
|
||||
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
|
||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgument(
|
||||
() => tokenProvider.GenerateRequestToken(httpContext, cookieToken),
|
||||
() => tokenProvider.GenerateRequestToken(httpContext, principal, cookieToken),
|
||||
"cookieToken",
|
||||
"The antiforgery cookie token is invalid.");
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
|
||||
var tokenProvider = new DefaultAntiforgeryTokenGenerator(
|
||||
|
|
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
additionalDataProvider: null);
|
||||
|
||||
// Act
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, principal, cookieToken);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(fieldToken);
|
||||
|
|
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());
|
||||
var principal = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());
|
||||
|
||||
var options = new AntiforgeryOptions();
|
||||
var claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
|
||||
|
|
@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act & assert
|
||||
var exception = Assert.Throws<InvalidOperationException>(
|
||||
() => tokenProvider.GenerateRequestToken(httpContext, cookieToken));
|
||||
() => tokenProvider.GenerateRequestToken(httpContext, principal, cookieToken));
|
||||
Assert.Equal(
|
||||
"The provided identity of type " +
|
||||
$"'{typeof(MyAuthenticatedIdentityWithoutUsername).FullName}' " +
|
||||
|
|
@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());
|
||||
var principal = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());
|
||||
|
||||
var mockAdditionalDataProvider = new Mock<IAntiforgeryAdditionalDataProvider>();
|
||||
mockAdditionalDataProvider.Setup(o => o.GetAdditionalData(httpContext))
|
||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
additionalDataProvider: mockAdditionalDataProvider.Object);
|
||||
|
||||
// Act
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, principal, cookieToken);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(fieldToken);
|
||||
|
|
@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
var identity = GetAuthenticatedIdentity("some-identity");
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
byte[] data = new byte[256 / 8];
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
|
|
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
additionalDataProvider: null);
|
||||
|
||||
// Act
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, principal, cookieToken);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(fieldToken);
|
||||
|
|
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
mockIdentity.Setup(o => o.Name)
|
||||
.Returns("my-username");
|
||||
|
||||
httpContext.User = new ClaimsPrincipal(mockIdentity.Object);
|
||||
var principal = new ClaimsPrincipal(mockIdentity.Object);
|
||||
|
||||
var claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
|
||||
|
||||
|
|
@ -199,7 +199,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
additionalDataProvider: null);
|
||||
|
||||
// Act
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);
|
||||
var fieldToken = tokenProvider.GenerateRequestToken(httpContext, principal, cookieToken);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(fieldToken);
|
||||
|
|
@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
|
||||
|
||||
|
|
@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Act & Assert
|
||||
string message;
|
||||
var ex = Assert.Throws<ArgumentNullException>(
|
||||
() => tokenProvider.TryValidateTokenSet(httpContext, null, fieldtoken, out message));
|
||||
() => tokenProvider.TryValidateTokenSet(httpContext, principal, null, fieldtoken, out message));
|
||||
|
||||
var trimmed = ex.Message.Substring(0, ex.Message.IndexOf(Environment.NewLine));
|
||||
Assert.Equal(@"The required antiforgery cookie token must be provided.", trimmed);
|
||||
|
|
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
|
||||
|
|
@ -306,7 +306,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Act & Assert
|
||||
string message;
|
||||
var ex = Assert.Throws<ArgumentNullException>(
|
||||
() => tokenProvider.TryValidateTokenSet(httpContext, cookieToken, null, out message));
|
||||
() => tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, null, out message));
|
||||
|
||||
var trimmed = ex.Message.Substring(0, ex.Message.IndexOf(Environment.NewLine));
|
||||
Assert.Equal("The required antiforgery request token must be provided.", trimmed);
|
||||
|
|
@ -317,7 +317,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
|
||||
|
|
@ -332,7 +332,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, fieldtoken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, fieldtoken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -344,7 +344,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
|
||||
|
|
@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, cookieToken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, cookieToken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -371,7 +371,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken() { IsCookieToken = false };
|
||||
|
|
@ -384,7 +384,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -400,7 +400,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var identity = GetAuthenticatedIdentity(identityUsername);
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken()
|
||||
|
|
@ -424,7 +424,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -437,7 +437,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var identity = GetAuthenticatedIdentity("the-user");
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken()
|
||||
|
|
@ -462,7 +462,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -475,7 +475,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var identity = new ClaimsIdentity();
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken()
|
||||
|
|
@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var identity = new ClaimsIdentity();
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken()
|
||||
|
|
@ -533,7 +533,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
|
|
@ -546,7 +546,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var identity = GetAuthenticatedIdentity("the-user");
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken()
|
||||
|
|
@ -567,7 +567,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
|
|
@ -580,7 +580,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var identity = GetAuthenticatedIdentity("the-user");
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var cookieToken = new AntiforgeryToken() { IsCookieToken = true };
|
||||
var fieldtoken = new AntiforgeryToken()
|
||||
|
|
@ -600,7 +600,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
|
|||
|
||||
// Act
|
||||
string message;
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);
|
||||
var result = tokenProvider.TryValidateTokenSet(httpContext, principal, cookieToken, fieldtoken, out message);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
|
|
|
|||
Loading…
Reference in New Issue