AuthZ: Combine needs to use policy provider
Fixes https://github.com/aspnet/Security/issues/841
This commit is contained in:
parent
080447e9aa
commit
c257c9528f
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"/>
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue