Add some sugar for AuthZ
- Register passthrough handler by default - AddPolicy overload that takesAction<AuthorizationPolicyBuilder> - Chaining policy overloads/methods - More fluent apis for PolicyBuilder Fixes #122, #114
This commit is contained in:
parent
c53394e847
commit
123065c0ae
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
|
|
@ -15,6 +16,13 @@ namespace Microsoft.AspNet.Security
|
|||
PolicyMap[name] = policy;
|
||||
}
|
||||
|
||||
public void AddPolicy([NotNull] string name, [NotNull] Action<AuthorizationPolicyBuilder> configurePolicy)
|
||||
{
|
||||
var policyBuilder = new AuthorizationPolicyBuilder();
|
||||
configurePolicy(policyBuilder);
|
||||
PolicyMap[name] = policyBuilder.Build();
|
||||
}
|
||||
|
||||
public AuthorizationPolicy GetPolicy([NotNull] string name)
|
||||
{
|
||||
return PolicyMap.ContainsKey(name) ? PolicyMap[name] : null;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
|
|
@ -10,14 +11,42 @@ namespace Microsoft.AspNet.Security
|
|||
{
|
||||
public AuthorizationPolicyBuilder(params string[] activeAuthenticationTypes)
|
||||
{
|
||||
foreach (var authType in activeAuthenticationTypes) {
|
||||
ActiveAuthenticationTypes.Add(authType);
|
||||
}
|
||||
AddAuthenticationTypes(activeAuthenticationTypes);
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder(AuthorizationPolicy policy)
|
||||
{
|
||||
Combine(policy);
|
||||
}
|
||||
|
||||
public IList<IAuthorizationRequirement> Requirements { get; set; } = new List<IAuthorizationRequirement>();
|
||||
public IList<string> ActiveAuthenticationTypes { get; set; } = new List<string>();
|
||||
|
||||
public AuthorizationPolicyBuilder AddAuthenticationTypes(params string[] activeAuthTypes)
|
||||
{
|
||||
foreach (var authType in activeAuthTypes)
|
||||
{
|
||||
ActiveAuthenticationTypes.Add(authType);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder AddRequirements(params IAuthorizationRequirement[] requirements)
|
||||
{
|
||||
foreach (var req in requirements)
|
||||
{
|
||||
Requirements.Add(req);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy)
|
||||
{
|
||||
AddAuthenticationTypes(policy.ActiveAuthenticationTypes.ToArray());
|
||||
AddRequirements(policy.Requirements.ToArray());
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder RequiresClaim([NotNull] string claimType, params string[] requiredValues)
|
||||
{
|
||||
Requirements.Add(new ClaimsAuthorizationRequirement
|
||||
|
|
@ -55,4 +84,4 @@ namespace Microsoft.AspNet.Security
|
|||
return new AuthorizationPolicy(Requirements, ActiveAuthenticationTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
services.TryAdd(describe.Transient<IAuthorizationService, DefaultAuthorizationService>());
|
||||
services.Add(describe.Transient<IAuthorizationHandler, ClaimsAuthorizationHandler>());
|
||||
services.Add(describe.Transient<IAuthorizationHandler, DenyAnonymousAuthorizationHandler>());
|
||||
services.Add(describe.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());
|
||||
if (configureOptions != null)
|
||||
{
|
||||
services.Configure(configureOptions);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNet.Http;
|
|||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Fallback;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -53,11 +52,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("Basic", new AuthorizationPolicyBuilder()
|
||||
.RequiresClaim("Permission", "CanViewPage")
|
||||
.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
|
||||
|
|
@ -75,10 +72,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder("Basic").RequiresClaim("Permission", "CanViewPage");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
|
||||
|
|
@ -96,10 +92,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage", "CanViewAnything");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage", "CanViewAnything"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -124,10 +119,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage", "CanViewAnything");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage", "CanViewAnything"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -151,10 +145,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage", "CanViewAnything");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage", "CanViewAnything"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -178,10 +171,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -205,10 +197,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -230,10 +221,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
|
|
@ -252,10 +242,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder("Basic").RequiresClaim("Permission", "CanViewPage");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity());
|
||||
|
|
@ -273,10 +262,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -433,13 +421,11 @@ namespace Microsoft.AspNet.Security.Test
|
|||
public async Task RolePolicyCanBlockNoRole()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresRole("Admin", "Users");
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => policy.RequiresRole("Admin", "Users"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -462,10 +448,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder();
|
||||
options.AddPolicy("Basic", policy.Build());
|
||||
options.AddPolicy("Basic", policy => { });
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -489,10 +474,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser();
|
||||
options.AddPolicy("Any", policy.Build());
|
||||
options.AddPolicy("Any", policy => policy.RequireAuthenticatedUser());
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
|
|
@ -516,10 +500,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser();
|
||||
options.AddPolicy("Any", policy.Build());
|
||||
options.AddPolicy("Any", policy => policy.RequireAuthenticatedUser());
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity());
|
||||
|
|
@ -546,11 +529,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder();
|
||||
policy.Requirements.Add(new CustomRequirement());
|
||||
options.AddPolicy("Custom", policy.Build());
|
||||
options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
|
|
@ -562,7 +543,6 @@ namespace Microsoft.AspNet.Security.Test
|
|||
Assert.False(allowed);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task CustomReqWithHandlerSucceeds()
|
||||
{
|
||||
|
|
@ -570,11 +550,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.AddTransient<IAuthorizationHandler, CustomHandler>();
|
||||
services.Configure<AuthorizationOptions>(options =>
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var policy = new AuthorizationPolicyBuilder();
|
||||
policy.Requirements.Add(new CustomRequirement());
|
||||
options.AddPolicy("Custom", policy.Build());
|
||||
options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
|
|
@ -586,5 +564,120 @@ namespace Microsoft.AspNet.Security.Test
|
|||
Assert.True(allowed);
|
||||
}
|
||||
|
||||
public class PassThroughRequirement : AuthorizationHandler<PassThroughRequirement>, IAuthorizationRequirement
|
||||
{
|
||||
public PassThroughRequirement(bool succeed)
|
||||
{
|
||||
Succeed = succeed;
|
||||
}
|
||||
|
||||
public bool Succeed { get; set; }
|
||||
|
||||
public override Task<bool> CheckAsync(AuthorizationContext context, PassThroughRequirement requirement)
|
||||
{
|
||||
return Task.FromResult(Succeed);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task PassThroughRequirementWillSucceedWithoutCustomHandler(bool shouldSucceed)
|
||||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("Passthrough", policy => policy.Requirements.Add(new PassThroughRequirement(shouldSucceed)));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Passthrough", context.Object);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(shouldSucceed, allowed);
|
||||
}
|
||||
|
||||
public async Task CanCombinePolicies()
|
||||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var basePolicy = new AuthorizationPolicyBuilder().RequiresClaim("Base", "Value").Build();
|
||||
options.AddPolicy("Combineed", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Base", "Value"),
|
||||
new Claim("Claim", "Exists")
|
||||
},
|
||||
"AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Combined", context.Object);
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
}
|
||||
|
||||
public async Task CombinePoliciesWillFailIfBasePolicyFails()
|
||||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var basePolicy = new AuthorizationPolicyBuilder().RequiresClaim("Base", "Value").Build();
|
||||
options.AddPolicy("Combined", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Claim", "Exists")
|
||||
},
|
||||
"AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Combined", context.Object);
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
}
|
||||
|
||||
public async Task CombinedPoliciesWillFailIfExtraRequirementFails()
|
||||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var basePolicy = new AuthorizationPolicyBuilder().RequiresClaim("Base", "Value").Build();
|
||||
options.AddPolicy("Combined", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Base", "Value"),
|
||||
},
|
||||
"AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Combined", context.Object);
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue