AuthPolicy should use IPolicyProvider
This commit is contained in:
parent
e63f094a5f
commit
c7a46e4caf
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -29,14 +30,44 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(policy));
|
throw new ArgumentNullException(nameof(policy));
|
||||||
}
|
}
|
||||||
|
|
||||||
Policy = policy;
|
Policy = policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the authorization policy to be used.
|
/// Initialize a new <see cref="AuthorizeFilter"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AuthorizationPolicy Policy { get; }
|
/// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/> to use to resolve policy names.</param>
|
||||||
|
/// <param name="authorizeData">The <see cref="IAuthorizeData"/> to combine into an <see cref="IAuthorizeData"/>.</param>
|
||||||
|
public AuthorizeFilter(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizeData> authorizeData)
|
||||||
|
{
|
||||||
|
if (policyProvider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(policyProvider));
|
||||||
|
}
|
||||||
|
if (authorizeData == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(authorizeData));
|
||||||
|
}
|
||||||
|
|
||||||
|
PolicyProvider = policyProvider;
|
||||||
|
AuthorizeData = authorizeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IAuthorizationPolicyProvider"/> to use to resolve policy names.
|
||||||
|
/// </summary>
|
||||||
|
public IAuthorizationPolicyProvider PolicyProvider { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IAuthorizeData"/> to combine into an <see cref="IAuthorizeData"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<IAuthorizeData> AuthorizeData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the authorization policy to be used. If null, the policy will be constructed via
|
||||||
|
/// AuthorizePolicy.CombineAsync(PolicyProvider, AuthorizeData)
|
||||||
|
/// </summary>
|
||||||
|
public AuthorizationPolicy Policy { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||||
|
|
@ -46,11 +77,17 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var effectivePolicy = Policy ?? await AuthorizationPolicy.CombineAsync(PolicyProvider, AuthorizeData);
|
||||||
|
if (effectivePolicy == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Build a ClaimsPrincipal with the Policy's required authentication types
|
// Build a ClaimsPrincipal with the Policy's required authentication types
|
||||||
if (Policy.AuthenticationSchemes != null && Policy.AuthenticationSchemes.Any())
|
if (effectivePolicy.AuthenticationSchemes != null && effectivePolicy.AuthenticationSchemes.Any())
|
||||||
{
|
{
|
||||||
ClaimsPrincipal newPrincipal = null;
|
ClaimsPrincipal newPrincipal = null;
|
||||||
foreach (var scheme in Policy.AuthenticationSchemes)
|
foreach (var scheme in effectivePolicy.AuthenticationSchemes)
|
||||||
{
|
{
|
||||||
var result = await context.HttpContext.Authentication.AuthenticateAsync(scheme);
|
var result = await context.HttpContext.Authentication.AuthenticateAsync(scheme);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
|
|
@ -76,9 +113,9 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
var authService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>();
|
var authService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>();
|
||||||
|
|
||||||
// Note: Default Anonymous User is new ClaimsPrincipal(new ClaimsIdentity())
|
// Note: Default Anonymous User is new ClaimsPrincipal(new ClaimsIdentity())
|
||||||
if (!await authService.AuthorizeAsync(httpContext.User, context, Policy))
|
if (!await authService.AuthorizeAsync(httpContext.User, context, effectivePolicy))
|
||||||
{
|
{
|
||||||
context.Result = new ChallengeResult(Policy.AuthenticationSchemes.ToArray());
|
context.Result = new ChallengeResult(effectivePolicy.AuthenticationSchemes.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,22 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Internal
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
public class AuthorizationApplicationModelProvider : IApplicationModelProvider
|
public class AuthorizationApplicationModelProvider : IApplicationModelProvider
|
||||||
{
|
{
|
||||||
private readonly AuthorizationOptions _authorizationOptions;
|
private readonly IAuthorizationPolicyProvider _policyProvider;
|
||||||
|
|
||||||
public AuthorizationApplicationModelProvider(IOptions<AuthorizationOptions> authorizationOptionsAccessor)
|
public AuthorizationApplicationModelProvider(IAuthorizationPolicyProvider policyProvider)
|
||||||
{
|
{
|
||||||
_authorizationOptions = authorizationOptionsAccessor.Value;
|
_policyProvider = policyProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order { get { return -1000 + 10; } }
|
public int Order { get { return -1000 + 10; } }
|
||||||
|
|
@ -33,18 +34,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthorizationPolicy policy;
|
|
||||||
|
|
||||||
foreach (var controllerModel in context.Result.Controllers)
|
foreach (var controllerModel in context.Result.Controllers)
|
||||||
{
|
{
|
||||||
policy = AuthorizationPolicy.Combine(
|
controllerModel.Filters.Add(new AuthorizeFilter(_policyProvider, controllerModel.Attributes.OfType<IAuthorizeData>()));
|
||||||
_authorizationOptions,
|
|
||||||
controllerModel.Attributes.OfType<IAuthorizeData>());
|
|
||||||
if (policy != null)
|
|
||||||
{
|
|
||||||
controllerModel.Filters.Add(new AuthorizeFilter(policy));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var attribute in controllerModel.Attributes.OfType<IAllowAnonymous>())
|
foreach (var attribute in controllerModel.Attributes.OfType<IAllowAnonymous>())
|
||||||
{
|
{
|
||||||
controllerModel.Filters.Add(new AllowAnonymousFilter());
|
controllerModel.Filters.Add(new AllowAnonymousFilter());
|
||||||
|
|
@ -52,14 +44,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
||||||
foreach (var actionModel in controllerModel.Actions)
|
foreach (var actionModel in controllerModel.Actions)
|
||||||
{
|
{
|
||||||
policy = AuthorizationPolicy.Combine(
|
actionModel.Filters.Add(new AuthorizeFilter(_policyProvider, actionModel.Attributes.OfType<IAuthorizeData>()));
|
||||||
_authorizationOptions,
|
|
||||||
actionModel.Attributes.OfType<IAuthorizeData>());
|
|
||||||
if (policy != null)
|
|
||||||
{
|
|
||||||
actionModel.Filters.Add(new AuthorizeFilter(policy));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var attribute in actionModel.Attributes.OfType<IAllowAnonymous>())
|
foreach (var attribute in actionModel.Attributes.OfType<IAllowAnonymous>())
|
||||||
{
|
{
|
||||||
actionModel.Filters.Add(new AllowAnonymousFilter());
|
actionModel.Filters.Add(new AllowAnonymousFilter());
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,31 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
Assert.Null(authorizationContext.Result);
|
Assert.Null(authorizationContext.Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AuthorizeFilterWillCallPolicyProviderOnAuthorization()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
|
||||||
|
var getPolicyCount = 0;
|
||||||
|
policyProvider.Setup(p => p.GetPolicyAsync(It.IsAny<string>())).ReturnsAsync(new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build())
|
||||||
|
.Callback(() => getPolicyCount++);
|
||||||
|
var authorizeFilter = new AuthorizeFilter(policyProvider.Object, new AuthorizeAttribute[] { new AuthorizeAttribute("whatever") });
|
||||||
|
var authorizationContext = GetAuthorizationContext(services => services.AddAuthorization());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
Assert.Equal(1, getPolicyCount);
|
||||||
|
Assert.Null(authorizationContext.Result);
|
||||||
|
|
||||||
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
Assert.Equal(2, getPolicyCount);
|
||||||
|
Assert.Null(authorizationContext.Result);
|
||||||
|
|
||||||
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
Assert.Equal(3, getPolicyCount);
|
||||||
|
Assert.Null(authorizationContext.Result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task AuthorizeFilterCanAuthorizeNullUser()
|
public async Task AuthorizeFilterCanAuthorizeNullUser()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
public void CreateControllerModel_AuthorizeAttributeAddsAuthorizeFilter()
|
public void CreateControllerModel_AuthorizeAttributeAddsAuthorizeFilter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new AuthorizationApplicationModelProvider(new TestOptionsManager<AuthorizationOptions>());
|
var provider = new AuthorizationApplicationModelProvider(new DefaultAuthorizationPolicyProvider(new TestOptionsManager<AuthorizationOptions>()));
|
||||||
var defaultProvider = new DefaultApplicationModelProvider(new TestOptionsManager<MvcOptions>());
|
var defaultProvider = new DefaultApplicationModelProvider(new TestOptionsManager<MvcOptions>());
|
||||||
|
|
||||||
var context = new ApplicationModelProviderContext(new[] { typeof(AccountController).GetTypeInfo() });
|
var context = new ApplicationModelProviderContext(new[] { typeof(AccountController).GetTypeInfo() });
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
options.Value.AddPolicy("Base", policy => policy.RequireClaim("Basic").RequireClaim("Basic2"));
|
options.Value.AddPolicy("Base", policy => policy.RequireClaim("Basic").RequireClaim("Basic2"));
|
||||||
options.Value.AddPolicy("Derived", policy => policy.RequireClaim("Derived"));
|
options.Value.AddPolicy("Derived", policy => policy.RequireClaim("Derived"));
|
||||||
|
|
||||||
var provider = new AuthorizationApplicationModelProvider(options);
|
var provider = new AuthorizationApplicationModelProvider(new DefaultAuthorizationPolicyProvider(options));
|
||||||
var defaultProvider = new DefaultApplicationModelProvider(new TestOptionsManager<MvcOptions>());
|
var defaultProvider = new DefaultApplicationModelProvider(new TestOptionsManager<MvcOptions>());
|
||||||
|
|
||||||
var context = new ApplicationModelProviderContext(new[] { typeof(DerivedController).GetTypeInfo() });
|
var context = new ApplicationModelProviderContext(new[] { typeof(DerivedController).GetTypeInfo() });
|
||||||
|
|
@ -56,14 +56,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
Assert.Empty(attributeRoutes);
|
Assert.Empty(attributeRoutes);
|
||||||
var authorizeFilters = action.Filters.OfType<AuthorizeFilter>();
|
var authorizeFilters = action.Filters.OfType<AuthorizeFilter>();
|
||||||
Assert.Single(authorizeFilters);
|
Assert.Single(authorizeFilters);
|
||||||
Assert.Equal(3, authorizeFilters.First().Policy.Requirements.Count);
|
|
||||||
|
Assert.NotNull(authorizeFilters.First().PolicyProvider);
|
||||||
|
Assert.Equal(3, authorizeFilters.First().AuthorizeData.Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CreateControllerModelAndActionModel_AllowAnonymousAttributeAddsAllowAnonymousFilter()
|
public void CreateControllerModelAndActionModel_AllowAnonymousAttributeAddsAllowAnonymousFilter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new AuthorizationApplicationModelProvider(new TestOptionsManager<AuthorizationOptions>());
|
var provider = new AuthorizationApplicationModelProvider(new DefaultAuthorizationPolicyProvider(new TestOptionsManager<AuthorizationOptions>()));
|
||||||
var defaultProvider = new DefaultApplicationModelProvider(new TestOptionsManager<MvcOptions>());
|
var defaultProvider = new DefaultApplicationModelProvider(new TestOptionsManager<MvcOptions>());
|
||||||
|
|
||||||
var context = new ApplicationModelProviderContext(new[] { typeof(AnonymousController).GetTypeInfo() });
|
var context = new ApplicationModelProviderContext(new[] { typeof(AnonymousController).GetTypeInfo() });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue