Add AuthZHandlerContextFactory

This commit is contained in:
Hao Kung 2016-08-02 17:55:10 -07:00
parent 6f15d616a8
commit d291bb7c24
6 changed files with 116 additions and 12 deletions

View File

@ -42,32 +42,32 @@ namespace Microsoft.AspNetCore.Authorization
/// <summary> /// <summary>
/// The collection of all the <see cref="IAuthorizationRequirement"/> for the current authorization action. /// The collection of all the <see cref="IAuthorizationRequirement"/> for the current authorization action.
/// </summary> /// </summary>
public IEnumerable<IAuthorizationRequirement> Requirements { get; } public virtual IEnumerable<IAuthorizationRequirement> Requirements { get; }
/// <summary> /// <summary>
/// The <see cref="ClaimsPrincipal"/> representing the current user. /// The <see cref="ClaimsPrincipal"/> representing the current user.
/// </summary> /// </summary>
public ClaimsPrincipal User { get; } public virtual ClaimsPrincipal User { get; }
/// <summary> /// <summary>
/// The optional resource to evaluate the <see cref="AuthorizationHandlerContext.Requirements"/> against. /// The optional resource to evaluate the <see cref="AuthorizationHandlerContext.Requirements"/> against.
/// </summary> /// </summary>
public object Resource { get; } public virtual object Resource { get; }
/// <summary> /// <summary>
/// Gets the requirements that have not yet been marked as succeeded. /// Gets the requirements that have not yet been marked as succeeded.
/// </summary> /// </summary>
public IEnumerable<IAuthorizationRequirement> PendingRequirements { get { return _pendingRequirements; } } public virtual IEnumerable<IAuthorizationRequirement> PendingRequirements { get { return _pendingRequirements; } }
/// <summary> /// <summary>
/// Flag indicating whether the current authorization processing has failed. /// Flag indicating whether the current authorization processing has failed.
/// </summary> /// </summary>
public bool HasFailed { get { return _failCalled; } } public virtual bool HasFailed { get { return _failCalled; } }
/// <summary> /// <summary>
/// Flag indicating whether the current authorization processing has succeeded. /// Flag indicating whether the current authorization processing has succeeded.
/// </summary> /// </summary>
public bool HasSucceeded public virtual bool HasSucceeded
{ {
get get
{ {
@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Authorization
/// Called to indicate <see cref="AuthorizationHandlerContext.HasSucceeded"/> will /// Called to indicate <see cref="AuthorizationHandlerContext.HasSucceeded"/> will
/// never return true, even if all requirements are met. /// never return true, even if all requirements are met.
/// </summary> /// </summary>
public void Fail() public virtual void Fail()
{ {
_failCalled = true; _failCalled = true;
} }
@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Authorization
/// successfully evaluated. /// successfully evaluated.
/// </summary> /// </summary>
/// <param name="requirement">The requirement whose evaluation has succeeded.</param> /// <param name="requirement">The requirement whose evaluation has succeeded.</param>
public void Succeed(IAuthorizationRequirement requirement) public virtual void Succeed(IAuthorizationRequirement requirement)
{ {
_succeedCalled = true; _succeedCalled = true;
_pendingRequirements.Remove(requirement); _pendingRequirements.Remove(requirement);

View File

@ -28,6 +28,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>());
services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>()); services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());
return services; return services;
} }

View File

@ -0,0 +1,29 @@
// 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.Collections.Generic;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// A type used to provide a <see cref="AuthorizationHandlerContext"/> used for authorization.
/// </summary>
public class DefaultAuthorizationHandlerContextFactory : IAuthorizationHandlerContextFactory
{
/// <summary>
/// Creates a <see cref="AuthorizationHandlerContext"/> used for authorization.
/// </summary>
/// <param name="requirements">The requirements to evaluate.</param>
/// <param name="user">The user to evaluate the requirements against.</param>
/// <param name="resource">
/// An optional resource the policy should be checked with.
/// If a resource is not required for policy evaluation you may pass null as the value.
/// </param>
/// <returns>The <see cref="AuthorizationHandlerContext"/>.</returns>
public virtual AuthorizationHandlerContext CreateContext(IEnumerable<IAuthorizationRequirement> requirements, ClaimsPrincipal user, object resource)
{
return new AuthorizationHandlerContext(requirements, user, resource);
}
}
}

View File

