Skip to content

Commit

Permalink
feat: Add aloow anyone option
Browse files Browse the repository at this point in the history
Signed-off-by: Sagilio <Sagilio@outlook.com>
  • Loading branch information
sagilio committed Mar 12, 2021
1 parent 4d9c2e3 commit e5cbe4a
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 54 deletions.
1 change: 1 addition & 0 deletions src/Casbin.AspNetCore.Core/CasbinAuthorizationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public class CasbinAuthorizationOptions
public Func<IServiceProvider, Model?, Enforcer>? DefaultEnforcerFactory { get; set; }
public string PreferSubClaimType { get; set; } = ClaimTypes.NameIdentifier;
public IRequestTransformer? DefaultRequestTransformer { get; set; }
public bool AllowAnyone { get; set; } = false;
}
}
5 changes: 2 additions & 3 deletions src/Casbin.AspNetCore/Abstractions/ICasbinEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ namespace Casbin.AspNetCore.Authorization
{
public interface ICasbinEvaluator
{
public Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy authorizationPolicy,
AuthenticateResult authenticationResult, HttpContext context,
ICasbinAuthorizationContext casbinContext, object? resource);
public Task<PolicyAuthorizationResult> AuthorizeAsync(ICasbinAuthorizationContext casbinContext,
AuthorizationPolicy policy, AuthenticateResult? authenticationResult = null);
}
}
2 changes: 1 addition & 1 deletion src/Casbin.AspNetCore/Casbin.AspNetCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<OutputType>Library</OutputType>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<Nullable>enable</Nullable>
<LangVersion>8.0</LangVersion>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<PropertyGroup>
Expand Down
56 changes: 24 additions & 32 deletions src/Casbin.AspNetCore/CasbinAuthorizationMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace Casbin.AspNetCore.Authorization
{
public class CasbinAuthorizationMiddleware
{
// AppContext switch used to control whether HttpContext or endpoint is passed as a resource to AuthZ
private const string SuppressUseHttpContextAsAuthorizationResource = "Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource";

// Property key is used by Endpoint routing to determine if Authorization has run
private const string AuthorizationMiddlewareInvokedWithEndpointKey = "__AuthorizationMiddlewareWithEndpointInvoked";
private static readonly object _authorizationMiddlewareWithEndpointInvokedValue = new object();
private const string s_casbinAuthorizationMiddlewareInvokedWithEndpointKey = "__CasbinAuthorizationMiddlewareWithEndpointInvoked";
private static readonly object s_casbinAuthorizationMiddlewareWithEndpointInvokedValue = new();

private readonly RequestDelegate _next;
private readonly ICasbinPolicyCreator _policyCreator;
private readonly IOptions<CasbinAuthorizationOptions> _options;

public CasbinAuthorizationMiddleware(RequestDelegate next, ICasbinPolicyCreator policyCreator)
public CasbinAuthorizationMiddleware(RequestDelegate next, ICasbinPolicyCreator policyCreator, IOptions<CasbinAuthorizationOptions> options)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_policyCreator = policyCreator ?? throw new ArgumentNullException(nameof(policyCreator)); ;
_policyCreator = policyCreator ?? throw new ArgumentNullException(nameof(policyCreator));
_options = options ?? throw new ArgumentNullException(nameof(options));
}

public async Task Invoke(HttpContext context)
Expand All @@ -34,12 +33,9 @@ public async Task Invoke(HttpContext context)
}

var endpoint = context.GetEndpoint();

if (endpoint != null)
if (endpoint is not null)
{
// EndpointRoutingMiddleware uses this flag to check if the Authorization middleware processed auth metadata on the endpoint.
// The Authorization middleware can only make this claim if it observes an actual endpoint.
context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = _authorizationMiddlewareWithEndpointInvokedValue;
context.Items[s_casbinAuthorizationMiddlewareInvokedWithEndpointKey] = s_casbinAuthorizationMiddlewareWithEndpointInvokedValue;
}

// IMPORTANT: Changes to authorization logic should be mirrored in MVC's AuthorizeFilter
Expand All @@ -51,33 +47,29 @@ public async Task Invoke(HttpContext context)
return;
}


// Policy evaluator has transient lifetime so it fetched from request services instead of injecting in constructor
var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();

bool allowAnyone = _options.Value.AllowAnyone;
var policy = _policyCreator.Create(authorizeData);
var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);

// Allow Anonymous skips all authorization
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
AuthenticateResult? authenticateResult = null;
if (allowAnyone is false)
{
await _next(context);
return;
// Policy evaluator has transient lifetime so it fetched from request services instead of injecting in constructor
var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();
authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);
}

object? resource;
if (AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource, out bool useEndpointAsResource) && useEndpointAsResource)
{
resource = endpoint;
}
else
// Allow Anonymous skips all authorization
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() is not null)
{
resource = context;
await _next(context);
return;
}

var casbinContext = context.RequestServices.GetRequiredService<ICasbinAuthorizationContextFactory>().CreateContext(authorizeData, context);
var casbinAuthorizationContextFactory = context.RequestServices.GetRequiredService<ICasbinAuthorizationContextFactory>();
var casbinAuthorizationContext = casbinAuthorizationContextFactory.CreateContext(authorizeData, context);

var authorizeResult = await context.RequestServices.GetRequiredService<ICasbinEvaluator>().AuthorizeAsync(policy, authenticateResult, context, casbinContext, resource);
var casbinEvaluator = context.RequestServices.GetRequiredService<ICasbinEvaluator>();
var authorizeResult = await casbinEvaluator.AuthorizeAsync(casbinAuthorizationContext, policy, authenticateResult);

var authorizationMiddlewareResultHandler = context.RequestServices.GetRequiredService<ICasbinAuthorizationMiddlewareResultHandler>();
await authorizationMiddlewareResultHandler.HandleAsync(_next, context, policy, authorizeResult);
Expand Down
17 changes: 10 additions & 7 deletions src/Casbin.AspNetCore/CasbinEvaluator.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Threading.Tasks;
using Casbin.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;

namespace Casbin.AspNetCore.Authorization
{
Expand All @@ -16,26 +16,29 @@ public CasbinEvaluator(IAuthorizationService authorizationService)
_authorizationService = authorizationService;
}

public async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy,
AuthenticateResult authenticationResult, HttpContext context,
ICasbinAuthorizationContext casbinContext, object? resource)
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(ICasbinAuthorizationContext casbinContext, AuthorizationPolicy policy, AuthenticateResult? authenticationResult = null)
{
if (policy == null)
if (policy is null)
{
throw new ArgumentNullException(nameof(policy));
}

if (casbinContext == null)
if (casbinContext is null)
{
throw new ArgumentNullException(nameof(casbinContext));
}

var result = await _authorizationService.AuthorizeAsync(context.User, casbinContext, policy);
var result = await _authorizationService.AuthorizeAsync(casbinContext.HttpContext.User, casbinContext, policy);
if (result.Succeeded)
{
return PolicyAuthorizationResult.Success();
}

if (authenticationResult is null)
{
return PolicyAuthorizationResult.Forbid();
}

// If authentication was successful, return forbidden, otherwise challenge
return authenticationResult.Succeeded
? PolicyAuthorizationResult.Forbid()
Expand Down
2 changes: 1 addition & 1 deletion src/Casbin.AspNetCore/Policy/CasbinPolicyCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public AuthorizationPolicy Create(IEnumerable<ICasbinAuthorizationData> authoriz
IList<string>? authenticationSchemes = null;
foreach (var data in authorizationData)
{
var authTypesSplit = data.AuthenticationSchemes?.Split(',');
string[]? authTypesSplit = data.AuthenticationSchemes?.Split(',');
if (authTypesSplit is null || authTypesSplit.Length > 0 is false)
{
return _emptyPolicy;
Expand Down
17 changes: 7 additions & 10 deletions test/Casbin.AspNetCore.Tests/CasbinEvaluatorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class CasbinEvaluatorTest : IClassFixture<TestServerFixture>
private readonly IServiceProvider _serviceProvider;
private readonly ICasbinPolicyCreator _casbinPolicyCreator;
private readonly ICasbinAuthorizationContextFactory _casbinAuthorizationContextFactory;
private const string _defaultScheme = "context.User";
private const string s_defaultScheme = "context.User";

public CasbinEvaluatorTest(TestServerFixture testServerFixture)
{
Expand Down Expand Up @@ -48,11 +48,10 @@ public async Task ShouldBasicAuthorizeAsync(
var casbinContext = _casbinAuthorizationContextFactory.CreateContext(
new CasbinAuthorizeAttribute(resource, action), httpContext);
var policy = _casbinPolicyCreator.Create(casbinContext.AuthorizationData);
var result = AuthenticateResult.Success(new AuthenticationTicket(httpContext.User, _defaultScheme));
var result = AuthenticateResult.Success(new AuthenticationTicket(httpContext.User, s_defaultScheme));

// Act
var authorizationResult = await casbinEvaluator.AuthorizeAsync(
policy, result, httpContext, casbinContext, httpContext);
var authorizationResult = await casbinEvaluator.AuthorizeAsync(casbinContext, policy, result);

// Assert
Assert.Equal(expectResult, authorizationResult.Succeeded);
Expand Down Expand Up @@ -82,11 +81,10 @@ public async Task ShouldBasicAuthorizeWhenSpecIssuerAsync(
var casbinContext = _casbinAuthorizationContextFactory.CreateContext(
new CasbinAuthorizeAttribute(resource, action) { Issuer = testIssuer }, httpContext);
var policy = _casbinPolicyCreator.Create(casbinContext.AuthorizationData);
var result = AuthenticateResult.Success(new AuthenticationTicket(httpContext.User, _defaultScheme));
var result = AuthenticateResult.Success(new AuthenticationTicket(httpContext.User, s_defaultScheme));

// Act
var authorizationResult = await casbinEvaluator.AuthorizeAsync(
policy, result, httpContext, casbinContext, httpContext);
var authorizationResult = await casbinEvaluator.AuthorizeAsync(casbinContext, policy, result);

// Assert
Assert.Equal(expectResult, authorizationResult.Succeeded);
Expand Down Expand Up @@ -115,11 +113,10 @@ public async Task ShouldBasicAuthorizeWhenSpecSubClaimTypeAsync(
new CasbinAuthorizeAttribute(resource, action) { PreferSubClaimType = testClaimType },
httpContext);
var policy = _casbinPolicyCreator.Create(casbinContext.AuthorizationData);
var result = AuthenticateResult.Success(new AuthenticationTicket(httpContext.User, _defaultScheme));
var result = AuthenticateResult.Success(new AuthenticationTicket(httpContext.User, s_defaultScheme));

// Act
var authorizationResult = await casbinEvaluator.AuthorizeAsync(
policy, result, httpContext, casbinContext, httpContext);
var authorizationResult = await casbinEvaluator.AuthorizeAsync(casbinContext, policy, result);

// Assert
Assert.Equal(expectResult ,authorizationResult.Succeeded);
Expand Down

0 comments on commit e5cbe4a

Please sign in to comment.