Return BadRequest response when antiforgery token validation fails

This commit is contained in:
Ajay Bhargav Baaskaran 2016-01-07 11:49:25 -08:00
parent 8afe28c05d
commit bf1fcf6b56
6 changed files with 80 additions and 12 deletions

View File

@ -4,13 +4,14 @@
using System;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
{
public class AutoValidateAntiforgeryTokenAuthorizationFilter : ValidateAntiforgeryTokenAuthorizationFilter
{
public AutoValidateAntiforgeryTokenAuthorizationFilter(IAntiforgery antiforgery)
: base(antiforgery)
public AutoValidateAntiforgeryTokenAuthorizationFilter(IAntiforgery antiforgery, ILoggerFactory loggerFactory)
: base(antiforgery, loggerFactory)
{
}

View File

@ -8,14 +8,17 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
{
public class ValidateAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy
{
private readonly IAntiforgery _antiforgery;
private readonly ILogger _logger;
public ValidateAntiforgeryTokenAuthorizationFilter(IAntiforgery antiforgery)
public ValidateAntiforgeryTokenAuthorizationFilter(IAntiforgery antiforgery, ILoggerFactory loggerFactory)
{
if (antiforgery == null)
{
@ -23,9 +26,10 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
}
_antiforgery = antiforgery;
_logger = loggerFactory.CreateLogger<ValidateAntiforgeryTokenAuthorizationFilter>();
}
public Task OnAuthorizationAsync(AuthorizationContext context)
public async Task OnAuthorizationAsync(AuthorizationContext context)
{
if (context == null)
{
@ -34,10 +38,16 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
if (IsClosestAntiforgeryPolicy(context.Filters) && ShouldValidate(context))
{
return _antiforgery.ValidateRequestAsync(context.HttpContext);
try
{
await _antiforgery.ValidateRequestAsync(context.HttpContext);
}
catch (AntiforgeryValidationException exception)
{
_logger.AntiforgeryTokenInvalid(exception.Message, exception);
context.Result = new BadRequestResult();
}
}
return TaskCache.CompletedTask;
}
protected virtual bool ShouldValidate(AuthorizationContext context)

View File

@ -0,0 +1,26 @@
// 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.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class ValidateAntiforgeryTokenAuthorizationFilterLoggerExtensions
{
private static readonly Action<ILogger, string, Exception> _antiforgeryTokenInvalid;
static ValidateAntiforgeryTokenAuthorizationFilterLoggerExtensions()
{
_antiforgeryTokenInvalid = LoggerMessage.Define<string>(
LogLevel.Information,
1,
"Antiforgery token validation failed. {Message}");
}
public static void AntiforgeryTokenInvalid(this ILogger logger, string message, Exception exception)
{
_antiforgeryTokenInvalid(logger, message, exception);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNet.Antiforgery;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
@ -116,5 +117,33 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("OK", await response.Content.ReadAsStringAsync());
}
[Fact]
public async Task Antiforgery_HeaderNotSet_SendsBadRequest()
{
// Arrange
var getResponse = await Client.GetAsync("http://localhost/Antiforgery/Login");
var responseBody = await getResponse.Content.ReadAsStringAsync();
var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(
responseBody,
"Antiforgery/Login");
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Antiforgery/Login");
var nameValueCollection = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string,string>("__RequestVerificationToken", formToken),
new KeyValuePair<string,string>("UserName", "test"),
new KeyValuePair<string,string>("Password", "password"),
};
request.Content = new FormUrlEncodedContent(nameValueCollection);
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
}
}

View File

@ -8,6 +8,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Logging.Testing;
using Moq;
using Xunit;
@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
.Returns(Task.FromResult(0))
.Verifiable();
var filter = new AutoValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object);
var filter = new AutoValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object, NullLoggerFactory.Instance);
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
actionContext.HttpContext.Request.Method = httpMethod;
@ -56,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
.Returns(Task.FromResult(0))
.Verifiable();
var filter = new AutoValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object);
var filter = new AutoValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object, NullLoggerFactory.Instance);
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
actionContext.HttpContext.Request.Method = httpMethod;
@ -80,7 +81,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
.Returns(Task.FromResult(0))
.Verifiable();
var filter = new AutoValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object);
var filter = new AutoValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object, NullLoggerFactory.Instance);
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
actionContext.HttpContext.Request.Method = "POST";

View File

@ -8,6 +8,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Logging.Testing;
using Moq;
using Xunit;
@ -32,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
.Returns(Task.FromResult(0))
.Verifiable();
var filter = new ValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object);
var filter = new ValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object, NullLoggerFactory.Instance);
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
actionContext.HttpContext.Request.Method = httpMethod;
@ -56,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
.Returns(Task.FromResult(0))
.Verifiable();
var filter = new ValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object);
var filter = new ValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object, NullLoggerFactory.Instance);
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
actionContext.HttpContext.Request.Method = "POST";