diff --git a/src/Microsoft.AspNet.Security/AuthorizationContext.cs b/src/Microsoft.AspNet.Security/AuthorizationContext.cs
new file mode 100644
index 0000000000..0c6dc06197
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/AuthorizationContext.cs
@@ -0,0 +1,61 @@
+// 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.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.AspNet.Http;
+
+namespace Microsoft.AspNet.Security
+{
+ ///
+ /// Contains authorization information used by .
+ ///
+ public class AuthorizationContext
+ {
+ private HashSet _pendingRequirements = new HashSet();
+ private bool _failCalled;
+ private bool _succeedCalled;
+
+ public AuthorizationContext(
+ [NotNull] AuthorizationPolicy policy,
+ HttpContext context,
+ object resource)
+ {
+ Policy = policy;
+ Context = context;
+ Resource = resource;
+ foreach (var req in Policy.Requirements)
+ {
+ _pendingRequirements.Add(req);
+ }
+ }
+
+ public AuthorizationPolicy Policy { get; private set; }
+ public ClaimsPrincipal User { get { return Context.User; } }
+ public HttpContext Context { get; private set; }
+ public object Resource { get; private set; }
+
+ public IEnumerable PendingRequirements { get { return _pendingRequirements; } }
+
+ public bool HasFailed { get { return _failCalled; } }
+
+ public bool HasSucceeded {
+ get
+ {
+ return !_failCalled && _succeedCalled && !PendingRequirements.Any();
+ }
+ }
+
+ public void Fail()
+ {
+ _failCalled = true;
+ }
+
+ public void Succeed(IAuthorizationRequirement requirement)
+ {
+ _succeedCalled = true;
+ _pendingRequirements.Remove(requirement);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Security/AuthorizationHandler.cs b/src/Microsoft.AspNet.Security/AuthorizationHandler.cs
new file mode 100644
index 0000000000..d913318700
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/AuthorizationHandler.cs
@@ -0,0 +1,58 @@
+// 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(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
+ //bool AuthorizeAsync(ClaimsPrincipal, string operation, TResource instance)
+ //bool AuthorizeAsync(IAuthorization, ClaimsPrincipal, string operation, TResource instance)
+ public abstract class AuthorizationHandler : IAuthorizationHandler
+ where TRequirement : IAuthorizationRequirement
+ {
+ public async Task HandleAsync(AuthorizationContext context)
+ {
+ foreach (var req in context.Policy.Requirements.OfType())
+ {
+ if (await CheckAsync(context, req))
+ {
+ context.Succeed(req);
+ }
+ else
+ {
+ context.Fail();
+ }
+ }
+ }
+
+ public abstract Task CheckAsync(AuthorizationContext context, TRequirement requirement);
+ }
+
+ // TODO:
+ //public abstract class AuthorizationHandler : AuthorizationHandler
+ // 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);
+ //}
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Security/AuthorizationOptions.cs b/src/Microsoft.AspNet.Security/AuthorizationOptions.cs
new file mode 100644
index 0000000000..667ee4fcba
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/AuthorizationOptions.cs
@@ -0,0 +1,23 @@
+// 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.Collections.Generic;
+
+namespace Microsoft.AspNet.Security
+{
+ public class AuthorizationOptions
+ {
+ // TODO: make this case insensitive
+ private IDictionary PolicyMap { get; } = new Dictionary();
+
+ public void AddPolicy([NotNull] string name, [NotNull] AuthorizationPolicy policy)
+ {
+ PolicyMap[name] = policy;
+ }
+
+ public AuthorizationPolicy GetPolicy([NotNull] string name)
+ {
+ return PolicyMap.ContainsKey(name) ? PolicyMap[name] : null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Security/AuthorizationPolicy.cs b/src/Microsoft.AspNet.Security/AuthorizationPolicy.cs
index a58ae858ae..d142eb1b60 100644
--- a/src/Microsoft.AspNet.Security/AuthorizationPolicy.cs
+++ b/src/Microsoft.AspNet.Security/AuthorizationPolicy.cs
@@ -2,31 +2,18 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
-using System.Security.Claims;
-using System.Threading.Tasks;
namespace Microsoft.AspNet.Security
{
- ///
- /// This class provides a base implementation for
- ///
- public abstract class AuthorizationPolicy : IAuthorizationPolicy
+ public class AuthorizationPolicy
{
- public int Order { get; set; }
-
- public virtual Task ApplyingAsync(AuthorizationPolicyContext context)
+ public AuthorizationPolicy(IEnumerable requirements, IEnumerable activeAuthenticationTypes)
{
- return Task.FromResult(0);
+ Requirements = requirements;
+ ActiveAuthenticationTypes = activeAuthenticationTypes;
}
- public virtual Task ApplyAsync(AuthorizationPolicyContext context)
- {
- return Task.FromResult(0);
- }
-
- public virtual Task AppliedAsync(AuthorizationPolicyContext context)
- {
- return Task.FromResult(0);
- }
+ public IEnumerable Requirements { get; private set; }
+ public IEnumerable ActiveAuthenticationTypes { get; private set; }
}
}
diff --git a/src/Microsoft.AspNet.Security/AuthorizationPolicyBuilder.cs b/src/Microsoft.AspNet.Security/AuthorizationPolicyBuilder.cs
new file mode 100644
index 0000000000..520bc77460
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/AuthorizationPolicyBuilder.cs
@@ -0,0 +1,58 @@
+// 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.Collections.Generic;
+using System.Security.Claims;
+
+namespace Microsoft.AspNet.Security
+{
+ public class AuthorizationPolicyBuilder
+ {
+ public AuthorizationPolicyBuilder(params string[] activeAuthenticationTypes)
+ {
+ foreach (var authType in activeAuthenticationTypes) {
+ ActiveAuthenticationTypes.Add(authType);
+ }
+ }
+
+ public IList Requirements { get; set; } = new List();
+ public IList ActiveAuthenticationTypes { get; set; } = new List();
+
+ public AuthorizationPolicyBuilder RequiresClaim([NotNull] string claimType, params string[] requiredValues)
+ {
+ Requirements.Add(new ClaimsAuthorizationRequirement
+ {
+ ClaimType = claimType,
+ AllowedValues = requiredValues
+ });
+ return this;
+ }
+
+ public AuthorizationPolicyBuilder RequiresClaim([NotNull] string claimType)
+ {
+ Requirements.Add(new ClaimsAuthorizationRequirement
+ {
+ ClaimType = claimType,
+ AllowedValues = null
+ });
+ return this;
+ }
+
+ public AuthorizationPolicyBuilder RequiresRole([NotNull] params string[] roles)
+ {
+ RequiresClaim(ClaimTypes.Role, roles);
+ return this;
+ }
+
+ public AuthorizationPolicyBuilder RequireAuthenticatedUser()
+ {
+ Requirements.Add(new DenyAnonymousAuthorizationRequirement());
+ return this;
+ }
+
+ public AuthorizationPolicy Build()
+ {
+ return new AuthorizationPolicy(Requirements, ActiveAuthenticationTypes);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Security/AuthorizationPolicyContext.cs b/src/Microsoft.AspNet.Security/AuthorizationPolicyContext.cs
deleted file mode 100644
index b394bfcb68..0000000000
--- a/src/Microsoft.AspNet.Security/AuthorizationPolicyContext.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.Collections.Generic;
-using System.Security.Claims;
-using System.Linq;
-
-namespace Microsoft.AspNet.Security
-{
- ///
- /// Contains authorization information used by .
- ///
- public class AuthorizationPolicyContext
- {
- public AuthorizationPolicyContext(IEnumerable claims, ClaimsPrincipal user, object resource )
- {
- Claims = (claims ?? Enumerable.Empty()).ToList();
- User = user;
- Resource = resource;
-
- // user claims are copied to a new and mutable list
- UserClaims = user != null
- ? user.Claims.ToList()
- : new List();
- }
-
- ///
- /// The list of claims the is checking.
- ///
- public IList Claims { get; private set; }
-
- ///
- /// The user to check the claims against.
- ///
- public ClaimsPrincipal User { get; private set; }
-
- ///
- /// The claims of the user.
- ///
- ///
- /// This list can be modified by policies for retries.
- ///
- public IList UserClaims { get; private set; }
-
- ///
- /// An optional resource associated to the check.
- ///
- public object Resource { get; private set; }
-
- ///
- /// Gets or set whether the permission will be granted to the user.
- ///
- public bool Authorized { get; set; }
-
- ///
- /// When set to true, the authorization check will be processed again.
- ///
- public bool Retry { get; set; }
- }
-}
diff --git a/src/Microsoft.AspNet.Security/AuthorizationServiceExtensions.cs b/src/Microsoft.AspNet.Security/AuthorizationServiceExtensions.cs
deleted file mode 100644
index 17ec58196d..0000000000
--- a/src/Microsoft.AspNet.Security/AuthorizationServiceExtensions.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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;
-using System.Security.Claims;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNet.Security
-{
- public static class AuthorizationServiceExtensions
- {
- ///
- /// Checks if a user has specific claims.
- ///
- /// The claim to check against a specific user.
- /// The user to check claims against.
- /// true when the user fulfills one of the claims, false otherwise.
- public static Task AuthorizeAsync([NotNull] this IAuthorizationService service, Claim claim, ClaimsPrincipal user)
- {
- return service.AuthorizeAsync(new Claim[] { claim }, user);
- }
-
- ///
- /// Checks if a user has specific claims.
- ///
- /// The claim to check against a specific user.
- /// The user to check claims against.
- /// true when the user fulfills one of the claims, false otherwise.
- public static bool Authorize([NotNull] this IAuthorizationService service, Claim claim, ClaimsPrincipal user)
- {
- return service.Authorize(new Claim[] { claim }, user);
- }
-
- ///
- /// Checks if a user has specific claims for a specific context obj.
- ///
- /// The claim to check against a specific user.
- /// The user to check claims against.
- /// The resource the claims should be check with.
- /// true when the user fulfills one of the claims, false otherwise.
- public static Task AuthorizeAsync([NotNull] this IAuthorizationService service, Claim claim, ClaimsPrincipal user, object resource)
- {
- return service.AuthorizeAsync(new Claim[] { claim }, user, resource);
- }
-
- ///
- /// Checks if a user has specific claims for a specific context obj.
- ///
- /// The claimsto check against a specific user.
- /// The user to check claims against.
- /// The resource the claims should be check with.
- /// true when the user fulfills one of the claims, false otherwise.
- public static bool Authorize([NotNull] this IAuthorizationService service, Claim claim, ClaimsPrincipal user, object resource)
- {
- return service.Authorize(new Claim[] { claim }, user, resource);
- }
-
- ///
- /// Checks if a user has specific claims.
- ///
- /// The claims to check against a specific user.
- /// The user to check claims against.
- /// true when the user fulfills one of the claims, false otherwise.
- public static Task AuthorizeAsync([NotNull] this IAuthorizationService service, IEnumerable claims, ClaimsPrincipal user)
- {
- return service.AuthorizeAsync(claims, user, null);
- }
-
- ///
- /// Checks if a user has specific claims.
- ///
- /// The claims to check against a specific user.
- /// The user to check claims against.
- /// true when the user fulfills one of the claims, false otherwise.
- public static bool Authorize([NotNull] this IAuthorizationService service, IEnumerable claims, ClaimsPrincipal user)
- {
- return service.Authorize(claims, user, null);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Security/ClaimsAuthorizationHandler.cs b/src/Microsoft.AspNet.Security/ClaimsAuthorizationHandler.cs
new file mode 100644
index 0000000000..9f3f58c3ac
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/ClaimsAuthorizationHandler.cs
@@ -0,0 +1,32 @@
+// 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
+{
+ public class ClaimsAuthorizationHandler : AuthorizationHandler
+ {
+ public override Task CheckAsync(AuthorizationContext context, ClaimsAuthorizationRequirement requirement)
+ {
+ if (context.Context.User == null)
+ {
+ return Task.FromResult(false);
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Security/ClaimsAuthorizationRequirement.cs b/src/Microsoft.AspNet.Security/ClaimsAuthorizationRequirement.cs
new file mode 100644
index 0000000000..8ec5e7c7e1
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/ClaimsAuthorizationRequirement.cs
@@ -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.Collections.Generic;
+
+namespace Microsoft.AspNet.Security
+{
+ // Must contain a claim with the specified name, and at least one of the required values
+ // If AllowedValues is null or empty, that means any claim is valid
+ public class ClaimsAuthorizationRequirement : IAuthorizationRequirement
+ {
+ public string ClaimType { get; set; }
+ public IEnumerable AllowedValues { get; set; }
+ }
+}
diff --git a/src/Microsoft.AspNet.Security/DefaultAuthorizationService.cs b/src/Microsoft.AspNet.Security/DefaultAuthorizationService.cs
index 0b05a6d3dd..d20cf65445 100644
--- a/src/Microsoft.AspNet.Security/DefaultAuthorizationService.cs
+++ b/src/Microsoft.AspNet.Security/DefaultAuthorizationService.cs
@@ -1,101 +1,67 @@
// 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;
using System.Security.Claims;
using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
+using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Security
{
public class DefaultAuthorizationService : IAuthorizationService
{
- private readonly IList _policies;
- public int MaxRetries = 99;
+ private readonly IList _handlers;
+ private readonly AuthorizationOptions _options;
- public DefaultAuthorizationService(IEnumerable policies)
+ public DefaultAuthorizationService(IOptions options, IEnumerable handlers)
{
- if (policies == null)
- {
- _policies = Enumerable.Empty().ToArray();
- }
- else
- {
- _policies = policies.OrderBy(x => x.Order).ToArray();
- }
+ _handlers = handlers.ToArray();
+ _options = options.Options;
}
- public async Task AuthorizeAsync(IEnumerable claims, ClaimsPrincipal user, object resource)
+ public Task AuthorizeAsync([NotNull] string policyName, HttpContext context, object resource = null)
{
- var context = new AuthorizationPolicyContext(claims, user, resource);
-
- foreach (var policy in _policies)
+ var policy = _options.GetPolicy(policyName);
+ if (policy == null)
{
- await policy.ApplyingAsync(context);
+ return Task.FromResult(false);
}
+ return AuthorizeAsync(policy, context, resource);
+ }
- // we only apply the policies for a limited number of times to prevent
- // infinite loops
-
- int retries;
- for (retries = 0; retries < MaxRetries; retries++)
+ public async Task AuthorizeAsync([NotNull] AuthorizationPolicy policy, [NotNull] HttpContext context, object resource = null)
+ {
+ var user = context.User;
+ try
{
- // we don't need to check for owned claims if the permission is already granted
- if (!context.Authorized)
+ // Generate the user identities if policy specified the AuthTypes
+ if (policy.ActiveAuthenticationTypes != null && policy.ActiveAuthenticationTypes.Any() )
{
- if (context.User != null)
+ 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)
{
- if (ClaimsMatch(context.Claims, context.UserClaims))
- {
- context.Authorized = true;
- }
+ principal.AddIdentity(result.Identity);
}
+ context.User = principal;
}
- // reset the retry flag
- context.Retry = false;
+ var authContext = new AuthorizationContext(policy, context, resource);
- // give a chance for policies to change claims or the grant
- foreach (var policy in _policies)
+ foreach (var handler in _handlers)
{
- await policy.ApplyAsync(context);
- }
-
- // if no policies have changed the context, stop checking
- if (!context.Retry)
- {
- break;
+ await handler.HandleAsync(authContext);
}
+ return authContext.HasSucceeded;
}
-
- if (retries == MaxRetries)
+ finally
{
- throw new InvalidOperationException("Too many authorization retries.");
+ context.User = user;
}
-
- foreach (var policy in _policies)
- {
- await policy.AppliedAsync(context);
- }
-
- return context.Authorized;
- }
-
- public bool Authorize(IEnumerable claims, ClaimsPrincipal user, object resource)
- {
- return AuthorizeAsync(claims, user, resource).GetAwaiter().GetResult();
- }
-
- private bool ClaimsMatch([NotNull] IEnumerable x, [NotNull] IEnumerable y)
- {
- return x.Any(claim =>
- y.Any(userClaim =>
- string.Equals(claim.Type, userClaim.Type, StringComparison.OrdinalIgnoreCase) &&
- string.Equals(claim.Value, userClaim.Value, StringComparison.Ordinal)
- )
- );
-
}
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Security/DenyAnonymousAuthorizationHandler.cs b/src/Microsoft.AspNet.Security/DenyAnonymousAuthorizationHandler.cs
new file mode 100644
index 0000000000..878a32ec92
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/DenyAnonymousAuthorizationHandler.cs
@@ -0,0 +1,20 @@
+// 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.Threading.Tasks;
+
+namespace Microsoft.AspNet.Security
+{
+ public class DenyAnonymousAuthorizationHandler : AuthorizationHandler
+ {
+ public override Task CheckAsync(AuthorizationContext context, DenyAnonymousAuthorizationRequirement requirement)
+ {
+ var user = context.User;
+ var userIsAnonymous =
+ user == null ||
+ user.Identity == null ||
+ !user.Identity.IsAuthenticated;
+ return Task.FromResult(!userIsAnonymous);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Security/DenyAnonymousAuthorizationRequirement.cs b/src/Microsoft.AspNet.Security/DenyAnonymousAuthorizationRequirement.cs
new file mode 100644
index 0000000000..286d5fd69a
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/DenyAnonymousAuthorizationRequirement.cs
@@ -0,0 +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 Microsoft.AspNet.Security;
+
+namespace Microsoft.AspNet.Security
+{
+ public class DenyAnonymousAuthorizationRequirement : IAuthorizationRequirement { }
+}
diff --git a/src/Microsoft.AspNet.Security/IAuthorizationPolicy.cs b/src/Microsoft.AspNet.Security/IAuthorizationHandler.cs
similarity index 50%
rename from src/Microsoft.AspNet.Security/IAuthorizationPolicy.cs
rename to src/Microsoft.AspNet.Security/IAuthorizationHandler.cs
index 0f121d558a..975a305b86 100644
--- a/src/Microsoft.AspNet.Security/IAuthorizationPolicy.cs
+++ b/src/Microsoft.AspNet.Security/IAuthorizationHandler.cs
@@ -5,11 +5,9 @@ using System.Threading.Tasks;
namespace Microsoft.AspNet.Security
{
- public interface IAuthorizationPolicy
+ public interface IAuthorizationHandler
{
- int Order { get; set; }
- Task ApplyingAsync(AuthorizationPolicyContext context);
- Task ApplyAsync(AuthorizationPolicyContext context);
- Task AppliedAsync(AuthorizationPolicyContext context);
+ Task HandleAsync(AuthorizationContext context);
+ //void Handle(AuthorizationContext context);
}
}
diff --git a/src/Microsoft.AspNet.Security/IAuthorizationRequirement.cs b/src/Microsoft.AspNet.Security/IAuthorizationRequirement.cs
new file mode 100644
index 0000000000..bd25247df2
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/IAuthorizationRequirement.cs
@@ -0,0 +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.
+
+namespace Microsoft.AspNet.Security
+{
+ public interface IAuthorizationRequirement
+ {
+ }
+}
diff --git a/src/Microsoft.AspNet.Security/IAuthorizationService.cs b/src/Microsoft.AspNet.Security/IAuthorizationService.cs
index 9fcef75a2f..8bcafda3d7 100644
--- a/src/Microsoft.AspNet.Security/IAuthorizationService.cs
+++ b/src/Microsoft.AspNet.Security/IAuthorizationService.cs
@@ -1,34 +1,32 @@
// 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.Collections.Generic;
-using System.Security.Claims;
using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Security
{
///
- /// Checks claims based permissions for a user.
+ /// Checks policy based permissions for a user
///
public interface IAuthorizationService
{
///
- /// Checks if a user has specific claims for a specific context obj.
+ /// Checks if a user meets a specific authorization policy
///
- /// The claims to check against a specific user.
- /// The user to check claims against.
- /// The resource the claims should be check with.
- /// true when the user fulfills one of the claims, false otherwise.
- Task AuthorizeAsync(IEnumerable claims, ClaimsPrincipal user, object resource);
+ /// The policy to check against a specific context.
+ /// The HttpContext to check the policy against.
+ /// The resource the policy should be checked with.
+ /// true when the user fulfills the policy, false otherwise.
+ Task AuthorizeAsync(string policyName, HttpContext context, object resource = null);
///
- /// Checks if a user has specific claims for a specific context obj.
+ /// Checks if a user meets a specific authorization policy
///
- /// The claims to check against a specific user.
- /// The user to check claims against.
- /// The resource the claims should be check with.
- /// true when the user fulfills one of the claims, false otherwise.
- bool Authorize(IEnumerable claims, ClaimsPrincipal user, object resource);
-
+ /// The policy to check against a specific context.
+ /// The HttpContext to check the policy against.
+ /// The resource the policy should be checked with.
+ /// true when the user fulfills the policy, false otherwise.
+ Task AuthorizeAsync(AuthorizationPolicy policy, HttpContext context, object resource = null);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Security/PassThroughAuthorizationHandler.cs b/src/Microsoft.AspNet.Security/PassThroughAuthorizationHandler.cs
new file mode 100644
index 0000000000..0dfc6ab289
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/PassThroughAuthorizationHandler.cs
@@ -0,0 +1,20 @@
+// 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
+{
+ public class PassThroughAuthorizationHandler : IAuthorizationHandler
+ {
+ public async Task HandleAsync(AuthorizationContext context)
+ {
+ foreach (var handler in context.Policy.Requirements.OfType())
+ {
+ await handler.HandleAsync(context);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Security/ServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Security/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000000..cceec4cc28
--- /dev/null
+++ b/src/Microsoft.AspNet.Security/ServiceCollectionExtensions.cs
@@ -0,0 +1,32 @@
+// 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 Microsoft.AspNet.Security;
+using Microsoft.Framework.ConfigurationModel;
+
+namespace Microsoft.Framework.DependencyInjection
+{
+ public static class ServiceCollectionExtensions
+ {
+ public static IServiceCollection ConfigureAuthorization([NotNull] this IServiceCollection services, [NotNull] Action configure)
+ {
+ return services.Configure(configure);
+ }
+
+ // Review: Need UseDefaultSubkey parameter?
+ public static IServiceCollection AddAuthorization([NotNull] this IServiceCollection services, IConfiguration config = null, Action configureOptions = null)
+ {
+ var describe = new ServiceDescriber(config);
+ services.AddOptions(config);
+ services.TryAdd(describe.Transient());
+ services.Add(describe.Transient());
+ services.Add(describe.Transient());
+ if (configureOptions != null)
+ {
+ services.Configure(configureOptions);
+ }
+ return services;
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Security.Test/DefaultAuthorizationServiceTests.cs b/test/Microsoft.AspNet.Security.Test/DefaultAuthorizationServiceTests.cs
index a5a003b801..00f6cde0aa 100644
--- a/test/Microsoft.AspNet.Security.Test/DefaultAuthorizationServiceTests.cs
+++ b/test/Microsoft.AspNet.Security.Test/DefaultAuthorizationServiceTests.cs
@@ -3,307 +3,588 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
-using Microsoft.AspNet.Security;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Http.Security;
+using Microsoft.Framework.DependencyInjection;
+using Microsoft.Framework.DependencyInjection.Fallback;
+using Microsoft.Framework.OptionsModel;
+using Moq;
using Xunit;
namespace Microsoft.AspNet.Security.Test
{
public class DefaultAuthorizationServiceTests
{
+ private IAuthorizationService BuildAuthorizationService(Action setupServices = null)
+ {
+ var services = new ServiceCollection();
+ services.AddAuthorization();
+ if (setupServices != null)
+ {
+ setupServices(services);
+ }
+ return services.BuildServiceProvider().GetRequiredService();
+ }
+
+ private Mock SetupContext(params ClaimsIdentity[] ids)
+ {
+ var context = new Mock();
+ context.SetupProperty(c => c.User);
+ var user = new ClaimsPrincipal();
+ user.AddIdentities(ids);
+ context.Object.User = user;
+ if (ids != null)
+ {
+ var results = new List();
+ foreach (var id in ids)
+ {
+ results.Add(new AuthenticationResult(id, new AuthenticationProperties(), new AuthenticationDescription()));
+ }
+ context.Setup(c => c.AuthenticateAsync(It.IsAny>())).ReturnsAsync(results).Verifiable();
+ }
+ return context;
+ }
+
[Fact]
- public void Check_ShouldAllowIfClaimIsPresent()
+ public async Task Authorize_ShouldAllowIfClaimIsPresent()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- var user = new ClaimsPrincipal(
- new ClaimsIdentity( new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic")
- );
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ options.AddPolicy("Basic", new AuthorizationPolicyBuilder()
+ .RequiresClaim("Permission", "CanViewPage")
+ .Build());
+ });
+ });
+ var context = SetupContext(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.True(allowed);
}
[Fact]
- public void Check_ShouldAllowIfClaimIsAmongValues()
+ public async Task Authorize_ShouldAllowIfClaimIsPresentWithSpecifiedAuthType()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- var user = new ClaimsPrincipal(
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder("Basic").RequiresClaim("Permission", "CanViewPage");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
+ [Fact]
+ public async Task Authorize_ShouldAllowIfClaimIsAmongValues()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage", "CanViewAnything");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
new ClaimsIdentity(
- new Claim[] {
- new Claim("Permission", "CanViewPage"),
+ new Claim[] {
+ new Claim("Permission", "CanViewPage"),
new Claim("Permission", "CanViewAnything")
- },
+ },
"Basic")
);
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.True(allowed);
}
[Fact]
- public void Check_ShouldNotAllowIfClaimTypeIsNotPresent()
+ public async Task Authorize_ShouldFailWhenAllRequirementsNotHandled()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- var user = new ClaimsPrincipal(
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage", "CanViewAnything");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
new ClaimsIdentity(
- new Claim[] {
- new Claim("SomethingElse", "CanViewPage"),
+ new Claim[] {
+ new Claim("SomethingElse", "CanViewPage"),
},
"Basic")
);
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.False(allowed);
}
[Fact]
- public void Check_ShouldNotAllowIfClaimValueIsNotPresent()
+ public async Task Authorize_ShouldNotAllowIfClaimTypeIsNotPresent()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- var user = new ClaimsPrincipal(
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage", "CanViewAnything");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
new ClaimsIdentity(
- new Claim[] {
- new Claim("Permission", "CanViewComment"),
+ new Claim[] {
+ new Claim("SomethingElse", "CanViewPage"),
},
"Basic")
);
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.False(allowed);
}
[Fact]
- public void Check_ShouldNotAllowIfNoClaims()
+ public async Task Authorize_ShouldNotAllowIfClaimValueIsNotPresent()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- var user = new ClaimsPrincipal(
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim("Permission", "CanViewComment"),
+ },
+ "Basic")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+ [Fact]
+ public async Task Authorize_ShouldNotAllowIfNoClaims()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
new ClaimsIdentity(
new Claim[0],
"Basic")
);
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.False(allowed);
}
[Fact]
- public void Check_ShouldNotAllowIfUserIsNull()
+ public async Task Authorize_ShouldNotAllowIfUserIsNull()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- ClaimsPrincipal user = null;
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext();
+ context.Object.User = null;
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.False(allowed);
}
[Fact]
- public void Check_ShouldNotAllowIfUserIsNotAuthenticated()
+ public async Task Authorize_ShouldNotAllowIfNotCorrectAuthType()
{
// Arrange
- var authorizationService = new DefaultAuthorizationService(Enumerable.Empty());
- var user = new ClaimsPrincipal(
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder("Basic").RequiresClaim("Permission", "CanViewPage");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(new ClaimsIdentity());
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+ [Fact]
+ public async Task Authorize_ShouldAllowWithNoAuthType()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
new ClaimsIdentity(
- new Claim[] {
- new Claim("Permission", "CanViewComment"),
+ new Claim[] {
+ new Claim("Permission", "CanViewPage"),
+ },
+ "Basic")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
+ [Fact]
+ public async Task Authorize_ShouldNotAllowIfUnknownPolicy()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim("Permission", "CanViewComment"),
},
null)
);
// Act
- var allowed = authorizationService.Authorize(new Claim[] { new Claim("Permission", "CanViewPage") }, user);
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
// Assert
Assert.False(allowed);
}
[Fact]
- public void Check_ShouldApplyPoliciesInOrder()
+ public async Task Authorize_CustomRolePolicy()
{
// Arrange
- string result = "";
- var policies = new IAuthorizationPolicy[] {
- new FakePolicy() {
- Order = 20,
- ApplyingAsyncAction = (context) => { result += "20"; }
- },
- new FakePolicy() {
- Order = -1,
- ApplyingAsyncAction = (context) => { result += "-1"; }
- },
- new FakePolicy() {
- Order = 30,
- ApplyingAsyncAction = (context) => { result += "30"; }
- },
- };
-
- var authorizationService = new DefaultAuthorizationService(policies);
-
- // Act
- var allowed = authorizationService.Authorize(Enumerable.Empty(), null);
-
- // Assert
- Assert.Equal("-12030", result);
- }
-
- [Fact]
- public void Check_ShouldInvokeApplyingApplyAppliedInOrder()
- {
- // Arrange
- string result = "";
- var policies = new IAuthorizationPolicy[] {
- new FakePolicy() {
- Order = 20,
- ApplyingAsyncAction = (context) => { result += "Applying20"; },
- ApplyAsyncAction = (context) => { result += "Apply20"; },
- AppliedAsyncAction = (context) => { result += "Applied20"; }
- },
- new FakePolicy() {
- Order = -1,
- ApplyingAsyncAction = (context) => { result += "Applying-1"; },
- ApplyAsyncAction = (context) => { result += "Apply-1"; },
- AppliedAsyncAction = (context) => { result += "Applied-1"; }
- },
- new FakePolicy() {
- Order = 30,
- ApplyingAsyncAction = (context) => { result += "Applying30"; },
- ApplyAsyncAction = (context) => { result += "Apply30"; },
- AppliedAsyncAction = (context) => { result += "Applied30"; }
- },
- };
-
- var authorizationService = new DefaultAuthorizationService(policies);
-
- // Act
- var allowed = authorizationService.Authorize(Enumerable.Empty(), null);
-
- // Assert
- Assert.Equal("Applying-1Applying20Applying30Apply-1Apply20Apply30Applied-1Applied20Applied30", result);
- }
-
- [Fact]
- public void Check_ShouldConvertNullClaimsToEmptyList()
- {
- // Arrange
- IList claims = null;
- var policies = new IAuthorizationPolicy[] {
- new FakePolicy() {
- Order = 20,
- ApplyingAsyncAction = (context) => { claims = context.Claims; }
- }
- };
-
- var authorizationService = new DefaultAuthorizationService(policies);
-
- // Act
- var allowed = authorizationService.Authorize(Enumerable.Empty(), null);
-
- // Assert
- Assert.NotNull(claims);
- Assert.Equal(0, claims.Count);
- }
-
- [Fact]
- public void Check_ShouldThrowWhenPoliciesDontStop()
- {
- // Arrange
- var policies = new IAuthorizationPolicy[] {
- new FakePolicy() {
- ApplyAsyncAction = (context) => { context.Retry = true; }
- }
- };
-
- var authorizationService = new DefaultAuthorizationService(policies);
-
- // Act
- // Assert
- Exception ex = Assert.Throws(() => authorizationService.Authorize(Enumerable.Empty(), null));
- }
-
- [Fact]
- public void Check_ApplyCanMutateCheckedClaims()
- {
-
- // Arrange
- var user = new ClaimsPrincipal(
- new ClaimsIdentity( new Claim[] { new Claim("Permission", "CanDeleteComments") }, "Basic")
+ var policy = new AuthorizationPolicyBuilder().RequiresRole("Administrator")
+ .RequiresClaim(ClaimTypes.Role, "User");
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim(ClaimTypes.Role, "User"),
+ new Claim(ClaimTypes.Role, "Administrator")
+ },
+ "Basic")
);
- var policies = new IAuthorizationPolicy[] {
- new FakePolicy() {
- ApplyAsyncAction = (context) => {
- // for instance, if user owns the comment
- if(!context.Claims.Any(claim => claim.Type == "Permission" && claim.Value == "CanDeleteComments"))
- {
- context.Claims.Add(new Claim("Permission", "CanDeleteComments"));
- context.Retry = true;
- }
- }
- }
- };
-
- var authorizationService = new DefaultAuthorizationService(policies);
-
// Act
- var allowed = authorizationService.Authorize(Enumerable.Empty(), user);
+ var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
// Assert
Assert.True(allowed);
}
[Fact]
- public void Check_PoliciesCanMutateUsersClaims()
+ public async Task Authorize_HasAnyClaimOfTypePolicy()
{
-
// Arrange
- var user = new ClaimsPrincipal(
- new ClaimsIdentity(new Claim[0], "Basic")
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim(ClaimTypes.Role);
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim(ClaimTypes.Role, ""),
+ },
+ "Basic")
);
- var policies = new IAuthorizationPolicy[] {
- new FakePolicy() {
- ApplyAsyncAction = (context) => {
- if (!context.Authorized)
- {
- context.UserClaims.Add(new Claim("Permission", "CanDeleteComments"));
- context.Retry = true;
- }
- }
- }
- };
-
- var authorizationService = new DefaultAuthorizationService(policies);
-
// Act
- var allowed = authorizationService.Authorize(new Claim("Permission", "CanDeleteComments"), user);
+ var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
// Assert
Assert.True(allowed);
}
+
+ [Fact]
+ public async Task Authorize_PolicyCanAuthenticationTypeWithNameClaim()
+ {
+ // Arrange
+ var policy = new AuthorizationPolicyBuilder("AuthType").RequiresClaim(ClaimTypes.Name);
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, "Name") }, "AuthType")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
+ [Fact]
+ public async Task RolePolicyCanRequireSingleRole()
+ {
+ // Arrange
+ var policy = new AuthorizationPolicyBuilder("AuthType").RequiresRole("Admin");
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Role, "Admin") }, "AuthType")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
+ [Fact]
+ public async Task RolePolicyCanRequireOneOfManyRoles()
+ {
+ // Arrange
+ var policy = new AuthorizationPolicyBuilder("AuthType").RequiresRole("Admin", "Users");
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Role, "Users") }, "AuthType"));
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
+ [Fact]
+ public async Task RolePolicyCanBlockWrongRole()
+ {
+ // Arrange
+ var policy = new AuthorizationPolicyBuilder().RequiresClaim("Permission", "CanViewPage");
+ var authorizationService = BuildAuthorizationService();
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim(ClaimTypes.Role, "Nope"),
+ },
+ "AuthType")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync(policy.Build(), context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+ [Fact]
+ public async Task RolePolicyCanBlockNoRole()
+ {
+ // Arrange
+
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequiresRole("Admin", "Users");
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ },
+ "AuthType")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+ [Fact]
+ public async Task PolicyFailsWithNoRequirements()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder();
+ options.AddPolicy("Basic", policy.Build());
+ });
+ });
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim(ClaimTypes.Name, "Name"),
+ },
+ "AuthType")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Basic", context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+ [Fact]
+ public async Task CanApproveAnyAuthenticatedUser()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser();
+ options.AddPolicy("Any", policy.Build());
+ });
+ });
+ var context = SetupContext(
+ new ClaimsIdentity(
+ new Claim[] {
+ new Claim(ClaimTypes.Name, "Name"),
+ },
+ "AuthType")
+ );
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Any", context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
+ [Fact]
+ public async Task CanBlockNonAuthenticatedUser()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser();
+ options.AddPolicy("Any", policy.Build());
+ });
+ });
+ var context = SetupContext(new ClaimsIdentity());
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Any", context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+ public class CustomRequirement : IAuthorizationRequirement { }
+ public class CustomHandler : AuthorizationHandler
+ {
+ public override Task CheckAsync(AuthorizationContext context, CustomRequirement requirement)
+ {
+ return Task.FromResult(true);
+ }
+ }
+
+ [Fact]
+ public async Task CustomReqWithNoHandlerFails()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder();
+ policy.Requirements.Add(new CustomRequirement());
+ options.AddPolicy("Custom", policy.Build());
+ });
+ });
+ var context = SetupContext();
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Custom", context.Object);
+
+ // Assert
+ Assert.False(allowed);
+ }
+
+
+ [Fact]
+ public async Task CustomReqWithHandlerSucceeds()
+ {
+ // Arrange
+ var authorizationService = BuildAuthorizationService(services =>
+ {
+ services.AddTransient();
+ services.Configure(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder();
+ policy.Requirements.Add(new CustomRequirement());
+ options.AddPolicy("Custom", policy.Build());
+ });
+ });
+ var context = SetupContext();
+
+ // Act
+ var allowed = await authorizationService.AuthorizeAsync("Custom", context.Object);
+
+ // Assert
+ Assert.True(allowed);
+ }
+
}
-}
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Security.Test/FakePolicy.cs b/test/Microsoft.AspNet.Security.Test/FakePolicy.cs
deleted file mode 100644
index be9139b89d..0000000000
--- a/test/Microsoft.AspNet.Security.Test/FakePolicy.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.Threading.Tasks;
-using Microsoft.AspNet.Security;
-
-namespace Microsoft.AspNet.Security.Test
-{
- public class FakePolicy : IAuthorizationPolicy
- {
-
- public int Order { get; set; }
-
- public Task ApplyingAsync(AuthorizationPolicyContext context)
- {
- if (ApplyingAsyncAction != null)
- {
- ApplyingAsyncAction(context);
- }
-
- return Task.FromResult(0);
- }
-
- public Task ApplyAsync(AuthorizationPolicyContext context)
- {
- if (ApplyAsyncAction != null)
- {
- ApplyAsyncAction(context);
- }
-
- return Task.FromResult(0);
-
- }
-
- public Task AppliedAsync(AuthorizationPolicyContext context)
- {
- if (AppliedAsyncAction != null)
- {
- AppliedAsyncAction(context);
- }
-
- return Task.FromResult(0);
- }
-
- public Action ApplyingAsyncAction { get; set;}
-
- public Action ApplyAsyncAction { get; set;}
-
- public Action AppliedAsyncAction { get; set;}
- }
-}
diff --git a/test/Microsoft.AspNet.Security.Test/TestApplicationEnvironment.cs b/test/Microsoft.AspNet.Security.Test/TestApplicationEnvironment.cs
deleted file mode 100644
index 01ef364c1d..0000000000
--- a/test/Microsoft.AspNet.Security.Test/TestApplicationEnvironment.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.Runtime.Versioning;
-using Microsoft.Framework.Runtime;
-
-namespace Microsoft.AspNet.Security
-{
- public class TestApplicationEnvironment : IApplicationEnvironment
- {
- public string ApplicationBasePath
- {
- get { return Environment.CurrentDirectory; }
- }
-
- public string ApplicationName
- {
- get { return "Test App environment"; }
- }
-
- public string Configuration
- {
- get { return "Test"; }
- }
-
- public FrameworkName RuntimeFramework
- {
- get { return new FrameworkName(".NETFramework", new Version(4, 5)); }
- }
-
- public string Version
- {
- get { return "1.0.0"; }
- }
- }
-}
\ No newline at end of file