diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs index c92be6232e..f56ea5c19e 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs @@ -27,6 +27,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); + services.TryAdd(ServiceDescriptor.Transient()); services.TryAddEnumerable(ServiceDescriptor.Transient()); return services; } diff --git a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs new file mode 100644 index 0000000000..64cc695b88 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs @@ -0,0 +1,31 @@ +// 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. + +namespace Microsoft.AspNetCore.Authorization +{ + /// + /// Determines whether an authorization request was successful or not. + /// + public class DefaultAuthorizationEvaluator : IAuthorizationEvaluator + { + /// + /// Returns true, if authorization has failed. + /// + /// The authorization information. + /// True if authorization has failed. + public virtual bool HasFailed(AuthorizationHandlerContext context) + { + return context.HasFailed; + } + + /// + /// Returns true, if authorization has succeeded. + /// + /// The authorization information. + /// True if authorization has succeeded. + public virtual bool HasSucceeded(AuthorizationHandlerContext context) + { + return context.HasSucceeded; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs index 6665204eee..45ee4aa4a2 100644 --- a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs +++ b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs @@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Authorization /// public class DefaultAuthorizationService : IAuthorizationService { + private readonly IAuthorizationEvaluator _evaluator; private readonly IAuthorizationPolicyProvider _policyProvider; private readonly IList _handlers; private readonly ILogger _logger; @@ -26,7 +27,16 @@ namespace Microsoft.AspNetCore.Authorization /// The used to provide policies. /// The handlers used to fulfill s. /// The logger used to log messages, warnings and errors. - public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable handlers, ILogger logger) + public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable handlers, ILogger logger) : this(policyProvider, handlers, logger, new DefaultAuthorizationEvaluator()) { } + + /// + /// Creates a new instance of . + /// + /// The used to provide policies. + /// The handlers used to fulfill s. + /// The logger used to log messages, warnings and errors. + /// The used to determine if authorzation was successful. + public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable handlers, ILogger logger, IAuthorizationEvaluator evaluator) { if (policyProvider == null) { @@ -40,10 +50,15 @@ namespace Microsoft.AspNetCore.Authorization { throw new ArgumentNullException(nameof(logger)); } + if (evaluator == null) + { + throw new ArgumentNullException(nameof(evaluator)); + } _handlers = handlers.ToArray(); _policyProvider = policyProvider; _logger = logger; + _evaluator = evaluator; } /// @@ -69,7 +84,7 @@ namespace Microsoft.AspNetCore.Authorization await handler.HandleAsync(authContext); } - if (authContext.HasSucceeded) + if (_evaluator.HasSucceeded(authContext)) { _logger.UserAuthorizationSucceeded(GetUserNameForLogging(user)); return true; diff --git a/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs b/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs new file mode 100644 index 0000000000..7b2c5d1bc5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs @@ -0,0 +1,25 @@ +// 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. + +namespace Microsoft.AspNetCore.Authorization +{ + /// + /// Determines whether an authorization request was successful or not. + /// + public interface IAuthorizationEvaluator + { + /// + /// Returns true, if authorization has failed. + /// + /// The authorization information. + /// True if authorization has failed. + bool HasFailed(AuthorizationHandlerContext context); + + /// + /// Returns true, if authorization has succeeded. + /// + /// The authorization information. + /// True if authorization has succeeded. + bool HasSucceeded(AuthorizationHandlerContext context); + } +} diff --git a/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs index 19bd761e05..749a11dc34 100644 --- a/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs +++ b/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs @@ -1019,5 +1019,30 @@ namespace Microsoft.AspNetCore.Authorization.Test Assert.True(await authorizationService.AuthorizeAsync(user, "2")); Assert.False(await authorizationService.AuthorizeAsync(user, "3")); } + + public class SuccessEvaluator : IAuthorizationEvaluator + { + public bool HasFailed(AuthorizationHandlerContext context) + { + return false; + } + + public bool HasSucceeded(AuthorizationHandlerContext context) + { + return true; + } + } + + [Fact] + public async Task CanUseCustomEvaluatorThatOverridesRequirement() + { + var authorizationService = BuildAuthorizationService(services => + { + // This will ignore the policy options + services.AddSingleton(); + services.AddAuthorization(options => options.AddPolicy("Fail", p => p.RequireAssertion(c => false))); + }); + Assert.True(await authorizationService.AuthorizeAsync(null, "Fail")); + } } } \ No newline at end of file