@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Authorization
/// </summary> /// </summary>
public class DefaultAuthorizationService : IAuthorizationService public class DefaultAuthorizationService : IAuthorizationService
{ {
private readonly IAuthorizationHandlerContextFactory _contextFactory;
private readonly IAuthorizationEvaluator _evaluator; private readonly IAuthorizationEvaluator _evaluator;
private readonly IAuthorizationPolicyProvider _policyProvider; private readonly IAuthorizationPolicyProvider _policyProvider;
private readonly IList<IAuthorizationHandler> _handlers; private readonly IList<IAuthorizationHandler> _handlers;
@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.Authorization
/// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/> used to provide policies.</param> /// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/> used to provide policies.</param>
/// <param name="handlers">The handlers used to fulfill <see cref="IAuthorizationRequirement"/>s.</param> /// <param name="handlers">The handlers used to fulfill <see cref="IAuthorizationRequirement"/>s.</param>
/// <param name="logger">The logger used to log messages, warnings and errors.</param> /// <param name="logger">The logger used to log messages, warnings and errors.</param>
public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizationHandler> handlers, ILogger<DefaultAuthorizationService> logger) : this(policyProvider, handlers, logger, new DefaultAuthorizationEvaluator()) { } public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizationHandler> handlers, ILogger<DefaultAuthorizationService> logger) : this(policyProvider, handlers, logger, new DefaultAuthorizationHandlerContextFactory(), new DefaultAuthorizationEvaluator()) { }
/// <summary> /// <summary>
/// Creates a new instance of <see cref="DefaultAuthorizationService"/>. /// Creates a new instance of <see cref="DefaultAuthorizationService"/>.
@ -35,8 +36,9 @@ namespace Microsoft.AspNetCore.Authorization
/// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/> used to provide policies.</param> /// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/> used to provide policies.</param>
/// <param name="handlers">The handlers used to fulfill <see cref="IAuthorizationRequirement"/>s.</param> /// <param name="handlers">The handlers used to fulfill <see cref="IAuthorizationRequirement"/>s.</param>
/// <param name="logger">The logger used to log messages, warnings and errors.</param> /// <param name="logger">The logger used to log messages, warnings and errors.</param>
/// <param name="contextFactory">The <see cref="IAuthorizationHandlerContextFactory"/> used to create the context to handle the authorization.</param>
/// <param name="evaluator">The <see cref="IAuthorizationEvaluator"/> used to determine if authorzation was successful.</param> /// <param name="evaluator">The <see cref="IAuthorizationEvaluator"/> used to determine if authorzation was successful.</param>
public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizationHandler> handlers, ILogger<DefaultAuthorizationService> logger, IAuthorizationEvaluator evaluator) public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizationHandler> handlers, ILogger<DefaultAuthorizationService> logger, IAuthorizationHandlerContextFactory contextFactory, IAuthorizationEvaluator evaluator)
{ {
if (policyProvider == null) if (policyProvider == null)
{ {
@ -50,6 +52,10 @@ namespace Microsoft.AspNetCore.Authorization
{ {
throw new ArgumentNullException(nameof(logger)); throw new ArgumentNullException(nameof(logger));
} }
if (contextFactory == null)
{
throw new ArgumentNullException(nameof(contextFactory));
}
if (evaluator == null) if (evaluator == null)
{ {
throw new ArgumentNullException(nameof(evaluator)); throw new ArgumentNullException(nameof(evaluator));
@ -59,6 +65,7 @@ namespace Microsoft.AspNetCore.Authorization
_policyProvider = policyProvider; _policyProvider = policyProvider;
_logger = logger; _logger = logger;
_evaluator = evaluator; _evaluator = evaluator;
_contextFactory = contextFactory;
} }
/// <summary> /// <summary>
@ -78,7 +85,7 @@ namespace Microsoft.AspNetCore.Authorization
throw new ArgumentNullException(nameof(requirements)); throw new ArgumentNullException(nameof(requirements));
} }
var authContext = new AuthorizationHandlerContext(requirements, user, resource); var authContext = _contextFactory.CreateContext(requirements, user, resource);
foreach (var handler in _handlers) foreach (var handler in _handlers)
{ {
await handler.HandleAsync(authContext); await handler.HandleAsync(authContext);

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.Collections.Generic;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// A type used to provide a <see cref="AuthorizationHandlerContext"/> used for authorization.
/// </summary>
public interface IAuthorizationHandlerContextFactory
{
/// <summary>
/// Creates a <see cref="AuthorizationHandlerContext"/> used for authorization.
/// </summary>
/// <param name="requirements">The requirements to evaluate.</param>
/// <param name="user">The user to evaluate the requirements against.</param>
/// <param name="resource">
/// An optional resource the policy should be checked with.
/// If a resource is not required for policy evaluation you may pass null as the value.
/// </param>
/// <returns>The <see cref="AuthorizationHandlerContext"/>.</returns>
AuthorizationHandlerContext CreateContext(IEnumerable<IAuthorizationRequirement> requirements, ClaimsPrincipal user, object resource);
}
}

View File

@ -1038,11 +1038,52 @@ namespace Microsoft.AspNetCore.Authorization.Test
{ {
var authorizationService = BuildAuthorizationService(services => var authorizationService = BuildAuthorizationService(services =>
{ {
// This will ignore the policy options
services.AddSingleton<IAuthorizationEvaluator, SuccessEvaluator>(); services.AddSingleton<IAuthorizationEvaluator, SuccessEvaluator>();
services.AddAuthorization(options => options.AddPolicy("Fail", p => p.RequireAssertion(c => false))); services.AddAuthorization(options => options.AddPolicy("Fail", p => p.RequireAssertion(c => false)));
}); });
Assert.True(await authorizationService.AuthorizeAsync(null, "Fail")); Assert.True(await authorizationService.AuthorizeAsync(null, "Fail"));
} }
public class BadContextMaker : IAuthorizationHandlerContextFactory
{
public AuthorizationHandlerContext CreateContext(IEnumerable<IAuthorizationRequirement> requirements, ClaimsPrincipal user, object resource)
{
return new BadContext();
}
}
public class BadContext : AuthorizationHandlerContext
{
public BadContext() : base(new List<IAuthorizationRequirement>(), null, null) { }
public override bool HasFailed
{
get
{
return true;
}
}
public override bool HasSucceeded
{
get
{
return false;
}
}
}
[Fact]
public async Task CanUseCustomContextThatAlwaysFails()
{
var authorizationService = BuildAuthorizationService(services =>
{
services.AddSingleton<IAuthorizationHandlerContextFactory, BadContextMaker>();
services.AddAuthorization(options => options.AddPolicy("Success", p => p.RequireAssertion(c => true)));
});
Assert.False(await authorizationService.AuthorizeAsync(null, "Success"));
}
} }
} }