Skip to content

[API Proposal]: AuthorizationPolicyBuilder.RequireClaim overload that take a Func<Claim, bool> #56331

Closed
@joegoldman2

Description

@joegoldman2

Background and Motivation

In many applications, claims-based authorization is a critical component for enforcing security and access controls. The current implementation of AuthorizationPolicyBuilder.RequireClaim (and ClaimsAuthorizationRequirement) is limited to checking claims based on a specific type and value. This restriction can force developers to implement custom claim-checking logic outside the provided methods.

Consider the following scenarios:

  • Pattern Matching: Verifying if a claim value matches a specific pattern or contains a substring.
  • Complex Conditions: Checking for claims where multiple properties need to be considered, such as both type and issuer.

These scenarios highlight the need for a more flexible claim-checking mechanism.

By adding an overload that accepts a Func<Claim, bool>, these kinds of scenarios are easier to implement without additional custom code.

Proposed API

namespace Microsoft.AspNetCore.Authorization;

public partial class AuthorizationPolicyBuilder
{
    // existing
    public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] allowedValues);
    public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable<string> allowedValues);
    public AuthorizationPolicyBuilder RequireClaim(string claimType);

    // new
+   public AuthorizationPolicyBuilder RequireClaim(Func<Claim, bool> match); // alternative name: claimPredicate
}
namespace Microsoft.AspNetCore.Authorization.Infrastructure;

public partial class ClaimsAuthorizationRequirement : AuthorizationHandler<ClaimsAuthorizationRequirement>, IAuthorizationRequirement
{
    // existing
    public ClaimsAuthorizationRequirement(string claimType, IEnumerable<string>? allowedValues)

    // new
+   public ClaimsAuthorizationRequirement(Func<Claim, bool> match) // alternative name: claimPredicate

    // ClaimType can now be null if Func<Claim, bool> is provided
-   public string ClaimType { get; }
+   public string? ClaimType { get; }

    // can also be a private field but considering that ClaimType and AllowedValues are exposed, maybe this value should also be exposed.
+   public Func<Claim, bool>? Match { get; } // alternative name: ClaimPredicate
}

This proposal matches the method ClaimIdentity.HasClaim(Predicate<System.Security.Claims.Claim> match) that already exists in the BCL. I use Func<T, bool> as I saw recent API proposals in the runtime repo recommended to use this instead of Predicate<T> (e.g. dotnet/runtime#107962 (comment)).

Usage Examples

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization(options =>
{
    // Checking if there is any claim that starts with a certain prefix
    options.AddPolicy("prefix", policy => policy.RequireClaim(claim => claim.Value.StartsWith("prefix-"));

    // Checking if there is a claim with type "role" and value containing "admin"
    options.AddPolicy("admin", policy => policy.RequireClaim(claim => claim.Type == "role" && claim.Value.Contains("admin"));
});

Risks

Nothing I can see now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-ready-for-reviewAPI is ready for formal API review - https://github.com/dotnet/apireviewsarea-security

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions