Latest AuthZ iteration
- Core Auth API now takes list of IAuthorizationRequirements, or policy name. - Overload that takes AuthorizationPolicy instance moved to extension method. - Remove HttpContext from API and replace with ClaimsPrincipal instead - Add Operation requirement - Add Sync overloads - Add ClaimsTransformationOptions (TBD where to use this) Fixes https://github.com/aspnet/Security/issues/132 Fixes https://github.com/aspnet/Security/issues/116 Fixes https://github.com/aspnet/Security/issues/11 Fixes https://github.com/aspnet/Security/issues/117
This commit is contained in:
parent
58661b2734
commit
5094b85ac9
|
|
@ -4,7 +4,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
|
|
@ -13,27 +12,23 @@ namespace Microsoft.AspNet.Security
|
|||
/// </summary>
|
||||
public class AuthorizationContext
|
||||
{
|
||||
private HashSet<IAuthorizationRequirement> _pendingRequirements = new HashSet<IAuthorizationRequirement>();
|
||||
private HashSet<IAuthorizationRequirement> _pendingRequirements;
|
||||
private bool _failCalled;
|
||||
private bool _succeedCalled;
|
||||
|
||||
public AuthorizationContext(
|
||||
[NotNull] AuthorizationPolicy policy,
|
||||
HttpContext context,
|
||||
[NotNull] IEnumerable<IAuthorizationRequirement> requirements,
|
||||
ClaimsPrincipal user,
|
||||
object resource)
|
||||
{
|
||||
Policy = policy;
|
||||
Context = context;
|
||||
Requirements = requirements;
|
||||
User = user;
|
||||
Resource = resource;
|
||||
foreach (var req in Policy.Requirements)
|
||||
{
|
||||
_pendingRequirements.Add(req);
|
||||
}
|
||||
_pendingRequirements = new HashSet<IAuthorizationRequirement>(requirements);
|
||||
}
|
||||
|
||||
public AuthorizationPolicy Policy { get; private set; }
|
||||
public ClaimsPrincipal User { get { return Context.User; } }
|
||||
public HttpContext Context { get; private set; }
|
||||
public IEnumerable<IAuthorizationRequirement> Requirements { get; private set; }
|
||||
public ClaimsPrincipal User { get; private set; }
|
||||
public object Resource { get; private set; }
|
||||
|
||||
public IEnumerable<IAuthorizationRequirement> PendingRequirements { get { return _pendingRequirements; } }
|
||||
|
|
|
|||
|
|
@ -1,58 +1,68 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
// Music store use case
|
||||
|
||||
// await AuthorizeAsync<Album>(user, "Edit", albumInstance);
|
||||
|
||||
// No policy name needed because this is auto based on resource (operation is the policy name)
|
||||
//RegisterOperation which auto generates the policy for Authorize<T>
|
||||
//bool AuthorizeAsync<TResource>(ClaimsPrincipal, string operation, TResource instance)
|
||||
//bool AuthorizeAsync<TResource>(IAuthorization, ClaimsPrincipal, string operation, TResource instance)
|
||||
public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler
|
||||
where TRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public async Task HandleAsync(AuthorizationContext context)
|
||||
public void Handle(AuthorizationContext context)
|
||||
{
|
||||
foreach (var req in context.Policy.Requirements.OfType<TRequirement>())
|
||||
foreach (var req in context.Requirements.OfType<TRequirement>())
|
||||
{
|
||||
if (await CheckAsync(context, req))
|
||||
Handle(context, req);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Task HandleAsync(AuthorizationContext context)
|
||||
{
|
||||
Handle(context);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
// REVIEW: do we need an async hook too?
|
||||
public abstract void Handle(AuthorizationContext context, TRequirement requirement);
|
||||
}
|
||||
|
||||
public abstract class AuthorizationHandler<TRequirement, TResource> : IAuthorizationHandler
|
||||
where TResource : class
|
||||
where TRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public virtual async Task HandleAsync(AuthorizationContext context)
|
||||
{
|
||||
var resource = context.Resource as TResource;
|
||||
// REVIEW: should we allow null resources?
|
||||
if (resource != null)
|
||||
{
|
||||
foreach (var req in context.Requirements.OfType<TRequirement>())
|
||||
{
|
||||
context.Succeed(req);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
await HandleAsync(context, req, resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Task<bool> CheckAsync(AuthorizationContext context, TRequirement requirement);
|
||||
public virtual Task HandleAsync(AuthorizationContext context, TRequirement requirement, TResource resource)
|
||||
{
|
||||
Handle(context, requirement, resource);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public virtual void Handle(AuthorizationContext context)
|
||||
{
|
||||
var resource = context.Resource as TResource;
|
||||
// REVIEW: should we allow null resources?
|
||||
if (resource != null)
|
||||
{
|
||||
foreach (var req in context.Requirements.OfType<TRequirement>())
|
||||
{
|
||||
Handle(context, req, resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void Handle(AuthorizationContext context, TRequirement requirement, TResource resource);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
//public abstract class AuthorizationHandler<TRequirement, TResource> : AuthorizationHandler<TRequirement>
|
||||
// where TResource : class
|
||||
// where TRequirement : IAuthorizationRequirement
|
||||
//{
|
||||
// public override Task HandleAsync(AuthorizationContext context)
|
||||
// {
|
||||
// var resource = context.Resource as TResource;
|
||||
// if (resource != null)
|
||||
// {
|
||||
// return HandleAsync(context, resource);
|
||||
// }
|
||||
|
||||
// return Task.FromResult(0);
|
||||
|
||||
// }
|
||||
|
||||
// public abstract Task HandleAsync(AuthorizationContext context, TResource resource);
|
||||
//}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
// 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;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
|
|
@ -9,11 +11,67 @@ namespace Microsoft.AspNet.Security
|
|||
{
|
||||
public AuthorizationPolicy(IEnumerable<IAuthorizationRequirement> requirements, IEnumerable<string> activeAuthenticationTypes)
|
||||
{
|
||||
Requirements = requirements;
|
||||
ActiveAuthenticationTypes = activeAuthenticationTypes;
|
||||
Requirements = new List<IAuthorizationRequirement>(requirements).AsReadOnly();
|
||||
ActiveAuthenticationTypes = new List<string>(activeAuthenticationTypes).AsReadOnly();
|
||||
}
|
||||
|
||||
public IEnumerable<IAuthorizationRequirement> Requirements { get; private set; }
|
||||
public IEnumerable<string> ActiveAuthenticationTypes { get; private set; }
|
||||
public IReadOnlyList<IAuthorizationRequirement> Requirements { get; private set; }
|
||||
public IReadOnlyList<string> ActiveAuthenticationTypes { get; private set; }
|
||||
|
||||
public static AuthorizationPolicy Combine([NotNull] params AuthorizationPolicy[] policies)
|
||||
{
|
||||
return Combine((IEnumerable<AuthorizationPolicy>)policies);
|
||||
}
|
||||
|
||||
// TODO: Add unit tests
|
||||
public static AuthorizationPolicy Combine([NotNull] IEnumerable<AuthorizationPolicy> policies)
|
||||
{
|
||||
var builder = new AuthorizationPolicyBuilder();
|
||||
foreach (var policy in policies)
|
||||
{
|
||||
builder.Combine(policy);
|
||||
}
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
public static AuthorizationPolicy Combine([NotNull] AuthorizationOptions options, [NotNull] IEnumerable<AuthorizeAttribute> attributes)
|
||||
{
|
||||
var policyBuilder = new AuthorizationPolicyBuilder();
|
||||
bool any = false;
|
||||
foreach (var authorizeAttribute in attributes.OfType<AuthorizeAttribute>())
|
||||
{
|
||||
any = true;
|
||||
var requireAnyAuthenticated = true;
|
||||
if (!string.IsNullOrWhiteSpace(authorizeAttribute.Policy))
|
||||
{
|
||||
var policy = options.GetPolicy(authorizeAttribute.Policy);
|
||||
if (policy == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeAttribute.Policy));
|
||||
}
|
||||
policyBuilder.Combine(policy);
|
||||
requireAnyAuthenticated = false;
|
||||
}
|
||||
var rolesSplit = authorizeAttribute.Roles?.Split(',');
|
||||
if (rolesSplit != null && rolesSplit.Any())
|
||||
{
|
||||
policyBuilder.RequiresRole(rolesSplit);
|
||||
requireAnyAuthenticated = false;
|
||||
}
|
||||
string[] authTypesSplit = authorizeAttribute.ActiveAuthenticationTypes?.Split(',');
|
||||
if (authTypesSplit != null && authTypesSplit.Any())
|
||||
{
|
||||
foreach (var authType in authTypesSplit)
|
||||
{
|
||||
policyBuilder.ActiveAuthenticationTypes.Add(authType);
|
||||
}
|
||||
}
|
||||
if (requireAnyAuthenticated)
|
||||
{
|
||||
policyBuilder.RequireAuthenticatedUser();
|
||||
}
|
||||
}
|
||||
return any ? policyBuilder.Build() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Security
|
|||
return this;
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy)
|
||||
public AuthorizationPolicyBuilder Combine([NotNull] AuthorizationPolicy policy)
|
||||
{
|
||||
AddAuthenticationTypes(policy.ActiveAuthenticationTypes.ToArray());
|
||||
AddRequirements(policy.Requirements.ToArray());
|
||||
|
|
@ -48,6 +48,11 @@ namespace Microsoft.AspNet.Security
|
|||
}
|
||||
|
||||
public AuthorizationPolicyBuilder RequiresClaim([NotNull] string claimType, params string[] requiredValues)
|
||||
{
|
||||
return RequiresClaim(claimType, (IEnumerable<string>)requiredValues);
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder RequiresClaim([NotNull] string claimType, IEnumerable<string> requiredValues)
|
||||
{
|
||||
Requirements.Add(new ClaimsAuthorizationRequirement
|
||||
{
|
||||
|
|
@ -68,6 +73,11 @@ namespace Microsoft.AspNet.Security
|
|||
}
|
||||
|
||||
public AuthorizationPolicyBuilder RequiresRole([NotNull] params string[] roles)
|
||||
{
|
||||
return RequiresRole((IEnumerable<string>)roles);
|
||||
}
|
||||
|
||||
public AuthorizationPolicyBuilder RequiresRole([NotNull] IEnumerable<string> roles)
|
||||
{
|
||||
RequiresClaim(ClaimTypes.Role, roles);
|
||||
return this;
|
||||
|
|
@ -81,7 +91,7 @@ namespace Microsoft.AspNet.Security
|
|||
|
||||
public AuthorizationPolicy Build()
|
||||
{
|
||||
return new AuthorizationPolicy(Requirements, ActiveAuthenticationTypes);
|
||||
return new AuthorizationPolicy(Requirements, ActiveAuthenticationTypes.Distinct());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// 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.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
public static class AuthorizationServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a user meets a specific authorization policy
|
||||
/// </summary>
|
||||
/// <param name="service">The authorization service.</param>
|
||||
/// <param name="user">The user to check the policy against.</param>
|
||||
/// <param name="resource">The resource the policy should be checked with.</param>
|
||||
/// <param name="policy">The policy to check against a specific context.</param>
|
||||
/// <returns><value>true</value> when the user fulfills the policy, <value>false</value> otherwise.</returns>
|
||||
public static Task<bool> AuthorizeAsync([NotNull] this IAuthorizationService service, ClaimsPrincipal user, object resource, [NotNull] AuthorizationPolicy policy)
|
||||
{
|
||||
if (policy.ActiveAuthenticationTypes != null && policy.ActiveAuthenticationTypes.Any() && user != null)
|
||||
{
|
||||
// Filter the user to only contain the active authentication types
|
||||
user = new ClaimsPrincipal(user.Identities.Where(i => policy.ActiveAuthenticationTypes.Contains(i.AuthenticationType)));
|
||||
}
|
||||
return service.AuthorizeAsync(user, resource, policy.Requirements.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user meets a specific authorization policy
|
||||
/// </summary>
|
||||
/// <param name="service">The authorization service.</param>
|
||||
/// <param name="user">The user to check the policy against.</param>
|
||||
/// <param name="resource">The resource the policy should be checked with.</param>
|
||||
/// <param name="policy">The policy to check against a specific context.</param>
|
||||
/// <returns><value>true</value> when the user fulfills the policy, <value>false</value> otherwise.</returns>
|
||||
public static bool Authorize([NotNull] this IAuthorizationService service, ClaimsPrincipal user, object resource, [NotNull] AuthorizationPolicy policy)
|
||||
{
|
||||
if (policy.ActiveAuthenticationTypes != null && policy.ActiveAuthenticationTypes.Any() && user != null)
|
||||
{
|
||||
// Filter the user to only contain the active authentication types
|
||||
user = new ClaimsPrincipal(user.Identities.Where(i => policy.ActiveAuthenticationTypes.Contains(i.AuthenticationType)));
|
||||
}
|
||||
return service.Authorize(user, resource, policy.Requirements.ToArray());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class AuthorizeAttribute : Attribute
|
||||
{
|
||||
public AuthorizeAttribute() { }
|
||||
|
||||
public AuthorizeAttribute(string policy)
|
||||
{
|
||||
Policy = policy;
|
||||
}
|
||||
|
||||
public string Policy { get; set; }
|
||||
|
||||
// REVIEW: can we get rid of the , deliminated in Roles/AuthTypes
|
||||
public string Roles { get; set; }
|
||||
|
||||
public string ActiveAuthenticationTypes { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -3,30 +3,30 @@
|
|||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
public class ClaimsAuthorizationHandler : AuthorizationHandler<ClaimsAuthorizationRequirement>
|
||||
{
|
||||
public override Task<bool> CheckAsync(AuthorizationContext context, ClaimsAuthorizationRequirement requirement)
|
||||
public override void Handle(AuthorizationContext context, ClaimsAuthorizationRequirement requirement)
|
||||
{
|
||||
if (context.Context.User == null)
|
||||
if (context.User != null)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
bool found = false;
|
||||
if (requirement.AllowedValues == null || !requirement.AllowedValues.Any())
|
||||
{
|
||||
found = context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
found = context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase)
|
||||
&& requirement.AllowedValues.Contains(c.Value, StringComparer.Ordinal));
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
if (requirement.AllowedValues == null || !requirement.AllowedValues.Any())
|
||||
{
|
||||
found = context.Context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
found = context.Context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase)
|
||||
&& requirement.AllowedValues.Contains(c.Value, StringComparer.Ordinal));
|
||||
}
|
||||
return Task.FromResult(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// 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.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
public class ClaimsTransformationOptions
|
||||
{
|
||||
public Func<ClaimsPrincipal, Task<ClaimsPrincipal>> TransformAsync { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
|
|
@ -21,47 +20,44 @@ namespace Microsoft.AspNet.Security
|
|||
_options = options.Options;
|
||||
}
|
||||
|
||||
public Task<bool> AuthorizeAsync([NotNull] string policyName, HttpContext context, object resource = null)
|
||||
public bool Authorize(ClaimsPrincipal user, object resource, string policyName)
|
||||
{
|
||||
var policy = _options.GetPolicy(policyName);
|
||||
if (policy == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this.Authorize(user, resource, policy);
|
||||
}
|
||||
|
||||
public bool Authorize(ClaimsPrincipal user, object resource, params IAuthorizationRequirement[] requirements)
|
||||
{
|
||||
var authContext = new AuthorizationContext(requirements, user, resource);
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
handler.Handle(authContext);
|
||||
}
|
||||
return authContext.HasSucceeded;
|
||||
}
|
||||
|
||||
public async Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, params IAuthorizationRequirement[] requirements)
|
||||
{
|
||||
var authContext = new AuthorizationContext(requirements, user, resource);
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
await handler.HandleAsync(authContext);
|
||||
}
|
||||
return authContext.HasSucceeded;
|
||||
}
|
||||
|
||||
public Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
|
||||
{
|
||||
var policy = _options.GetPolicy(policyName);
|
||||
if (policy == null)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
return AuthorizeAsync(policy, context, resource);
|
||||
}
|
||||
|
||||
public async Task<bool> AuthorizeAsync([NotNull] AuthorizationPolicy policy, [NotNull] HttpContext context, object resource = null)
|
||||
{
|
||||
var user = context.User;
|
||||
try
|
||||
{
|
||||
// Generate the user identities if policy specified the AuthTypes
|
||||
if (policy.ActiveAuthenticationTypes != null && policy.ActiveAuthenticationTypes.Any() )
|
||||
{
|
||||
var principal = new ClaimsPrincipal();
|
||||
|
||||
var results = await context.AuthenticateAsync(policy.ActiveAuthenticationTypes);
|
||||
// REVIEW: re requesting the identities fails for MVC currently, so we only request if not found
|
||||
foreach (var result in results)
|
||||
{
|
||||
principal.AddIdentity(result.Identity);
|
||||
}
|
||||
context.User = principal;
|
||||
}
|
||||
|
||||
var authContext = new AuthorizationContext(policy, context, resource);
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
await handler.HandleAsync(authContext);
|
||||
}
|
||||
return authContext.HasSucceeded;
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.User = user;
|
||||
}
|
||||
return this.AuthorizeAsync(user, resource, policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,14 +7,17 @@ namespace Microsoft.AspNet.Security
|
|||
{
|
||||
public class DenyAnonymousAuthorizationHandler : AuthorizationHandler<DenyAnonymousAuthorizationRequirement>
|
||||
{
|
||||
public override Task<bool> CheckAsync(AuthorizationContext context, DenyAnonymousAuthorizationRequirement requirement)
|
||||
public override void Handle(AuthorizationContext context, DenyAnonymousAuthorizationRequirement requirement)
|
||||
{
|
||||
var user = context.User;
|
||||
var userIsAnonymous =
|
||||
user == null ||
|
||||
user.Identity == null ||
|
||||
!user.Identity.IsAuthenticated;
|
||||
return Task.FromResult(!userIsAnonymous);
|
||||
if (!userIsAnonymous)
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@ namespace Microsoft.AspNet.Security
|
|||
public interface IAuthorizationHandler
|
||||
{
|
||||
Task HandleAsync(AuthorizationContext context);
|
||||
//void Handle(AuthorizationContext context);
|
||||
void Handle(AuthorizationContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// 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.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
|
|
@ -12,21 +12,39 @@ namespace Microsoft.AspNet.Security
|
|||
public interface IAuthorizationService
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a user meets a specific authorization policy
|
||||
/// Checks if a user meets a specific set of requirements for the specified resource
|
||||
/// </summary>
|
||||
/// <param name="policy">The policy to check against a specific context.</param>
|
||||
/// <param name="context">The HttpContext to check the policy against.</param>
|
||||
/// <param name="resource">The resource the policy should be checked with.</param>
|
||||
/// <returns><value>true</value> when the user fulfills the policy, <value>false</value> otherwise.</returns>
|
||||
Task<bool> AuthorizeAsync(string policyName, HttpContext context, object resource = null);
|
||||
/// <param name="user"></param>
|
||||
/// <param name="resource"></param>
|
||||
/// <param name="requirements"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, params IAuthorizationRequirement[] requirements);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user meets a specific set of requirements for the specified resource
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="resource"></param>
|
||||
/// <param name="requirements"></param>
|
||||
/// <returns></returns>
|
||||
bool Authorize(ClaimsPrincipal user, object resource, params IAuthorizationRequirement[] requirements);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user meets a specific authorization policy
|
||||
/// </summary>
|
||||
/// <param name="policy">The policy to check against a specific context.</param>
|
||||
/// <param name="context">The HttpContext to check the policy against.</param>
|
||||
/// <param name="user">The user to check the policy against.</param>
|
||||
/// <param name="resource">The resource the policy should be checked with.</param>
|
||||
/// <param name="policyName">The name of the policy to check against a specific context.</param>
|
||||
/// <returns><value>true</value> when the user fulfills the policy, <value>false</value> otherwise.</returns>
|
||||
Task<bool> AuthorizeAsync(AuthorizationPolicy policy, HttpContext context, object resource = null);
|
||||
Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user meets a specific authorization policy
|
||||
/// </summary>
|
||||
/// <param name="user">The user to check the policy against.</param>
|
||||
/// <param name="resource">The resource the policy should be checked with.</param>
|
||||
/// <param name="policyName">The name of the policy to check against a specific context.</param>
|
||||
/// <returns><value>true</value> when the user fulfills the policy, <value>false</value> otherwise.</returns>
|
||||
bool Authorize(ClaimsPrincipal user, object resource, string policyName);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
public class OperationAuthorizationRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,18 @@ namespace Microsoft.AspNet.Security
|
|||
{
|
||||
public async Task HandleAsync(AuthorizationContext context)
|
||||
{
|
||||
foreach (var handler in context.Policy.Requirements.OfType<IAuthorizationHandler>())
|
||||
foreach (var handler in context.Requirements.OfType<IAuthorizationHandler>())
|
||||
{
|
||||
await handler.HandleAsync(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(AuthorizationContext context)
|
||||
{
|
||||
foreach (var handler in context.Requirements.OfType<IAuthorizationHandler>())
|
||||
{
|
||||
handler.Handle(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNet.Security
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNet.Security.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The default data protection provider may only be used when the IApplicationBuilder.Properties contains an appropriate 'host.AppName' key.
|
||||
/// </summary>
|
||||
internal static string Exception_DefaultDpapiRequiresAppNameKey
|
||||
{
|
||||
get { return GetString("Exception_DefaultDpapiRequiresAppNameKey"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default data protection provider may only be used when the IApplicationBuilder.Properties contains an appropriate 'host.AppName' key.
|
||||
/// </summary>
|
||||
internal static string FormatException_DefaultDpapiRequiresAppNameKey()
|
||||
{
|
||||
return GetString("Exception_DefaultDpapiRequiresAppNameKey");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The state passed to UnhookAuthentication may only be the return value from HookAuthentication.
|
||||
/// </summary>
|
||||
internal static string Exception_UnhookAuthenticationStateType
|
||||
{
|
||||
get { return GetString("Exception_UnhookAuthenticationStateType"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The state passed to UnhookAuthentication may only be the return value from HookAuthentication.
|
||||
/// </summary>
|
||||
internal static string FormatException_UnhookAuthenticationStateType()
|
||||
{
|
||||
return GetString("Exception_UnhookAuthenticationStateType");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AuthenticationTokenProvider's required synchronous events have not been registered.
|
||||
/// </summary>
|
||||
internal static string Exception_AuthenticationTokenDoesNotProvideSyncMethods
|
||||
{
|
||||
get { return GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AuthenticationTokenProvider's required synchronous events have not been registered.
|
||||
/// </summary>
|
||||
internal static string FormatException_AuthenticationTokenDoesNotProvideSyncMethods()
|
||||
{
|
||||
return GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AuthorizationPolicy named: '{0}' was not found.
|
||||
/// </summary>
|
||||
internal static string Exception_AuthorizationPolicyNotFound
|
||||
{
|
||||
get { return GetString("Exception_AuthorizationPolicyNotFound"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AuthorizationPolicy named: '{0}' was not found.
|
||||
/// </summary>
|
||||
internal static string FormatException_AuthorizationPolicyNotFound(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("Exception_AuthorizationPolicyNotFound"), p0);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34003
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.AspNet.Security {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.Security.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The AuthenticationTokenProvider's required synchronous events have not been registered..
|
||||
/// </summary>
|
||||
internal static string Exception_AuthenticationTokenDoesNotProvideSyncMethods {
|
||||
get {
|
||||
return ResourceManager.GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The default data protection provider may only be used when the IApplicationBuilder.Properties contains an appropriate 'host.AppName' key..
|
||||
/// </summary>
|
||||
internal static string Exception_DefaultDpapiRequiresAppNameKey {
|
||||
get {
|
||||
return ResourceManager.GetString("Exception_DefaultDpapiRequiresAppNameKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A default value for SignInAsAuthenticationType was not found in IApplicationBuilder Properties. This can happen if your authentication middleware are added in the wrong order, or if one is missing..
|
||||
/// </summary>
|
||||
internal static string Exception_MissingDefaultSignInAsAuthenticationType {
|
||||
get {
|
||||
return ResourceManager.GetString("Exception_MissingDefaultSignInAsAuthenticationType", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The state passed to UnhookAuthentication may only be the return value from HookAuthentication..
|
||||
/// </summary>
|
||||
internal static string Exception_UnhookAuthenticationStateType {
|
||||
get {
|
||||
return ResourceManager.GetString("Exception_UnhookAuthenticationStateType", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,4 +126,7 @@
|
|||
<data name="Exception_AuthenticationTokenDoesNotProvideSyncMethods" xml:space="preserve">
|
||||
<value>The AuthenticationTokenProvider's required synchronous events have not been registered.</value>
|
||||
</data>
|
||||
<data name="Exception_AuthorizationPolicyNotFound" xml:space="preserve">
|
||||
<value>The AuthorizationPolicy named: '{0}' was not found.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -9,6 +9,11 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection ConfigureClaimsTransformation([NotNull] this IServiceCollection services, [NotNull] Action<ClaimsTransformationOptions> configure)
|
||||
{
|
||||
return services.Configure(configure);
|
||||
}
|
||||
|
||||
public static IServiceCollection ConfigureAuthorization([NotNull] this IServiceCollection services, [NotNull] Action<AuthorizationOptions> configure)
|
||||
{
|
||||
return services.Configure(configure);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
// 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.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Security.Test
|
||||
{
|
||||
public class AuthorizationPolicyFacts
|
||||
{
|
||||
[Fact]
|
||||
public void CanCombineAuthorizeAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AuthorizeAttribute[] {
|
||||
new AuthorizeAttribute(),
|
||||
new AuthorizeAttribute("1") { ActiveAuthenticationTypes = "dupe" },
|
||||
new AuthorizeAttribute("2") { ActiveAuthenticationTypes = "dupe" },
|
||||
new AuthorizeAttribute { Roles = "r1,r2", ActiveAuthenticationTypes = "roles" },
|
||||
};
|
||||
var options = new AuthorizationOptions();
|
||||
options.AddPolicy("1", policy => policy.RequiresClaim("1"));
|
||||
options.AddPolicy("2", policy => policy.RequiresClaim("2"));
|
||||
|
||||
// Act
|
||||
var combined = AuthorizationPolicy.Combine(options, attributes);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, combined.ActiveAuthenticationTypes.Count());
|
||||
Assert.True(combined.ActiveAuthenticationTypes.Contains("dupe"));
|
||||
Assert.True(combined.ActiveAuthenticationTypes.Contains("roles"));
|
||||
Assert.Equal(4, combined.Requirements.Count());
|
||||
Assert.True(combined.Requirements.Any(r => r is DenyAnonymousAuthorizationRequirement));
|
||||
Assert.Equal(3, combined.Requirements.OfType<ClaimsAuthorizationRequirement>().Count());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,11 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Fallback;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Security.Test
|
||||
|
|
@ -27,23 +25,12 @@ namespace Microsoft.AspNet.Security.Test
|
|||
return services.BuildServiceProvider().GetRequiredService<IAuthorizationService>();
|
||||
}
|
||||
|
||||
private Mock<HttpContext> SetupContext(params ClaimsIdentity[] ids)
|
||||
[Fact]
|
||||
public void AuthorizeCombineThrowsOnUnknownPolicy()
|
||||
{
|
||||
var context = new Mock<HttpContext>();
|
||||
context.SetupProperty(c => c.User);
|
||||
var user = new ClaimsPrincipal();
|
||||
user.AddIdentities(ids);
|
||||
context.Object.User = user;
|
||||
if (ids != null)
|
||||
{
|
||||
var results = new List<AuthenticationResult>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
results.Add(new AuthenticationResult(id, new AuthenticationProperties(), new AuthenticationDescription()));
|
||||
}
|
||||
context.Setup(c => c.AuthenticateAsync(It.IsAny<IEnumerable<string>>())).ReturnsAsync(results).Verifiable();
|
||||
}
|
||||
return context;
|
||||
Assert.Throws<InvalidOperationException>(() => AuthorizationPolicy.Combine(new AuthorizationOptions(), new AuthorizeAttribute[] {
|
||||
new AuthorizeAttribute { Policy = "Wut" }
|
||||
}));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -57,10 +44,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -77,10 +64,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -97,7 +84,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage", "CanViewAnything"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Permission", "CanViewPage"),
|
||||
|
|
@ -107,7 +94,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -124,7 +111,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage", "CanViewAnything"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("SomethingElse", "CanViewPage"),
|
||||
|
|
@ -133,7 +120,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -150,7 +137,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage", "CanViewAnything"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("SomethingElse", "CanViewPage"),
|
||||
|
|
@ -159,7 +146,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -176,7 +163,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Permission", "CanViewComment"),
|
||||
|
|
@ -185,7 +172,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -202,14 +189,14 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[0],
|
||||
"Basic")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -226,11 +213,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
context.Object.User = null;
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(null, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -247,10 +232,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity());
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -267,7 +252,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresClaim("Permission", "CanViewPage"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Permission", "CanViewPage"),
|
||||
|
|
@ -276,7 +261,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -287,7 +272,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Permission", "CanViewComment"),
|
||||
|
|
@ -296,7 +281,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -309,7 +294,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
var policy = new AuthorizationPolicyBuilder().RequiresRole("Administrator")
|
||||
.RequiresClaim(ClaimTypes.Role, "User");
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim(ClaimTypes.Role, "User"),
|
||||
|
|
@ -319,7 +304,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -331,7 +316,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim(ClaimTypes.Role);
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim(ClaimTypes.Role, ""),
|
||||
|
|
@ -340,7 +325,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -352,12 +337,46 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder("AuthType").RequiresClaim(ClaimTypes.Name);
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, "Name") }, "AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Authorize_PolicyWillFilterAuthenticationType()
|
||||
{
|
||||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder("Bogus").RequiresClaim(ClaimTypes.Name);
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, "Name") }, "AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Authorize_PolicyCanFilterMultipleAuthenticationType()
|
||||
{
|
||||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder("One", "Two").RequiresClaim(ClaimTypes.Name, "one").RequiresClaim(ClaimTypes.Name, "two");
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var user = new ClaimsPrincipal();
|
||||
user.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, "one") }, "One"));
|
||||
user.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, "two") }, "Two"));
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -369,12 +388,12 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder("AuthType").RequiresRole("Admin");
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Role, "Admin") }, "AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -386,11 +405,11 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder("AuthType").RequiresRole("Admin", "Users");
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Role, "Users") }, "AuthType"));
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -402,7 +421,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
// Arrange
|
||||
var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
|
||||
var authorizationService = BuildAuthorizationService();
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim(ClaimTypes.Role, "Nope"),
|
||||
|
|
@ -411,7 +430,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -428,7 +447,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => policy.RequiresRole("Admin", "Users"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
},
|
||||
|
|
@ -436,7 +455,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -453,7 +472,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Basic", policy => { });
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim(ClaimTypes.Name, "Name"),
|
||||
|
|
@ -462,7 +481,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Basic");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -479,7 +498,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Any", policy => policy.RequireAuthenticatedUser());
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim(ClaimTypes.Name, "Name"),
|
||||
|
|
@ -488,7 +507,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Any", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Any");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -505,10 +524,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Any", policy => policy.RequireAuthenticatedUser());
|
||||
});
|
||||
});
|
||||
var context = SetupContext(new ClaimsIdentity());
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Any", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Any");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -517,9 +536,9 @@ namespace Microsoft.AspNet.Security.Test
|
|||
public class CustomRequirement : IAuthorizationRequirement { }
|
||||
public class CustomHandler : AuthorizationHandler<CustomRequirement>
|
||||
{
|
||||
public override Task<bool> CheckAsync(AuthorizationContext context, CustomRequirement requirement)
|
||||
public override void Handle(AuthorizationContext context, CustomRequirement requirement)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -534,10 +553,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
var user = new ClaimsPrincipal();
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Custom", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Custom");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -555,10 +574,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
var user = new ClaimsPrincipal();
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Custom", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Custom");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -573,9 +592,11 @@ namespace Microsoft.AspNet.Security.Test
|
|||
|
||||
public bool Succeed { get; set; }
|
||||
|
||||
public override Task<bool> CheckAsync(AuthorizationContext context, PassThroughRequirement requirement)
|
||||
public override void Handle(AuthorizationContext context, PassThroughRequirement requirement)
|
||||
{
|
||||
return Task.FromResult(Succeed);
|
||||
if (Succeed) {
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -592,10 +613,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Passthrough", policy => policy.Requirements.Add(new PassThroughRequirement(shouldSucceed)));
|
||||
});
|
||||
});
|
||||
var context = SetupContext();
|
||||
var user = new ClaimsPrincipal();
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Passthrough", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Passthrough");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(shouldSucceed, allowed);
|
||||
|
|
@ -609,10 +630,10 @@ namespace Microsoft.AspNet.Security.Test
|
|||
services.ConfigureAuthorization(options =>
|
||||
{
|
||||
var basePolicy = new AuthorizationPolicyBuilder().RequiresClaim("Base", "Value").Build();
|
||||
options.AddPolicy("Combineed", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
options.AddPolicy("Combined", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Base", "Value"),
|
||||
|
|
@ -622,7 +643,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Combined", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined");
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
|
@ -639,7 +660,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Combined", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Claim", "Exists")
|
||||
|
|
@ -648,7 +669,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Combined", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
|
|
@ -665,7 +686,7 @@ namespace Microsoft.AspNet.Security.Test
|
|||
options.AddPolicy("Combined", policy => policy.Combine(basePolicy).RequiresClaim("Claim", "Exists"));
|
||||
});
|
||||
});
|
||||
var context = SetupContext(
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("Base", "Value"),
|
||||
|
|
@ -674,10 +695,88 @@ namespace Microsoft.AspNet.Security.Test
|
|||
);
|
||||
|
||||
// Act
|
||||
var allowed = await authorizationService.AuthorizeAsync("Combined", context.Object);
|
||||
var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined");
|
||||
|
||||
// Assert
|
||||
Assert.False(allowed);
|
||||
}
|
||||
|
||||
public class ExpenseReport { }
|
||||
|
||||
public static class Operations
|
||||
{
|
||||
public static OperationAuthorizationRequirement Edit = new OperationAuthorizationRequirement { Name = "Edit" };
|
||||
public static OperationAuthorizationRequirement Create = new OperationAuthorizationRequirement { Name = "Create" };
|
||||
public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = "Delete" };
|
||||
}
|
||||
|
||||
public class ExpenseReportAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, ExpenseReport>
|
||||
{
|
||||
public ExpenseReportAuthorizationHandler(IEnumerable<OperationAuthorizationRequirement> authorized)
|
||||
{
|
||||
_allowed = authorized;
|
||||
}
|
||||
|
||||
private IEnumerable<OperationAuthorizationRequirement> _allowed;
|
||||
|
||||
public override void Handle(AuthorizationContext context, OperationAuthorizationRequirement requirement, ExpenseReport resource)
|
||||
{
|
||||
if (_allowed.Contains(requirement))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SuperUserHandler : AuthorizationHandler<OperationAuthorizationRequirement>
|
||||
{
|
||||
public override void Handle(AuthorizationContext context, OperationAuthorizationRequirement requirement)
|
||||
{
|
||||
if (context.User.HasClaim("SuperUser", "yes"))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CanAuthorizeAllSuperuserOperations()
|
||||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.AddInstance<IAuthorizationHandler>(new ExpenseReportAuthorizationHandler(new OperationAuthorizationRequirement[] { Operations.Edit }));
|
||||
services.AddTransient<IAuthorizationHandler, SuperUserHandler>();
|
||||
});
|
||||
var user = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new Claim[] {
|
||||
new Claim("SuperUser", "yes"),
|
||||
},
|
||||
"AuthType")
|
||||
);
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Edit));
|
||||
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Delete));
|
||||
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Create));
|
||||
}
|
||||
|
||||
public async Task CanAuthorizeOnlyAllowedOperations()
|
||||
{
|
||||
// Arrange
|
||||
var authorizationService = BuildAuthorizationService(services =>
|
||||
{
|
||||
services.AddInstance<IAuthorizationHandler>(new ExpenseReportAuthorizationHandler(new OperationAuthorizationRequirement[] { Operations.Edit }));
|
||||
services.AddTransient<IAuthorizationHandler, SuperUserHandler>();
|
||||
});
|
||||
var user = new ClaimsPrincipal();
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Edit));
|
||||
Assert.False(await authorizationService.AuthorizeAsync(user, null, Operations.Delete));
|
||||
Assert.False(await authorizationService.AuthorizeAsync(user, null, Operations.Create));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue