AuthZ: Combine needs to use policy provider

Fixes https://github.com/aspnet/Security/issues/841
This commit is contained in:
Hao Kung 2016-05-31 13:45:30 -07:00
parent 080447e9aa
commit c257c9528f
5 changed files with 61 additions and 24 deletions

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authorization namespace Microsoft.AspNetCore.Authorization
{ {
@ -57,27 +58,27 @@ namespace Microsoft.AspNetCore.Authorization
return builder.Build(); return builder.Build();
} }
public static AuthorizationPolicy Combine(AuthorizationOptions options, IEnumerable<IAuthorizeData> attributes) public static async Task<AuthorizationPolicy> CombineAsync(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizeData> authorizeData)
{ {
if (options == null) if (policyProvider == null)
{ {
throw new ArgumentNullException(nameof(options)); throw new ArgumentNullException(nameof(policyProvider));
} }
if (attributes == null) if (authorizeData == null)
{ {
throw new ArgumentNullException(nameof(attributes)); throw new ArgumentNullException(nameof(authorizeData));
} }
var policyBuilder = new AuthorizationPolicyBuilder(); var policyBuilder = new AuthorizationPolicyBuilder();
var any = false; var any = false;
foreach (var authorizeAttribute in attributes.OfType<AuthorizeAttribute>()) foreach (var authorizeAttribute in authorizeData.OfType<AuthorizeAttribute>())
{ {
any = true; any = true;
var useDefaultPolicy = true; var useDefaultPolicy = true;
if (!string.IsNullOrWhiteSpace(authorizeAttribute.Policy)) if (!string.IsNullOrWhiteSpace(authorizeAttribute.Policy))
{ {
var policy = options.GetPolicy(authorizeAttribute.Policy); var policy = await policyProvider.GetPolicyAsync(authorizeAttribute.Policy);
if (policy == null) if (policy == null)
{ {
throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeAttribute.Policy)); throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeAttribute.Policy));
@ -89,7 +90,6 @@ namespace Microsoft.AspNetCore.Authorization
if (rolesSplit != null && rolesSplit.Any()) if (rolesSplit != null && rolesSplit.Any())
{ {
var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim()); var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());
policyBuilder.RequireRole(trimmedRolesSplit); policyBuilder.RequireRole(trimmedRolesSplit);
useDefaultPolicy = false; useDefaultPolicy = false;
} }
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Authorization
} }
if (useDefaultPolicy) if (useDefaultPolicy)
{ {
policyBuilder.Combine(options.DefaultPolicy); policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());
} }
} }
return any ? policyBuilder.Build() : null; return any ? policyBuilder.Build() : null;

View File

@ -22,7 +22,12 @@ namespace Microsoft.AspNetCore.Authorization
} }
_options = options.Value; _options = options.Value;
} }
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult(_options.DefaultPolicy);
}
/// <summary> /// <summary>
/// Gets a <see cref="AuthorizationPolicy"/> from the given <paramref name="policyName"/> /// Gets a <see cref="AuthorizationPolicy"/> from the given <paramref name="policyName"/>

View File

@ -16,5 +16,11 @@ namespace Microsoft.AspNetCore.Authorization
/// <param name="policyName"></param> /// <param name="policyName"></param>
/// <returns></returns> /// <returns></returns>
Task<AuthorizationPolicy> GetPolicyAsync(string policyName); Task<AuthorizationPolicy> GetPolicyAsync(string policyName);
/// <summary>
/// Returns the default <see cref="AuthorizationPolicy"/>.
/// </summary>
/// <returns></returns>
Task<AuthorizationPolicy> GetDefaultPolicyAsync();
} }
} }

View File

