* Add logging to Antiforgery

This commit is contained in:
ryanbrandenburg 2016-02-05 15:18:56 -08:00
parent 08cf13b870
commit c8a9ecc0c1
4 changed files with 141 additions and 23 deletions

View File

@ -0,0 +1,77 @@
// 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.AspNetCore.Antiforgery.Internal
{
internal static class AntiforgeryLoggerExtensions
{
private static readonly Action<ILogger, string, Exception> _validationFailed;
private static readonly Action<ILogger, Exception> _validated;
private static readonly Action<ILogger, string, Exception> _missingCookieToken;
private static readonly Action<ILogger, string, string, Exception> _missingRequestToken;
private static readonly Action<ILogger, Exception> _newCookieToken;
private static readonly Action<ILogger, Exception> _reusedCookieToken;
static AntiforgeryLoggerExtensions()
{
_validationFailed = LoggerMessage.Define<string>(
LogLevel.Warning,
1,
"Antiforgery validation failed with message '{Message}'.");
_validated = LoggerMessage.Define(
LogLevel.Debug,
2,
"Antiforgery successfully validated a request.");
_missingCookieToken = LoggerMessage.Define<string>(
LogLevel.Warning,
3,
"The required antiforgery cookie '{CookieName}' is not present.");
_missingRequestToken = LoggerMessage.Define<string, string>(
LogLevel.Warning,
4,
"The required antiforgery request token was not provided in either form field '{FormFieldName}' "
+ "or header '{HeaderName}'.");
_newCookieToken = LoggerMessage.Define(
LogLevel.Debug,
5,
"A new antiforgery cookie token was created.");
_reusedCookieToken = LoggerMessage.Define(
LogLevel.Debug,
6,
"An antiforgery cookie token was reused.");
}
public static void ValidationFailed(this ILogger logger, string message)
{
_validationFailed(logger, message, null);
}
public static void ValidatedAntiforgeryToken(this ILogger logger)
{
_validated(logger, null);
}
public static void MissingCookieToken(this ILogger logger, string cookieName)
{
_missingCookieToken(logger, cookieName, null);
}
public static void MissingRequestToken(this ILogger logger, string formFieldName, string headerName)
{
_missingRequestToken(logger, formFieldName, headerName, null);
}
public static void NewCookieToken(this ILogger logger)
{
_newCookieToken(logger, null);
}
public static void ReusedCookieToken(this ILogger logger)
{
_reusedCookieToken(logger, null);
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Antiforgery.Internal
@ -19,17 +20,20 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
private readonly IAntiforgeryTokenGenerator _tokenGenerator;
private readonly IAntiforgeryTokenSerializer _tokenSerializer;
private readonly IAntiforgeryTokenStore _tokenStore;
private readonly ILogger<DefaultAntiforgery> _logger;
public DefaultAntiforgery(
IOptions<AntiforgeryOptions> antiforgeryOptionsAccessor,
IAntiforgeryTokenGenerator tokenGenerator,
IAntiforgeryTokenSerializer tokenSerializer,
IAntiforgeryTokenStore tokenStore)
IAntiforgeryTokenStore tokenStore,
ILoggerFactory loggerFactory)
{
_options = antiforgeryOptionsAccessor.Value;
_tokenGenerator = tokenGenerator;
_tokenSerializer = tokenSerializer;
_tokenStore = tokenStore;
_logger = loggerFactory.CreateLogger<DefaultAntiforgery>();
}
/// <inheritdoc />
@ -46,6 +50,11 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
if (tokenSet.IsNewCookieToken)
{
SaveCookieTokenAndHeader(httpContext, tokenSet.CookieToken);
_logger.NewCookieToken();
}
else
{
_logger.ReusedCookieToken();
}
return Serialize(tokenSet);
@ -76,8 +85,14 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
CheckSSLConfig(httpContext);
var tokens = await _tokenStore.GetRequestTokensAsync(httpContext);
if (tokens.CookieToken == null || tokens.RequestToken == null)
if (tokens.CookieToken == null)
{
_logger.MissingCookieToken(_options.CookieName);
return false;
}
if (tokens.RequestToken == null)
{
_logger.MissingRequestToken(_options.FormFieldName, _options.HeaderName);
return false;
}
@ -87,11 +102,22 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
// Validate
string message;
return _tokenGenerator.TryValidateTokenSet(
var result = _tokenGenerator.TryValidateTokenSet(
httpContext,
deserializedCookieToken,
deserializedRequestToken,
out message);
if (result)
{
_logger.ValidatedAntiforgeryToken();
}
else
{
_logger.ValidationFailed(message);
}
return result;
}
/// <inheritdoc />
@ -133,6 +159,8 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
}
ValidateTokens(httpContext, tokens);
_logger.ValidatedAntiforgeryToken();
}
private void ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)

View File

@ -6,6 +6,9 @@ using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
@ -18,13 +21,12 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
public async Task ChecksSSL_ValidateRequestAsync_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
var httpContext = GetHttpContext();
var options = new AntiforgeryOptions()
{
RequireSsl = true
};
var antiforgery = GetAntiforgery(options);
var antiforgery = GetAntiforgery(httpContext, options);
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
@ -39,13 +41,13 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
public async Task ChecksSSL_IsRequestValidAsync_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
var httpContext = GetHttpContext();
var options = new AntiforgeryOptions()
{
RequireSsl = true
};
var antiforgery = GetAntiforgery(options);
var antiforgery = GetAntiforgery(httpContext, options);
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
@ -60,13 +62,13 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
public void ChecksSSL_GetAndStoreTokens_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
var httpContext = GetHttpContext();
var options = new AntiforgeryOptions()
{
RequireSsl = true
};
var antiforgery = GetAntiforgery(options);
var antiforgery = GetAntiforgery(httpContext, options);
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
@ -81,13 +83,13 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
public void ChecksSSL_GetTokens_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
var httpContext = GetHttpContext();
var options = new AntiforgeryOptions()
{
RequireSsl = true
};
var antiforgery = GetAntiforgery(options);
var antiforgery = GetAntiforgery(httpContext, options);
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
@ -102,13 +104,13 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
public void ChecksSSL_SetCookieTokenAndHeader_Throws()
{
// Arrange
var httpContext = new DefaultHttpContext();
var httpContext = GetHttpContext();
var options = new AntiforgeryOptions()
{
RequireSsl = true
};
var antiforgery = GetAntiforgery(options);
var antiforgery = GetAntiforgery(httpContext, options);
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
@ -290,12 +292,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
out message))
.Returns(false)
.Verifiable();
var antiforgery = new DefaultAntiforgery(
new TestOptionsManager(),
context.TokenGenerator.Object,
context.TokenSerializer.Object,
context.TokenStore.Object);
var antiforgery = GetAntiforgery(context);
// Act & assert
var exception = await Assert.ThrowsAsync<AntiforgeryValidationException>(
@ -458,6 +455,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
}
private DefaultAntiforgery GetAntiforgery(
HttpContext httpContext,
AntiforgeryOptions options = null,
IAntiforgeryTokenGenerator tokenGenerator = null,
IAntiforgeryTokenSerializer tokenSerializer = null,
@ -469,16 +467,29 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
optionsManager.Value = options;
}
var loggerFactory = httpContext.RequestServices.GetRequiredService<ILoggerFactory>();
return new DefaultAntiforgery(
antiforgeryOptionsAccessor: optionsManager,
tokenGenerator: tokenGenerator,
tokenSerializer: tokenSerializer,
tokenStore: tokenStore);
tokenStore: tokenStore,
loggerFactory: loggerFactory);
}
private IServiceProvider GetServices()
{
var builder = new ServiceCollection();
builder.AddSingleton<ILoggerFactory>(new LoggerFactory());
return builder.BuildServiceProvider();
}
private HttpContext GetHttpContext()
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = GetServices();
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity("some-auth"));
return httpContext;
}
@ -486,6 +497,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
private DefaultAntiforgery GetAntiforgery(AntiforgeryMockContext context)
{
return GetAntiforgery(
context.HttpContext,
context.Options,
context.TokenGenerator?.Object,
context.TokenSerializer?.Object,
@ -630,4 +642,4 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
public AntiforgeryOptions Value { get; set; } = new AntiforgeryOptions();
}
}
}
}

View File

@ -8,6 +8,7 @@
"Microsoft.AspNetCore.Http": "1.0.0-*",
"Microsoft.AspNetCore.Testing": "1.0.0-*",
"Microsoft.Extensions.DependencyInjection": "1.0.0-*",
"Microsoft.Extensions.Logging": "1.0.0-*",
"Microsoft.Extensions.WebEncoders": "1.0.0-*",
"Microsoft.NETCore.Platforms": "1.0.1-*",
"xunit": "2.1.0-*"
@ -19,7 +20,7 @@
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.Threading.Tasks": ""
"System.Threading.Tasks": ""
},
"dependencies": {
"Moq": "4.2.1312.1622",