Merge AuthZ ToString PR (#15350)

Rebased verison of https://github.com/aspnet/AspNetCore/pull/10822
This commit is contained in:
Hao Kung 2019-10-25 14:28:13 -07:00 committed by GitHub
parent affd7e00df
commit c376e833e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 400 additions and 10 deletions

View File

@ -177,6 +177,7 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
public System.Func<Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext, System.Threading.Tasks.Task<bool>> Handler { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
[System.Diagnostics.DebuggerStepThroughAttribute]
public System.Threading.Tasks.Task HandleAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context) { throw null; }
public override string ToString() { throw null; }
}
public partial class ClaimsAuthorizationRequirement : Microsoft.AspNetCore.Authorization.AuthorizationHandler<Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement>, Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
@ -184,22 +185,26 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
public System.Collections.Generic.IEnumerable<string> AllowedValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string ClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
public partial class DenyAnonymousAuthorizationRequirement : Microsoft.AspNetCore.Authorization.AuthorizationHandler<Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement>, Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
public DenyAnonymousAuthorizationRequirement() { }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
public partial class NameAuthorizationRequirement : Microsoft.AspNetCore.Authorization.AuthorizationHandler<Microsoft.AspNetCore.Authorization.Infrastructure.NameAuthorizationRequirement>, Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
public NameAuthorizationRequirement(string requiredName) { }
public string RequiredName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.NameAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
public partial class OperationAuthorizationRequirement : Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
public OperationAuthorizationRequirement() { }
public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public override string ToString() { throw null; }
}
public partial class PassThroughAuthorizationHandler : Microsoft.AspNetCore.Authorization.IAuthorizationHandler
{
@ -212,6 +217,7 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
public RolesAuthorizationRequirement(System.Collections.Generic.IEnumerable<string> allowedRoles) { }
public System.Collections.Generic.IEnumerable<string> AllowedRoles { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.RolesAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
}
namespace Microsoft.Extensions.DependencyInjection

View File

@ -177,6 +177,7 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
public System.Func<Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext, System.Threading.Tasks.Task<bool>> Handler { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
[System.Diagnostics.DebuggerStepThroughAttribute]
public System.Threading.Tasks.Task HandleAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context) { throw null; }
public override string ToString() { throw null; }
}
public partial class ClaimsAuthorizationRequirement : Microsoft.AspNetCore.Authorization.AuthorizationHandler<Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement>, Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
@ -184,22 +185,26 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
public System.Collections.Generic.IEnumerable<string> AllowedValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string ClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
public partial class DenyAnonymousAuthorizationRequirement : Microsoft.AspNetCore.Authorization.AuthorizationHandler<Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement>, Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
public DenyAnonymousAuthorizationRequirement() { }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
public partial class NameAuthorizationRequirement : Microsoft.AspNetCore.Authorization.AuthorizationHandler<Microsoft.AspNetCore.Authorization.Infrastructure.NameAuthorizationRequirement>, Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
public NameAuthorizationRequirement(string requiredName) { }
public string RequiredName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.NameAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
public partial class OperationAuthorizationRequirement : Microsoft.AspNetCore.Authorization.IAuthorizationRequirement
{
public OperationAuthorizationRequirement() { }
public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public override string ToString() { throw null; }
}
public partial class PassThroughAuthorizationHandler : Microsoft.AspNetCore.Authorization.IAuthorizationHandler
{
@ -212,6 +217,7 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
public RolesAuthorizationRequirement(System.Collections.Generic.IEnumerable<string> allowedRoles) { }
public System.Collections.Generic.IEnumerable<string> AllowedRoles { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
protected override System.Threading.Tasks.Task HandleRequirementAsync(Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext context, Microsoft.AspNetCore.Authorization.Infrastructure.RolesAuthorizationRequirement requirement) { throw null; }
public override string ToString() { throw null; }
}
}
namespace Microsoft.Extensions.DependencyInjection

View File

@ -56,5 +56,10 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
context.Succeed(this);
}
}
public override string ToString()
{
return $"{nameof(Handler)} assertion should evaluate to true.";
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authorization.Infrastructure
@ -69,5 +70,14 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
}
return Task.CompletedTask;
}
public override string ToString()
{
var value = (AllowedValues == null || !AllowedValues.Any())
? string.Empty
: $" and Claim.Value is one of the following values: ({string.Join("|", AllowedValues)})";
return $"{nameof(ClaimsAuthorizationRequirement)}:Claim.Type={ClaimType}{value}";
}
}
}

View File

@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Authorization
}
else
{
_logger.UserAuthorizationFailed();
_logger.UserAuthorizationFailed(result.Failure);
}
return result;
}
@ -132,4 +132,4 @@ namespace Microsoft.AspNetCore.Authorization
return await this.AuthorizeAsync(user, resource, policy);
}
}
}
}

View File

@ -29,5 +29,10 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
}
return Task.CompletedTask;
}
public override string ToString()
{
return $"{nameof(DenyAnonymousAuthorizationRequirement)}:Requires an authenticated user.";
}
}
}

View File

@ -2,12 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Authorization;
namespace Microsoft.Extensions.Logging
{
internal static class LoggingExtensions
{
private static Action<ILogger, Exception> _userAuthorizationFailed;
private static Action<ILogger, string, Exception> _userAuthorizationFailed;
private static Action<ILogger, Exception> _userAuthorizationSucceeded;
static LoggingExtensions()
@ -16,16 +17,22 @@ namespace Microsoft.Extensions.Logging
eventId: new EventId(1, "UserAuthorizationSucceeded"),
logLevel: LogLevel.Information,
formatString: "Authorization was successful.");
_userAuthorizationFailed = LoggerMessage.Define(
_userAuthorizationFailed = LoggerMessage.Define<string>(
eventId: new EventId(2, "UserAuthorizationFailed"),
logLevel: LogLevel.Information,
formatString: "Authorization failed.");
formatString: "Authorization failed for {0}");
}
public static void UserAuthorizationSucceeded(this ILogger logger)
=> _userAuthorizationSucceeded(logger, null);
public static void UserAuthorizationFailed(this ILogger logger)
=> _userAuthorizationFailed(logger, null);
public static void UserAuthorizationFailed(this ILogger logger, AuthorizationFailure failure)
{
var reason = failure.FailCalled
? "Fail() was explicitly called."
: "These requirements were not met:" + Environment.NewLine + string.Join(Environment.NewLine, failure.FailedRequirements);
_userAuthorizationFailed(logger, reason, null);
}
}
}

View File

@ -48,5 +48,10 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
}
return Task.CompletedTask;
}
public override string ToString()
{
return $"{nameof(NameAuthorizationRequirement)}:Requires a user identity with Name equal to {RequiredName}";
}
}
}

View File

@ -13,5 +13,10 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
/// The name of this instance of <see cref="IAuthorizationRequirement"/>.
/// </summary>
public string Name { get; set; }
public override string ToString()
{
return $"{nameof(OperationAuthorizationRequirement)}:Name={Name}";
}
}
}

View File

@ -64,5 +64,11 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure
return Task.CompletedTask;
}
public override string ToString()
{
var roles = $"User.IsInRole must be true for one of the following roles: ({string.Join("|", AllowedRoles)})";
return $"{nameof(RolesAuthorizationRequirement)}:{roles}";
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class AssertionRequirementsTests
{
private AssertionRequirement CreateRequirement()
{
return new AssertionRequirement(context => true);
}
[Fact]
public void ToString_ShouldReturnFormatValue()
{
// Arrange
var requirement = new AssertionRequirement(context => true);
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("Handler assertion should evaluate to true.", formattedValue);
}
}
}

View File

@ -0,0 +1,58 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class ClaimsAuthorizationRequirementTests
{
public ClaimsAuthorizationRequirement CreateRequirement(string claimType, params string[] allowedValues)
{
return new ClaimsAuthorizationRequirement(claimType, allowedValues);
}
[Fact]
public void ToString_ShouldReturnAndDescriptionWhenAllowedValuesNotNull()
{
// Arrange
var requirement = CreateRequirement("Custom", "CustomValue1", "CustomValue2");
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("ClaimsAuthorizationRequirement:Claim.Type=Custom and Claim.Value is one of the following values: (CustomValue1|CustomValue2)", formattedValue);
}
[Fact]
public void ToString_ShouldReturnWithoutAllowedDescriptionWhenAllowedValuesIsNull()
{
// Arrange
var requirement = CreateRequirement("Custom", (string[])null);
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("ClaimsAuthorizationRequirement:Claim.Type=Custom", formattedValue);
}
[Fact]
public void ToString_ShouldReturnWithoutAllowedDescriptionWhenAllowedValuesIsEmpty()
{
// Arrange
var requirement = CreateRequirement("Custom", Array.Empty<string>());
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("ClaimsAuthorizationRequirement:Claim.Type=Custom", formattedValue);
}
}
}

View File

@ -8,6 +8,7 @@ using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Xunit;
@ -64,7 +65,8 @@ namespace Microsoft.AspNetCore.Authorization.Test
{
services.AddAuthorization(options =>
{
options.AddPolicy("Basic", policy => {
options.AddPolicy("Basic", policy =>
{
policy.AddAuthenticationSchemes("Basic");
policy.RequireClaim("Permission", "CanViewPage");
});
@ -710,7 +712,8 @@ namespace Microsoft.AspNetCore.Authorization.Test
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PassThroughRequirement requirement)
{
if (Succeed) {
if (Succeed)
{
context.Succeed(requirement);
}
return Task.FromResult(0);
@ -926,7 +929,6 @@ namespace Microsoft.AspNetCore.Authorization.Test
Assert.True((await authorizationService.AuthorizeAsync(user, 2, Operations.Edit)).Succeeded);
}
[Fact]
public async Task DoesNotCallHandlerWithWrongResourceType()
{
@ -1174,5 +1176,104 @@ namespace Microsoft.AspNetCore.Authorization.Test
Assert.False((await authorizationService.AuthorizeAsync(null, "Success")).Succeeded);
}
public class LogRequirement : IAuthorizationRequirement
{
public override string ToString()
{
return "LogRequirement";
}
}
public class DefaultAuthorizationServiceTestLogger : ILogger<DefaultAuthorizationService>
{
private Action<LogLevel, EventId, object, Exception, Func<object, Exception, string>> _assertion;
public DefaultAuthorizationServiceTestLogger(Action<LogLevel, EventId, object, Exception, Func<object, Exception, string>> assertion)
{
_assertion = assertion;
}
public IDisposable BeginScope<TState>(TState state)
{
throw new NotImplementedException();
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
_assertion(logLevel, eventId, state, exception, (s, e) => formatter?.Invoke((TState)s, e));
}
}
[Fact]
public async Task Authorize_ShouldLogRequirementDetailWhenUnHandled()
{
// Arrange
static void Assertion(LogLevel level, EventId eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
Assert.Equal(LogLevel.Information, level);
Assert.Equal(2, eventId.Id);
Assert.Equal("UserAuthorizationFailed", eventId.Name);
var message = formatter(state, exception);
Assert.Equal("Authorization failed for These requirements were not met:" + Environment.NewLine + "LogRequirement" + Environment.NewLine + "LogRequirement", message);
}
var authorizationService = BuildAuthorizationService(services =>
{
services.AddSingleton<ILogger<DefaultAuthorizationService>>(new DefaultAuthorizationServiceTestLogger(Assertion));
services.AddAuthorization(options => options.AddPolicy("Log", p =>
{
p.Requirements.Add(new LogRequirement());
p.Requirements.Add(new LogRequirement());
}));
});
var user = new ClaimsPrincipal();
// Act
var result = await authorizationService.AuthorizeAsync(user, "Log");
// Assert
}
[Fact]
public async Task Authorize_ShouldLogExplicitFailedWhenFailedCall()
{
// Arrange
static void Assertion(LogLevel level, EventId eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
Assert.Equal(LogLevel.Information, level);
Assert.Equal(2, eventId.Id);
Assert.Equal("UserAuthorizationFailed", eventId.Name);
var message = formatter(state, exception);
Assert.Equal("Authorization failed for Fail() was explicitly called.", message);
}
var authorizationService = BuildAuthorizationService(services =>
{
services.AddSingleton<IAuthorizationHandler, FailHandler>();
services.AddSingleton<ILogger<DefaultAuthorizationService>>(new DefaultAuthorizationServiceTestLogger(Assertion));
services.AddAuthorization(options => options.AddPolicy("Log", p =>
{
p.Requirements.Add(new LogRequirement());
p.Requirements.Add(new LogRequirement());
}));
});
var user = new ClaimsPrincipal();
// Act
var result = await authorizationService.AuthorizeAsync(user, "Log");
// Assert
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class DenyAnonymousAuthorizationRequirementTests
{
private DenyAnonymousAuthorizationRequirement CreateRequirement()
{
return new DenyAnonymousAuthorizationRequirement();
}
[Fact]
public void ToString_ShouldReturnFormatValue()
{
// Arrange
var requirement = CreateRequirement();
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("DenyAnonymousAuthorizationRequirement:Requires an authenticated user.", formattedValue);
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class NameAuthorizationRequirementTests
{
public NameAuthorizationRequirement CreateRequirement(string requiredName)
{
return new NameAuthorizationRequirement(requiredName);
}
[Fact]
public void ToString_ShouldReturnFormatValue()
{
// Arrange
var requirement = CreateRequirement("Custom");
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("NameAuthorizationRequirement:Requires a user identity with Name equal to Custom", formattedValue);
}
}
}

View File

@ -0,0 +1,35 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class OperationAuthorizationRequirementTests
{
private OperationAuthorizationRequirement CreateRequirement(string name)
{
return new OperationAuthorizationRequirement()
{
Name = name
};
}
[Fact]
public void ToString_ShouldReturnFormatValue()
{
// Arrange
var requirement = CreateRequirement("Custom");
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("OperationAuthorizationRequirement:Name=Custom", formattedValue);
}
}
}

View File

@ -0,0 +1,45 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class RolesAuthorizationRequirementTests
{
private RolesAuthorizationRequirement CreateRequirement(params string[] allowedRoles)
{
return new RolesAuthorizationRequirement(allowedRoles);
}
[Fact]
public void ToString_ShouldReturnSplitByBarWhenHasTwoAllowedRoles()
{
// Arrange
var requirement = CreateRequirement("Custom1", "Custom2");
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("RolesAuthorizationRequirement:User.IsInRole must be true for one of the following roles: (Custom1|Custom2)", formattedValue);
}
[Fact]
public void ToString_ShouldReturnUnSplitStringWhenOnlyOneAllowedRoles()
{
// Arrange
var requirement = CreateRequirement("Custom1");
// Act
var formattedValue = requirement.ToString();
// Assert
Assert.Equal("RolesAuthorizationRequirement:User.IsInRole must be true for one of the following roles: (Custom1)",formattedValue);
}
}
}