@ -3,8 +3,10 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure; using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.Extensions.Options;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Authroization.Test namespace Microsoft.AspNetCore.Authroization.Test
@ -18,7 +20,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
} }
[Fact] [Fact]
public void CanCombineAuthorizeAttributes() public async Task CanCombineAuthorizeAttributes()
{ {
// Arrange // Arrange
var attributes = new AuthorizeAttribute[] { var attributes = new AuthorizeAttribute[] {
@ -31,8 +33,10 @@ namespace Microsoft.AspNetCore.Authroization.Test
options.AddPolicy("1", policy => policy.RequireClaim("1")); options.AddPolicy("1", policy => policy.RequireClaim("1"));
options.AddPolicy("2", policy => policy.RequireClaim("2")); options.AddPolicy("2", policy => policy.RequireClaim("2"));
var provider = new DefaultAuthorizationPolicyProvider(Options.Create(options));
// Act // Act
var combined = AuthorizationPolicy.Combine(options, attributes); var combined = await AuthorizationPolicy.CombineAsync(provider, attributes);
// Assert // Assert
Assert.Equal(2, combined.AuthenticationSchemes.Count()); Assert.Equal(2, combined.AuthenticationSchemes.Count());
@ -45,7 +49,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
} }
[Fact] [Fact]
public void CanReplaceDefaultPolicy() public async Task CanReplaceDefaultPolicy()
{ {
// Arrange // Arrange
var attributes = new AuthorizeAttribute[] { var attributes = new AuthorizeAttribute[] {
@ -56,8 +60,10 @@ namespace Microsoft.AspNetCore.Authroization.Test
options.DefaultPolicy = new AuthorizationPolicyBuilder("default").RequireClaim("default").Build(); options.DefaultPolicy = new AuthorizationPolicyBuilder("default").RequireClaim("default").Build();
options.AddPolicy("2", policy => policy.RequireClaim("2")); options.AddPolicy("2", policy => policy.RequireClaim("2"));
var provider = new DefaultAuthorizationPolicyProvider(Options.Create(options));
// Act // Act
var combined = AuthorizationPolicy.Combine(options, attributes); var combined = await AuthorizationPolicy.CombineAsync(provider, attributes);
// Assert // Assert
Assert.Equal(2, combined.AuthenticationSchemes.Count()); Assert.Equal(2, combined.AuthenticationSchemes.Count());
@ -69,16 +75,17 @@ namespace Microsoft.AspNetCore.Authroization.Test
} }
[Fact] [Fact]
public void CombineMustTrimRoles() public async Task CombineMustTrimRoles()
{ {
// Arrange // Arrange
var attributes = new AuthorizeAttribute[] { var attributes = new AuthorizeAttribute[] {
new AuthorizeAttribute() { Roles = "r1 , r2" } new AuthorizeAttribute() { Roles = "r1 , r2" }
}; };
var options = new AuthorizationOptions(); var options = new AuthorizationOptions();
var provider = new DefaultAuthorizationPolicyProvider(Options.Create(options));
// Act // Act
var combined = AuthorizationPolicy.Combine(options, attributes); var combined = await AuthorizationPolicy.CombineAsync(provider, attributes);
// Assert // Assert
Assert.True(combined.Requirements.Any(r => r is RolesAuthorizationRequirement)); Assert.True(combined.Requirements.Any(r => r is RolesAuthorizationRequirement));
@ -89,7 +96,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
} }
[Fact] [Fact]
public void CombineMustTrimAuthenticationScheme() public async Task CombineMustTrimAuthenticationScheme()
{ {
// Arrange // Arrange
var attributes = new AuthorizeAttribute[] { var attributes = new AuthorizeAttribute[] {
@ -97,8 +104,10 @@ namespace Microsoft.AspNetCore.Authroization.Test
}; };
var options = new AuthorizationOptions(); var options = new AuthorizationOptions();
var provider = new DefaultAuthorizationPolicyProvider(Options.Create(options));
// Act // Act
var combined = AuthorizationPolicy.Combine(options, attributes); var combined = await AuthorizationPolicy.CombineAsync(provider, attributes);
// Assert // Assert
Assert.Equal(2, combined.AuthenticationSchemes.Count()); Assert.Equal(2, combined.AuthenticationSchemes.Count());
@ -107,7 +116,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
} }
[Fact] [Fact]
public void CombineMustIgnoreEmptyAuthenticationScheme() public async Task CombineMustIgnoreEmptyAuthenticationScheme()
{ {
// Arrange // Arrange
var attributes = new AuthorizeAttribute[] { var attributes = new AuthorizeAttribute[] {
@ -115,8 +124,10 @@ namespace Microsoft.AspNetCore.Authroization.Test
}; };
var options = new AuthorizationOptions(); var options = new AuthorizationOptions();
var provider = new DefaultAuthorizationPolicyProvider(Options.Create(options));
// Act // Act
var combined = AuthorizationPolicy.Combine(options, attributes); var combined = await AuthorizationPolicy.CombineAsync(provider, attributes);
// Assert // Assert
Assert.Equal(2, combined.AuthenticationSchemes.Count()); Assert.Equal(2, combined.AuthenticationSchemes.Count());
@ -125,16 +136,17 @@ namespace Microsoft.AspNetCore.Authroization.Test
} }
[Fact] [Fact]
public void CombineMustIgnoreEmptyRoles() public async Task CombineMustIgnoreEmptyRoles()
{ {
// Arrange // Arrange
var attributes = new AuthorizeAttribute[] { var attributes = new AuthorizeAttribute[] {
new AuthorizeAttribute() { Roles = "r1 , ,, , r2" } new AuthorizeAttribute() { Roles = "r1 , ,, , r2" }
}; };
var options = new AuthorizationOptions(); var options = new AuthorizationOptions();
var provider = new DefaultAuthorizationPolicyProvider(Options.Create(options));
// Act // Act
var combined = AuthorizationPolicy.Combine(options, attributes); var combined = await AuthorizationPolicy.CombineAsync(provider, attributes);
// Assert // Assert
Assert.True(combined.Requirements.Any(r => r is RolesAuthorizationRequirement)); Assert.True(combined.Requirements.Any(r => r is RolesAuthorizationRequirement));

View File

@ -8,6 +8,7 @@ using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization.Infrastructure; using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test namespace Microsoft.AspNetCore.Authorization.Test
@ -28,9 +29,12 @@ namespace Microsoft.AspNetCore.Authorization.Test
} }
[Fact] [Fact]
public void AuthorizeCombineThrowsOnUnknownPolicy() public async Task AuthorizeCombineThrowsOnUnknownPolicy()
{ {
Assert.Throws<InvalidOperationException>(() => AuthorizationPolicy.Combine(new AuthorizationOptions(), new AuthorizeAttribute[] { var provider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions()));
// Act
await Assert.ThrowsAsync<InvalidOperationException>(() => AuthorizationPolicy.CombineAsync(provider, new AuthorizeAttribute[] {
new AuthorizeAttribute { Policy = "Wut" } new AuthorizeAttribute { Policy = "Wut" }
})); }));
} }
@ -944,6 +948,11 @@ namespace Microsoft.AspNetCore.Authorization.Test
public class StaticPolicyProvider : IAuthorizationPolicyProvider public class StaticPolicyProvider : IAuthorizationPolicyProvider
{ {
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{ {
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
@ -973,6 +982,11 @@ namespace Microsoft.AspNetCore.Authorization.Test
public class DynamicPolicyProvider : IAuthorizationPolicyProvider public class DynamicPolicyProvider : IAuthorizationPolicyProvider
{ {
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{ {
return Task.FromResult(new AuthorizationPolicyBuilder().RequireClaim(policyName).Build()); return Task.FromResult(new AuthorizationPolicyBuilder().RequireClaim(policyName).Build());