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

View File

@ -28,6 +28,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>());
services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());
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>
public class DefaultAuthorizationService : IAuthorizationService
{
private readonly IAuthorizationHandlerContextFactory _contextFactory;
private readonly IAuthorizationEvaluator _evaluator;
private readonly IAuthorizationPolicyProvider _policyProvider;
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="handlers">The handlers used to fulfill <see cref="IAuthorizationRequirement"/>s.</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>
/// 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="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="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>
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)
{
@ -50,6 +52,10 @@ namespace Microsoft.AspNetCore.Authorization
{
throw new ArgumentNullException(nameof(logger));
}
if (contextFactory == null)
{
throw new ArgumentNullException(nameof(contextFactory));
}
if (evaluator == null)
{
throw new ArgumentNullException(nameof(evaluator));
@ -59,6 +65,7 @@ namespace Microsoft.AspNetCore.Authorization
_policyProvider = policyProvider;
_logger = logger;
_evaluator = evaluator;
_contextFactory = contextFactory;
}
/// <summary>
@ -78,7 +85,7 @@ namespace Microsoft.AspNetCore.Authorization
throw new ArgumentNullException(nameof(requirements));
}
var authContext = new AuthorizationHandlerContext(requirements, user, resource);
var authContext = _contextFactory.CreateContext(requirements, user, resource);
foreach (var handler in _handlers)
{
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 =>
{
// This will ignore the policy options
services.AddSingleton<IAuthorizationEvaluator, SuccessEvaluator>();
services.AddAuthorization(options => options.AddPolicy("Fail", p => p.RequireAssertion(c => false)));
});
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"));
}
}
}