diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/AutoValidateAntiforgeryTokenAuthorizationFilter.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/AutoValidateAntiforgeryTokenAuthorizationFilter.cs index cb3d2a4ce8..368082970a 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/AutoValidateAntiforgeryTokenAuthorizationFilter.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/AutoValidateAntiforgeryTokenAuthorizationFilter.cs @@ -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) { } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/ValidateAntiforgeryTokenAuthorizationFilter.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/ValidateAntiforgeryTokenAuthorizationFilter.cs index 50eb7792ea..835d39825f 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/ValidateAntiforgeryTokenAuthorizationFilter.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Internal/ValidateAntiforgeryTokenAuthorizationFilter.cs @@ -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(); } - 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) diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ValidateAntiforgeryTokenAuthorizationFilterLoggerExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ValidateAntiforgeryTokenAuthorizationFilterLoggerExtensions.cs new file mode 100644 index 0000000000..84c514fec3 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Logging/ValidateAntiforgeryTokenAuthorizationFilterLoggerExtensions.cs @@ -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 _antiforgeryTokenInvalid; + + static ValidateAntiforgeryTokenAuthorizationFilterLoggerExtensions() + { + _antiforgeryTokenInvalid = LoggerMessage.Define( + LogLevel.Information, + 1, + "Antiforgery token validation failed. {Message}"); + } + + public static void AntiforgeryTokenInvalid(this ILogger logger, string message, Exception exception) + { + _antiforgeryTokenInvalid(logger, message, exception); + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/AntiforgeryTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/AntiforgeryTests.cs index 6256155a70..7bf14aac8e 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/AntiforgeryTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/AntiforgeryTests.cs @@ -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> + { + new KeyValuePair("__RequestVerificationToken", formToken), + new KeyValuePair("UserName", "test"), + new KeyValuePair("Password", "password"), + }; + + request.Content = new FormUrlEncodedContent(nameValueCollection); + + // Act + var response = await Client.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/AutoValidateAntiforgeryTokenAuthorizationFilterTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/AutoValidateAntiforgeryTokenAuthorizationFilterTest.cs index aebece829b..6d9a05251c 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/AutoValidateAntiforgeryTokenAuthorizationFilterTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/AutoValidateAntiforgeryTokenAuthorizationFilterTest.cs @@ -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"; diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/ValidateAntiforgeryTokenAuthorizationFilterTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/ValidateAntiforgeryTokenAuthorizationFilterTest.cs index 3c645ffce4..83776f5e6f 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/ValidateAntiforgeryTokenAuthorizationFilterTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Internal/ValidateAntiforgeryTokenAuthorizationFilterTest.cs @@ -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";