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:
Hao Kung 2015-02-16 15:04:10 -08:00
parent 58661b2734
commit 5094b85ac9
20 changed files with 637 additions and 301 deletions

View File

@ -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; } }

View File

@ -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);
//}
}

View File

@ -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;
}
}
}

View File

@ -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());
}
}
}

View File

@ -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());
}
}
}

View File

@ -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; }
}
}

View File

@ -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);
}
}
}

View File

@ -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; }
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -8,6 +8,6 @@ namespace Microsoft.AspNet.Security
public interface IAuthorizationHandler
{
Task HandleAsync(AuthorizationContext context);
//void Handle(AuthorizationContext context);
void Handle(AuthorizationContext context);
}
}

View File

@ -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);
}
}

View File

@ -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; }
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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&apos;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 &apos;host.AppName&apos; 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);
}
}
}
}

View File

@ -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>

View File

@ -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);

View File

@ -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());
}
}
}

View File

@ -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));
}
}
}