From d42c05b6b2dc3e04244c522435505f62bb1de5f0 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:28:09 +0000 Subject: [PATCH 1/4] Add `AuthorizationPolicyBuilder.RequireClaim` overload that take a `Predicate` --- .../Core/src/AuthorizationPolicyBuilder.cs | 15 +++++++ .../src/ClaimsAuthorizationRequirement.cs | 35 +++++++++++++++- .../PublicAPI/net462/PublicAPI.Unshipped.txt | 5 +++ .../PublicAPI/net9.0/PublicAPI.Unshipped.txt | 5 +++ .../netstandard2.0/PublicAPI.Unshipped.txt | 5 +++ .../ClaimsAuthorizationRequirementTests.cs | 30 ++++++++++--- .../test/DefaultAuthorizationServiceTests.cs | 42 +++++++++++++++++++ 7 files changed, 130 insertions(+), 7 deletions(-) diff --git a/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs b/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs index 369145a52ead..a86fdac6bc71 100644 --- a/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs +++ b/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization.Infrastructure; using Microsoft.AspNetCore.Shared; @@ -141,6 +142,20 @@ public AuthorizationPolicyBuilder RequireClaim(string claimType) return this; } + /// + /// Adds a to the current instance which requires + /// that the current user has a claim that satisfies the specified predicate. + /// + /// The predicate to evaluate the claims. + /// A reference to this instance after the operation has completed. + public AuthorizationPolicyBuilder RequireClaim(Predicate match) + { + ArgumentNullThrowHelper.ThrowIfNull(match); + + Requirements.Add(new ClaimsAuthorizationRequirement(match)); + return this; + } + /// /// Adds a to the current instance which enforces that the current user /// must have at least one of the specified roles. diff --git a/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs b/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs index 55ae9b5f0445..1be103edad7e 100644 --- a/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs +++ b/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Shared; @@ -32,10 +33,22 @@ public ClaimsAuthorizationRequirement(string claimType, IEnumerable? all _emptyAllowedValues = AllowedValues == null || !AllowedValues.Any(); } + /// + /// Creates a new instance of . + /// + /// The predicate to evaluate the claims. + public ClaimsAuthorizationRequirement(Predicate match) + { + ArgumentNullThrowHelper.ThrowIfNull(match); + + Match = match; + _emptyAllowedValues = true; + } + /// /// Gets the claim type that must be present. /// - public string ClaimType { get; } + public string? ClaimType { get; } /// /// Gets the optional list of claim values, which, if present, @@ -43,6 +56,12 @@ public ClaimsAuthorizationRequirement(string claimType, IEnumerable? all /// public IEnumerable? AllowedValues { get; } + /// + /// A predicate to evaluate the claims. + /// Used if specified instead of and . + /// + public Predicate? Match { get; } + /// /// Makes a decision if authorization is allowed based on the claims requirements specified. /// @@ -53,7 +72,12 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte if (context.User != null) { var found = false; - if (requirement._emptyAllowedValues) + + if (requirement.Match != null) + { + found = context.User.HasClaim(requirement.Match); + } + else if (requirement._emptyAllowedValues) { foreach (var claim in context.User.Claims) { @@ -76,17 +100,24 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte } } } + if (found) { context.Succeed(requirement); } } + return Task.CompletedTask; } /// public override string ToString() { + if (Match != null) + { + return $"{nameof(ClaimsAuthorizationRequirement)}:Evaluates using a custom predicate"; + } + var value = (_emptyAllowedValues) ? string.Empty : $" and Claim.Value is one of the following values: ({string.Join("|", AllowedValues!)})"; diff --git a/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt index 7dc5c58110bf..e1d1c1f3b51d 100644 --- a/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt +++ b/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Predicate! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Predicate! match) -> void +*REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Predicate? diff --git a/src/Security/Authorization/Core/src/PublicAPI/net9.0/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI/net9.0/PublicAPI.Unshipped.txt index 7dc5c58110bf..e1d1c1f3b51d 100644 --- a/src/Security/Authorization/Core/src/PublicAPI/net9.0/PublicAPI.Unshipped.txt +++ b/src/Security/Authorization/Core/src/PublicAPI/net9.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Predicate! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Predicate! match) -> void +*REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Predicate? diff --git a/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 7dc5c58110bf..e1d1c1f3b51d 100644 --- a/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Predicate! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Predicate! match) -> void +*REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Predicate? diff --git a/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs b/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs index 365c63c1ee90..dd8f6d34a404 100644 --- a/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs +++ b/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs @@ -1,17 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Security.Claims; using Microsoft.AspNetCore.Authorization.Infrastructure; namespace Microsoft.AspNetCore.Authorization.Test; public class ClaimsAuthorizationRequirementTests { - public ClaimsAuthorizationRequirement CreateRequirement(string claimType, params string[] allowedValues) - { - return new ClaimsAuthorizationRequirement(claimType, allowedValues); - } - [Fact] public void ToString_ShouldReturnAndDescriptionWhenAllowedValuesNotNull() { @@ -50,4 +46,28 @@ public void ToString_ShouldReturnWithoutAllowedDescriptionWhenAllowedValuesIsEmp // Assert Assert.Equal("ClaimsAuthorizationRequirement:Claim.Type=Custom", formattedValue); } + + [Fact] + public void ToString_ShouldReturnPredicateDescriptionWhenPredicateIsUsed() + { + // Arrange + Predicate claimPredicate = claim => claim.Type == "Permissions" && claim.Value.Contains("CanViewPage"); + var requirement = CreateRequirement(claimPredicate); + + // Act + var formattedValue = requirement.ToString(); + + // Assert + Assert.Equal("ClaimsAuthorizationRequirement:Evaluates using a custom predicate", formattedValue); + } + + private ClaimsAuthorizationRequirement CreateRequirement(string claimType, params string[] allowedValues) + { + return new ClaimsAuthorizationRequirement(claimType, allowedValues); + } + + private ClaimsAuthorizationRequirement CreateRequirement(Predicate match) + { + return new ClaimsAuthorizationRequirement(match); + } } diff --git a/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs b/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs index fcab4e0388b1..a87c3f556a48 100644 --- a/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs +++ b/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs @@ -90,6 +90,27 @@ public async Task Authorize_ShouldAllowIfClaimIsAmongValues() Assert.True(allowed.Succeeded); } + [Fact] + public async Task Authorize_ShouldAllowIfClaimMatchesPredicate() + { + // Arrange + var authorizationService = BuildAuthorizationService(services => + { + services.AddAuthorizationBuilder().AddPolicy("Basic", policy => + { + policy.AddAuthenticationSchemes("Basic"); + policy.RequireClaim(claim => claim.Type == "Permission" && claim.Value == "CanViewPage"); + }); + }); + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic")); + + // Act + var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); + + // Assert + Assert.True(allowed.Succeeded); + } + [Fact] public async Task Authorize_ShouldInvokeAllHandlersByDefault() { @@ -260,6 +281,27 @@ public async Task Authorize_ShouldNotAllowIfClaimValueIsNotPresent() Assert.False(allowed.Succeeded); } + [Fact] + public async Task Authorize_ShouldNotAllowIfClaimDoesNotMatchPredicate() + { + // Arrange + var authorizationService = BuildAuthorizationService(services => + { + services.AddAuthorizationBuilder().AddPolicy("Basic", policy => + { + policy.AddAuthenticationSchemes("Basic"); + policy.RequireClaim(claim => claim.Type == "Permission" && claim.Value == "CanViewAnything"); + }); + }); + var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic")); + + // Act + var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); + + // Assert + Assert.False(allowed.Succeeded); + } + [Fact] public async Task Authorize_ShouldNotAllowIfNoClaims() { From d114f360ad57a43b416a69a7e8728cc0831efd4b Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman@users.noreply.github.com> Date: Thu, 20 Jun 2024 21:09:41 +0000 Subject: [PATCH 2/4] Remove leading spaces --- .../Authorization/Core/src/ClaimsAuthorizationRequirement.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs b/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs index 1be103edad7e..b72c7023421f 100644 --- a/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs +++ b/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs @@ -57,8 +57,8 @@ public ClaimsAuthorizationRequirement(Predicate match) public IEnumerable? AllowedValues { get; } /// - /// A predicate to evaluate the claims. - /// Used if specified instead of and . + /// A predicate to evaluate the claims. + /// Used if specified instead of and . /// public Predicate? Match { get; } From 4d81728396c9cd5698ff7aef795d82ef7889bc6a Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:26:20 +0000 Subject: [PATCH 3/4] Replace Predicate with Func --- .../Authorization/Core/src/AuthorizationPolicyBuilder.cs | 2 +- .../Core/src/ClaimsAuthorizationRequirement.cs | 6 +++--- .../Core/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt | 5 +++++ .../Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt | 6 +++--- .../src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt | 6 +++--- .../test/ClaimsAuthorizationRequirementTests.cs | 6 +++--- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs b/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs index a86fdac6bc71..5c41ede9a03e 100644 --- a/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs +++ b/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs @@ -148,7 +148,7 @@ public AuthorizationPolicyBuilder RequireClaim(string claimType) /// /// The predicate to evaluate the claims. /// A reference to this instance after the operation has completed. - public AuthorizationPolicyBuilder RequireClaim(Predicate match) + public AuthorizationPolicyBuilder RequireClaim(Func match) { ArgumentNullThrowHelper.ThrowIfNull(match); diff --git a/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs b/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs index b72c7023421f..b5e75d9b7fcf 100644 --- a/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs +++ b/src/Security/Authorization/Core/src/ClaimsAuthorizationRequirement.cs @@ -37,7 +37,7 @@ public ClaimsAuthorizationRequirement(string claimType, IEnumerable? all /// Creates a new instance of . /// /// The predicate to evaluate the claims. - public ClaimsAuthorizationRequirement(Predicate match) + public ClaimsAuthorizationRequirement(Func match) { ArgumentNullThrowHelper.ThrowIfNull(match); @@ -60,7 +60,7 @@ public ClaimsAuthorizationRequirement(Predicate match) /// A predicate to evaluate the claims. /// Used if specified instead of and . /// - public Predicate? Match { get; } + public Func? Match { get; } /// /// Makes a decision if authorization is allowed based on the claims requirements specified. @@ -75,7 +75,7 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte if (requirement.Match != null) { - found = context.User.HasClaim(requirement.Match); + found = context.User.HasClaim(new Predicate(requirement.Match)); } else if (requirement._emptyAllowedValues) { diff --git a/src/Security/Authorization/Core/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt index 7dc5c58110bf..f5b5801bf502 100644 --- a/src/Security/Authorization/Core/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt +++ b/src/Security/Authorization/Core/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Func! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Func! match) -> void +*REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Func? diff --git a/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt index e1d1c1f3b51d..f5b5801bf502 100644 --- a/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt +++ b/src/Security/Authorization/Core/src/PublicAPI/net462/PublicAPI.Unshipped.txt @@ -1,6 +1,6 @@ #nullable enable -Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Predicate! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Predicate! match) -> void +Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Func! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Func! match) -> void *REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Predicate? +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Func? diff --git a/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index e1d1c1f3b51d..f5b5801bf502 100644 --- a/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Security/Authorization/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,6 +1,6 @@ #nullable enable -Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Predicate! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Predicate! match) -> void +Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Func! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Func! match) -> void *REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Predicate? +Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Func? diff --git a/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs b/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs index dd8f6d34a404..0b63931523cc 100644 --- a/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs +++ b/src/Security/Authorization/test/ClaimsAuthorizationRequirementTests.cs @@ -51,8 +51,8 @@ public void ToString_ShouldReturnWithoutAllowedDescriptionWhenAllowedValuesIsEmp public void ToString_ShouldReturnPredicateDescriptionWhenPredicateIsUsed() { // Arrange - Predicate claimPredicate = claim => claim.Type == "Permissions" && claim.Value.Contains("CanViewPage"); - var requirement = CreateRequirement(claimPredicate); + Func match = claim => claim.Type == "Permissions" && claim.Value.Contains("CanViewPage"); + var requirement = CreateRequirement(match); // Act var formattedValue = requirement.ToString(); @@ -66,7 +66,7 @@ private ClaimsAuthorizationRequirement CreateRequirement(string claimType, param return new ClaimsAuthorizationRequirement(claimType, allowedValues); } - private ClaimsAuthorizationRequirement CreateRequirement(Predicate match) + private ClaimsAuthorizationRequirement CreateRequirement(Func match) { return new ClaimsAuthorizationRequirement(match); } From d7f595ee68ce45440115ac826685fa8bb098b91c Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:57:15 +0000 Subject: [PATCH 4/4] Undo PublicAPI.Unshipped.txt --- .../src/PublicAPI/net10.0/PublicAPI.Unshipped.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/SignalR/common/SignalR.Common/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt b/src/SignalR/common/SignalR.Common/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt index e1d1c1f3b51d..7dc5c58110bf 100644 --- a/src/SignalR/common/SignalR.Common/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt +++ b/src/SignalR/common/SignalR.Common/src/PublicAPI/net10.0/PublicAPI.Unshipped.txt @@ -1,6 +1 @@ #nullable enable -Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireClaim(System.Predicate! match) -> Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder! -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimsAuthorizationRequirement(System.Predicate! match) -> void -*REMOVED*Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string! -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.ClaimType.get -> string? -Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement.Match.get -> System.Predicate?