Adding AuthorizationPolicy and mutable user claims

#13
This commit is contained in:
Sebastien Ros 2014-05-05 14:29:13 -07:00
parent c64934ad53
commit b7ed0faa33
5 changed files with 161 additions and 2 deletions

View File

@ -0,0 +1,46 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Security.Authorization
{
/// <summary>
/// This class provides a base implementation for <see cref="IAuthorizationPolicy" />
/// </summary>
public abstract class AuthorizationPolicy : IAuthorizationPolicy
{
public int Order { get; set; }
public virtual Task ApplyingAsync(AuthorizationPolicyContext context)
{
return Task.FromResult(0);
}
public virtual Task ApplyAsync(AuthorizationPolicyContext context)
{
return Task.FromResult(0);
}
public virtual Task AppliedAsync(AuthorizationPolicyContext context)
{
return Task.FromResult(0);
}
}
}

View File

@ -16,6 +16,11 @@ namespace Microsoft.AspNet.Security.Authorization
Claims = (claims ?? Enumerable.Empty<Claim>()).ToList();
User = user;
Resource = resource;
// user claims are copied to a new and mutable list
UserClaims = user != null
? user.Claims.ToList()
: new List<Claim>();
}
/// <summary>
@ -28,6 +33,14 @@ namespace Microsoft.AspNet.Security.Authorization
/// </summary>
public ClaimsPrincipal User { get; private set; }
/// <summary>
/// The claims of the user.
/// </summary>
/// <remarks>
/// This list can be modified by policies for retries.
/// </remarks>
public IList<Claim> UserClaims { get; private set; }
/// <summary>
/// An optional resource associated to the check.
/// </summary>

View File

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 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.Authorization
{
public static class AuthorizationServiceExtensions
{
/// <summary>
/// Checks if a user has specific claims.
/// </summary>
/// <param name="claim">The claim to check against a specific user.</param>
/// <param name="user">The user to check claims against.</param>
/// <returns><value>true</value> when the user fulfills one of the claims, <value>false</value> otherwise.</returns>
public static Task<bool> AuthorizeAsync(this IAuthorizationService service, Claim claim, ClaimsPrincipal user)
{
return service.AuthorizeAsync(new Claim[] { claim }, user);
}
/// <summary>
/// Checks if a user has specific claims.
/// </summary>
/// <param name="claim">The claim to check against a specific user.</param>
/// <param name="user">The user to check claims against.</param>
/// <returns><value>true</value> when the user fulfills one of the claims, <value>false</value> otherwise.</returns>
public static bool Authorize(this IAuthorizationService service, Claim claim, ClaimsPrincipal user)
{
return service.Authorize(new Claim[] { claim }, user);
}
/// <summary>
/// Checks if a user has specific claims for a specific context obj.
/// </summary>
/// <param name="claim">The claim to check against a specific user.</param>
/// <param name="user">The user to check claims against.</param>
/// <param name="resource">The resource the claims should be check with.</param>
/// <returns><value>true</value> when the user fulfills one of the claims, <value>false</value> otherwise.</returns>
public static Task<bool> AuthorizeAsync(this IAuthorizationService service, Claim claim, ClaimsPrincipal user, object resource)
{
return service.AuthorizeAsync(new Claim[] { claim }, user, resource);
}
/// <summary>
/// Checks if a user has specific claims for a specific context obj.
/// </summary>
/// <param name="claim">The claimsto check against a specific user.</param>
/// <param name="user">The user to check claims against.</param>
/// <param name="resource">The resource the claims should be check with.</param>
/// <returns><value>true</value> when the user fulfills one of the claims, <value>false</value> otherwise.</returns>
public static bool Authorize(this IAuthorizationService service, Claim claim, ClaimsPrincipal user, object resource)
{
return service.Authorize(new Claim[] { claim }, user, resource);
}
}
}

View File

@ -55,7 +55,7 @@ namespace Microsoft.AspNet.Security.Authorization
{
if (context.User != null)
{
if (context.Claims.Any(claim => user.HasClaim(claim.Type, claim.Value)))
if (ClaimsMatch(context.Claims, context.UserClaims))
{
context.Authorized = true;
}
@ -95,5 +95,16 @@ namespace Microsoft.AspNet.Security.Authorization
{
return AuthorizeAsync(claims, user, resource).Result;
}
private bool ClaimsMatch([NotNull] IEnumerable<Claim> x, [NotNull] IEnumerable<Claim> y)
{
return x.Any(claim =>
y.Any(userClaim =>
string.Equals(claim.Type, userClaim.Type, StringComparison.OrdinalIgnoreCase) &&
string.Equals(claim.Value, userClaim.Value, StringComparison.Ordinal)
)
);
}
}
}

View File

@ -243,7 +243,7 @@ namespace Microsoft.AspNet.Security.Test
}
[Fact]
public void Check_ApplyCanMutateClaims()
public void Check_ApplyCanMutateCheckedClaims()
{
// Arrange
@ -272,5 +272,35 @@ namespace Microsoft.AspNet.Security.Test
// Assert
Assert.True(allowed);
}
[Fact]
public void Check_PoliciesCanMutateUsersClaims()
{
// Arrange
var user = new ClaimsPrincipal(
new ClaimsIdentity(new Claim[0], "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);
// Assert
Assert.True(allowed);
}
}
}