/* * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * See https://github.com/openiddict/openiddict-core for more information concerning * the license and the contributors participating to this project. */ using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; using System.Security.Claims; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; using Microsoft.Extensions.Primitives; namespace OpenIddict.Abstractions; /// /// Provides extension methods to make /// and easier to work with. /// public static class OpenIddictExtensions { /// /// Extracts the authentication context class values from an . /// /// The instance. public static ImmutableArray GetAcrValues(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return GetValues(request.AcrValues, Separators.Space); } /// /// Extracts the prompt values from an . /// /// The instance. public static ImmutableArray GetPrompts(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return GetValues(request.Prompt, Separators.Space); } /// /// Extracts the response types from an . /// /// The instance. public static ImmutableArray GetResponseTypes(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return GetValues(request.ResponseType, Separators.Space); } /// /// Extracts the scopes from an . /// /// The instance. public static ImmutableArray GetScopes(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return GetValues(request.Scope, Separators.Space); } /// /// Determines whether the requested authentication context class values contain the specified item. /// /// The instance. /// The component to look for in the parameter. public static bool HasAcrValue(this OpenIddictRequest request, string value) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(value)) { throw new ArgumentException(SR.GetResourceString(SR.ID0177), nameof(value)); } return HasValue(request.AcrValues, value, Separators.Space); } /// /// Determines whether the requested prompt contains the specified value. /// /// The instance. /// The component to look for in the parameter. public static bool HasPrompt(this OpenIddictRequest request, string prompt) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(prompt)) { throw new ArgumentException(SR.GetResourceString(SR.ID0178), nameof(prompt)); } return HasValue(request.Prompt, prompt, Separators.Space); } /// /// Determines whether the requested response type contains the specified value. /// /// The instance. /// The component to look for in the parameter. public static bool HasResponseType(this OpenIddictRequest request, string type) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0179), nameof(type)); } return HasValue(request.ResponseType, type, Separators.Space); } /// /// Determines whether the requested scope contains the specified value. /// /// The instance. /// The component to look for in the parameter. public static bool HasScope(this OpenIddictRequest request, string scope) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(scope)) { throw new ArgumentException(SR.GetResourceString(SR.ID0180), nameof(scope)); } return HasValue(request.Scope, scope, Separators.Space); } /// /// Determines whether the "response_type" parameter corresponds to the "none" response type. /// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#none for more information. /// /// The instance. /// if the request is a response_type=none request, otherwise. public static bool IsNoneFlow(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(request.ResponseType)) { return false; } var segment = Trim(new StringSegment(request.ResponseType), Separators.Space); if (!segment.HasValue || segment.Length is 0) { return false; } return segment.Equals(ResponseTypes.None, StringComparison.Ordinal); } /// /// Determines whether the "response_type" parameter corresponds to the authorization code flow. /// See http://tools.ietf.org/html/rfc6749#section-4.1.1 for more information. /// /// The instance. /// if the request is a code flow request, otherwise. public static bool IsAuthorizationCodeFlow(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(request.ResponseType)) { return false; } var segment = Trim(new StringSegment(request.ResponseType), Separators.Space); if (!segment.HasValue || segment.Length is 0) { return false; } return segment.Equals(ResponseTypes.Code, StringComparison.Ordinal); } /// /// Determines whether the "response_type" parameter corresponds to the implicit flow. /// See http://tools.ietf.org/html/rfc6749#section-4.2.1 and /// http://openid.net/specs/openid-connect-core-1_0.html for more information /// /// The instance. /// if the request is an implicit flow request, otherwise. public static bool IsImplicitFlow(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(request.ResponseType)) { return false; } var flags = /* none: */ 0x00; foreach (var element in new StringTokenizer(request.ResponseType, Separators.Space)) { var segment = Trim(element, Separators.Space); if (!segment.HasValue || segment.Length is 0) { continue; } if (segment.Equals(ResponseTypes.IdToken, StringComparison.Ordinal)) { flags |= /* id_token: */ 0x01; continue; } // Note: though the OIDC core specs does not include the OAuth 2.0-inherited response_type=token, // it is considered as a valid response_type for the implicit flow for backward compatibility. else if (segment.Equals(ResponseTypes.Token, StringComparison.Ordinal)) { flags |= /* token */ 0x02; continue; } // Always return false if the response_type item // is not a valid component for the implicit flow. return false; } // Return true if the response_type parameter contains "id_token" or "token". return (flags & /* id_token: */ 0x01) == 0x01 || (flags & /* token: */ 0x02) == 0x02; } /// /// Determines whether the "response_type" parameter corresponds to the hybrid flow. /// See http://tools.ietf.org/html/rfc6749#section-4.2.1 and /// http://openid.net/specs/openid-connect-core-1_0.html for more information. /// /// The instance. /// if the request is an hybrid flow request, otherwise. public static bool IsHybridFlow(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(request.ResponseType)) { return false; } var flags = /* none */ 0x00; foreach (var element in new StringTokenizer(request.ResponseType, Separators.Space)) { var segment = Trim(element, Separators.Space); if (!segment.HasValue || segment.Length is 0) { continue; } if (segment.Equals(ResponseTypes.Code, StringComparison.Ordinal)) { flags |= /* code: */ 0x01; continue; } else if (segment.Equals(ResponseTypes.IdToken, StringComparison.Ordinal)) { flags |= /* id_token: */ 0x02; continue; } else if (segment.Equals(ResponseTypes.Token, StringComparison.Ordinal)) { flags |= /* token: */ 0x04; continue; } // Always return false if the response_type item // is not a valid component for the hybrid flow. return false; } // Return false if the response_type parameter doesn't contain "code". if ((flags & /* code: */ 0x01) != 0x01) { return false; } // Return true if the response_type parameter contains "id_token" or "token". return (flags & /* id_token: */ 0x02) == 0x02 || (flags & /* token: */ 0x04) == 0x04; } /// /// Determines whether the "response_mode" parameter corresponds to the fragment response mode. /// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html for more information. /// /// The instance. /// /// if the request specified the fragment response mode or if /// it's the default value for the requested flow, otherwise. /// public static bool IsFragmentResponseMode(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.Equals(request.ResponseMode, ResponseModes.Fragment, StringComparison.Ordinal)) { return true; } // Don't guess the response_mode value // if an explicit value has been provided. if (!string.IsNullOrEmpty(request.ResponseMode)) { return false; } // Both the implicit and the hybrid flows // use response_mode=fragment by default. return request.IsImplicitFlow() || request.IsHybridFlow(); } /// /// Determines whether the "response_mode" parameter corresponds to the query response mode. /// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html for more information. /// /// The instance. /// /// if the request specified the query response mode or if /// it's the default value for the requested flow, otherwise. /// public static bool IsQueryResponseMode(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.Equals(request.ResponseMode, ResponseModes.Query, StringComparison.Ordinal)) { return true; } // Don't guess the response_mode value // if an explicit value has been provided. if (!string.IsNullOrEmpty(request.ResponseMode)) { return false; } // Code flow and "response_type=none" use response_mode=query by default. return request.IsAuthorizationCodeFlow() || request.IsNoneFlow(); } /// /// Determines whether the "response_mode" parameter corresponds to the form post response mode. /// See http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html for more information. /// /// The instance. /// /// if the request specified the form post response mode or if /// it's the default value for the requested flow, otherwise. /// public static bool IsFormPostResponseMode(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return string.Equals(request.ResponseMode, ResponseModes.FormPost, StringComparison.Ordinal); } /// /// Determines whether the "grant_type" parameter corresponds to the authorization code grant. /// See http://tools.ietf.org/html/rfc6749#section-4.1.3 for more information. /// /// The instance. /// if the request is a code grant request, otherwise. public static bool IsAuthorizationCodeGrantType(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return string.Equals(request.GrantType, GrantTypes.AuthorizationCode, StringComparison.Ordinal); } /// /// Determines whether the "grant_type" parameter corresponds to the client credentials grant. /// See http://tools.ietf.org/html/rfc6749#section-4.4.2 for more information. /// /// The instance. /// if the request is a client credentials grant request, otherwise. public static bool IsClientCredentialsGrantType(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return string.Equals(request.GrantType, GrantTypes.ClientCredentials, StringComparison.Ordinal); } /// /// Determines whether the "grant_type" parameter corresponds to the device code grant. /// See https://tools.ietf.org/html/rfc8628 for more information. /// /// The instance. /// if the request is a device code grant request, otherwise. public static bool IsDeviceCodeGrantType(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return string.Equals(request.GrantType, GrantTypes.DeviceCode, StringComparison.Ordinal); } /// /// Determines whether the "grant_type" parameter corresponds to the password grant. /// See http://tools.ietf.org/html/rfc6749#section-4.3.2 for more information. /// /// The instance. /// if the request is a password grant request, otherwise. public static bool IsPasswordGrantType(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return string.Equals(request.GrantType, GrantTypes.Password, StringComparison.Ordinal); } /// /// Determines whether the "grant_type" parameter corresponds to the refresh token grant. /// See http://tools.ietf.org/html/rfc6749#section-6 for more information. /// /// The instance. /// if the request is a refresh token grant request, otherwise. public static bool IsRefreshTokenGrantType(this OpenIddictRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } return string.Equals(request.GrantType, GrantTypes.RefreshToken, StringComparison.Ordinal); } /// /// Gets the destinations associated with a claim. /// /// The instance. /// The destinations associated with the claim. public static ImmutableArray GetDestinations(this Claim claim) { if (claim is null) { throw new ArgumentNullException(nameof(claim)); } claim.Properties.TryGetValue(Properties.Destinations, out string? destinations); if (string.IsNullOrEmpty(destinations)) { return ImmutableArray.Create(); } using var document = JsonDocument.Parse(destinations); var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); foreach (var element in document.RootElement.EnumerateArray()) { var value = element.GetString(); if (string.IsNullOrEmpty(value) || builder.Contains(value, StringComparer.OrdinalIgnoreCase)) { continue; } builder.Add(value); } return builder.ToImmutable(); } /// /// Determines whether the given claim contains the required destination. /// /// The instance. /// The required destination. public static bool HasDestination(this Claim claim, string destination) { if (claim is null) { throw new ArgumentNullException(nameof(claim)); } if (string.IsNullOrEmpty(destination)) { throw new ArgumentException(SR.GetResourceString(SR.ID0181), nameof(destination)); } claim.Properties.TryGetValue(Properties.Destinations, out string? destinations); if (string.IsNullOrEmpty(destinations)) { return false; } using var document = JsonDocument.Parse(destinations); foreach (var element in document.RootElement.EnumerateArray()) { var value = element.GetString(); if (string.Equals(value, destination, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } /// /// Adds specific destinations to a claim. /// /// The instance. /// The destinations. public static Claim SetDestinations(this Claim claim, ImmutableArray destinations) { if (claim is null) { throw new ArgumentNullException(nameof(claim)); } if (destinations.IsDefaultOrEmpty) { claim.Properties.Remove(Properties.Destinations); return claim; } if (destinations.Any(string.IsNullOrEmpty)) { throw new ArgumentException(SR.GetResourceString(SR.ID0182), nameof(destinations)); } using var stream = new MemoryStream(); using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, Indented = false }); writer.WriteStartArray(); foreach (var destination in destinations.Distinct(StringComparer.OrdinalIgnoreCase)) { writer.WriteStringValue(destination); } writer.WriteEndArray(); writer.Flush(); claim.Properties[Properties.Destinations] = Encoding.UTF8.GetString(stream.ToArray()); return claim; } /// /// Adds specific destinations to a claim. /// /// The instance. /// The destinations. public static Claim SetDestinations(this Claim claim, IEnumerable? destinations) => claim.SetDestinations(destinations?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Adds specific destinations to a claim. /// /// The instance. /// The destinations. public static Claim SetDestinations(this Claim claim, params string[]? destinations) => claim.SetDestinations(destinations?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Gets the destinations associated with all the claims of the given identity. /// /// The identity. /// The destinations, returned as a flattened dictionary. public static ImmutableDictionary GetDestinations(this ClaimsIdentity identity) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } var builder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal); foreach (var group in identity.Claims.GroupBy(claim => claim.Type)) { var claims = group.ToList(); var destinations = new HashSet(claims[0].GetDestinations(), StringComparer.OrdinalIgnoreCase); if (destinations.Count is not 0) { // Ensure the other claims of the same type use the same exact destinations. for (var index = 0; index < claims.Count; index++) { if (!destinations.SetEquals(claims[index].GetDestinations())) { throw new InvalidOperationException(SR.FormatID0183(group.Key)); } } builder.Add(group.Key, destinations.ToArray()); } } return builder.ToImmutable(); } /// /// Gets the destinations associated with all the claims of the given principal. /// /// The principal. /// The destinations, returned as a flattened dictionary. public static ImmutableDictionary GetDestinations(this ClaimsPrincipal principal) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } var builder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal); foreach (var group in principal.Claims.GroupBy(claim => claim.Type)) { var claims = group.ToList(); var destinations = new HashSet(claims[0].GetDestinations(), StringComparer.OrdinalIgnoreCase); if (destinations.Count is not 0) { // Ensure the other claims of the same type use the same exact destinations. for (var index = 0; index < claims.Count; index++) { if (!destinations.SetEquals(claims[index].GetDestinations())) { throw new InvalidOperationException(SR.FormatID0183(group.Key)); } } builder.Add(group.Key, destinations.ToArray()); } } return builder.ToImmutable(); } /// /// Sets the destinations associated with all the claims of the given identity. /// /// The identity. /// The destinations, as a flattened dictionary. /// The identity. public static ClaimsIdentity SetDestinations(this ClaimsIdentity identity, ImmutableDictionary destinations) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (destinations is null) { throw new ArgumentNullException(nameof(destinations)); } foreach (var destination in destinations) { foreach (var claim in identity.Claims.Where(claim => claim.Type == destination.Key)) { claim.SetDestinations(destination.Value); } } return identity; } /// /// Sets the destinations associated with all the claims of the given principal. /// /// The principal. /// The destinations, as a flattened dictionary. /// The principal. public static ClaimsPrincipal SetDestinations(this ClaimsPrincipal principal, ImmutableDictionary destinations) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (destinations is null) { throw new ArgumentNullException(nameof(destinations)); } foreach (var destination in destinations) { foreach (var claim in principal.Claims.Where(claim => claim.Type == destination.Key)) { claim.SetDestinations(destination.Value); } } return principal; } /// /// Sets the destinations associated with all the claims of the given identity. /// /// The identity. /// The destinations selector delegate. /// The identity. public static ClaimsIdentity SetDestinations(this ClaimsIdentity identity, Func> selector) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (selector is null) { throw new ArgumentNullException(nameof(selector)); } foreach (var claim in identity.Claims) { claim.SetDestinations(selector(claim)); } return identity; } /// /// Sets the destinations associated with all the claims of the given principal. /// /// The principal. /// The destinations selector delegate. /// The principal. public static ClaimsPrincipal SetDestinations(this ClaimsPrincipal principal, Func> selector) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (selector is null) { throw new ArgumentNullException(nameof(selector)); } foreach (var claim in principal.Claims) { claim.SetDestinations(selector(claim)); } return principal; } /// /// Clones an identity by filtering its claims and the claims of its actor, recursively. /// /// The instance to filter. /// /// The delegate filtering the claims: return /// to accept the claim, to remove it. /// public static ClaimsIdentity Clone(this ClaimsIdentity identity, Func filter) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (filter is null) { throw new ArgumentNullException(nameof(filter)); } var clone = identity.Clone(); // Note: make sure to call ToList() to avoid modifying // the initial collection iterated by ClaimsIdentity.Claims. foreach (var claim in clone.Claims.ToList()) { if (!filter(claim)) { clone.RemoveClaim(claim); } } if (clone.Actor is not null) { clone.Actor = clone.Actor.Clone(filter); } return clone; } /// /// Clones a principal by filtering its identities. /// /// The instance to filter. /// /// The delegate filtering the claims: return /// to accept the claim, to remove it. /// public static ClaimsPrincipal Clone(this ClaimsPrincipal principal, Func filter) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (filter is null) { throw new ArgumentNullException(nameof(filter)); } var clone = new ClaimsPrincipal(); foreach (var identity in principal.Identities) { clone.AddIdentity(identity.Clone(filter)); } return clone; } /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, string value) => identity.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, string value) => principal.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, string value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (value is null) { throw new ArgumentNullException(nameof(value)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(new Claim(type, value, ClaimValueTypes.String, issuer, issuer, identity)); return identity; } /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, string value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(type, value, issuer); return principal; } /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, bool value) => identity.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, bool value) => principal.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, bool value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(new Claim(type, value.ToString(), ClaimValueTypes.Boolean, issuer, issuer, identity)); return identity; } /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, bool value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } identity.AddClaim(type, value, issuer); return principal; } /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, long value) => identity.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, long value) => principal.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, long value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(new Claim(type, value.ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Integer64, issuer, issuer, identity)); return identity; } /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, long value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(type, value, issuer); return principal; } /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, JsonElement value) => identity.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, JsonElement value) => principal.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, JsonElement value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } if (value.ValueKind is JsonValueKind.Array) { throw new ArgumentException(SR.GetResourceString(SR.ID0185), nameof(value)); } identity.AddClaim(new Claim( type : type, value : value.ToString()!, valueType : GetClaimValueType(value), issuer : issuer, originalIssuer: issuer, subject : identity)); return identity; } /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, JsonElement value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(type, value, issuer); return principal; } /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, IDictionary value) => identity.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, IDictionary value) => principal.AddClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds a claim to a given identity. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsIdentity AddClaim(this ClaimsIdentity identity, string type, IDictionary value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (value is null) { throw new ArgumentNullException(nameof(value)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } using var stream = new MemoryStream(); using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, Indented = false }); writer.WriteStartObject(); foreach (var property in value) { writer.WritePropertyName(property.Key); writer.WriteStringValue(property.Value); } writer.WriteEndObject(); writer.Flush(); identity.AddClaim(new Claim( type : type, value : Encoding.UTF8.GetString(stream.ToArray()), valueType : "JSON", issuer : issuer, originalIssuer: issuer, subject : identity)); return identity; } /// /// Adds a claim to a given principal. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. public static ClaimsPrincipal AddClaim(this ClaimsPrincipal principal, string type, IDictionary value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaim(type, value, issuer); return principal; } /// /// Adds claims to a given identity. /// /// The identity. /// The type associated with the claims. /// The values associated with the claims. public static ClaimsIdentity AddClaims(this ClaimsIdentity identity, string type, ImmutableArray values) => identity.AddClaims(type, values, ClaimsIdentity.DefaultIssuer); /// /// Adds claims to a given principal. /// /// The principal. /// The type associated with the claims. /// The values associated with the claims. public static ClaimsPrincipal AddClaims(this ClaimsPrincipal principal, string type, ImmutableArray values) => principal.AddClaims(type, values, ClaimsIdentity.DefaultIssuer); /// /// Adds claims to a given identity. /// /// The identity. /// The type associated with the claims. /// The values associated with the claims. /// The issuer associated with the claims. public static ClaimsIdentity AddClaims(this ClaimsIdentity identity, string type, ImmutableArray values, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } var set = new HashSet(StringComparer.Ordinal); for (var index = 0; index < values.Length; index++) { var item = values[index]; if (set.Add(item)) { identity.AddClaim(new Claim( type : type, value : item, valueType : ClaimValueTypes.String, issuer : issuer, originalIssuer: issuer, subject : identity)); } } return identity; } /// /// Adds claims to a given principal. /// /// The principal. /// The type associated with the claims. /// The values associated with the claims. /// The issuer associated with the claims. public static ClaimsPrincipal AddClaims(this ClaimsPrincipal principal, string type, ImmutableArray values, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.AddClaims(type, values, issuer); return principal; } /// /// Adds claims to a given identity. /// /// The identity. /// The type associated with the claims. /// The value associated with the claims. public static ClaimsIdentity AddClaims(this ClaimsIdentity identity, string type, JsonElement value) => identity.AddClaims(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds claims to a given principal. /// /// The principal. /// The type associated with the claims. /// The value associated with the claims. public static ClaimsPrincipal AddClaims(this ClaimsPrincipal principal, string type, JsonElement value) => principal.AddClaims(type, value, ClaimsIdentity.DefaultIssuer); /// /// Adds claims to a given identity. /// /// The identity. /// The type associated with the claims. /// The value associated with the claims. /// The issuer associated with the claims. public static ClaimsIdentity AddClaims(this ClaimsIdentity identity, string type, JsonElement value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } if (value.ValueKind is not JsonValueKind.Array) { throw new ArgumentException(SR.GetResourceString(SR.ID0185), nameof(value)); } var set = new HashSet(StringComparer.Ordinal); foreach (var element in value.EnumerateArray()) { var item = element.ToString()!; if (set.Add(item)) { identity.AddClaim(new Claim( type : type, value : item, valueType : GetClaimValueType(element), issuer : issuer, originalIssuer: issuer, subject : identity)); } } return identity; } /// /// Adds claims to a given principal. /// /// The principal. /// The type associated with the claims. /// The value associated with the claims. /// The issuer associated with the claims. public static ClaimsPrincipal AddClaims(this ClaimsPrincipal principal, string type, JsonElement value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (principal.Identity is not ClaimsIdentity identity) { throw new ArgumentException(SR.GetResourceString(SR.ID0286), nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } if (value.ValueKind is not JsonValueKind.Array) { throw new ArgumentException(SR.GetResourceString(SR.ID0185), nameof(value)); } identity.AddClaims(type, value, issuer); return principal; } /// /// Gets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The claim value. public static string? GetClaim(this ClaimsIdentity identity, string type) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } return identity.FindFirst(type)?.Value; } /// /// Gets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The claim value. public static string? GetClaim(this ClaimsPrincipal principal, string type) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } return principal.FindFirst(type)?.Value; } /// /// Gets the claim values corresponding to the given type. /// /// The claims identity. /// The type associated with the claims. /// The claim values. public static ImmutableArray GetClaims(this ClaimsIdentity identity, string type) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } return identity.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray(); } /// /// Gets the claim values corresponding to the given type. /// /// The claims principal. /// The type associated with the claims. /// The claim values. public static ImmutableArray GetClaims(this ClaimsPrincipal principal, string type) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } return principal.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray(); } /// /// Determines whether the claims identity contains at least one claim of the specified type. /// /// The claims identity. /// The claim type. /// if the identity contains at least one claim of the specified type. public static bool HasClaim(this ClaimsIdentity identity, string type) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } return identity.FindAll(type).Any(); } /// /// Determines whether the claims principal contains at least one claim of the specified type. /// /// The claims principal. /// The claim type. /// if the principal contains at least one claim of the specified type. public static bool HasClaim(this ClaimsPrincipal principal, string type) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } return principal.FindAll(type).Any(); } /// /// Removes all the claims corresponding to the given type. /// /// The identity. /// The type associated with the claims. /// The claims identity. public static ClaimsIdentity RemoveClaims(this ClaimsIdentity identity, string type) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } foreach (var claim in identity.FindAll(type).ToList()) { identity.RemoveClaim(claim); } return identity; } /// /// Removes all the claims corresponding to the given type. /// /// The principal. /// The type associated with the claims. /// The claims identity. public static ClaimsPrincipal RemoveClaims(this ClaimsPrincipal principal, string type) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } foreach (var identity in principal.Identities) { foreach (var claim in identity.FindAll(type).ToList()) { identity.RemoveClaim(claim); } } return principal; } /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, string? value) => identity.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, string? value) => principal.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, string? value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); if (!string.IsNullOrEmpty(value)) { identity.AddClaim(type, value, issuer); } return identity; } /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, string? value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); if (!string.IsNullOrEmpty(value)) { principal.AddClaim(type, value, issuer); } return principal; } /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, bool? value) => identity.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, bool? value) => principal.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, bool? value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); if (value is not null) { identity.AddClaim(type, value.GetValueOrDefault(), issuer); } return identity; } /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, bool? value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); if (value is not null) { principal.AddClaim(type, value.GetValueOrDefault(), issuer); } return principal; } /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, long? value) => identity.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, long? value) => principal.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, long? value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); if (value is not null) { identity.AddClaim(type, value.GetValueOrDefault(), issuer); } return identity; } /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, long? value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); if (value is not null) { principal.AddClaim(type, value.GetValueOrDefault(), issuer); } return principal; } /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, JsonElement value) => identity.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, JsonElement value) => principal.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, JsonElement value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); if (!IsEmptyJsonElement(value)) { identity.AddClaim(type, value, issuer); } return identity; } /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, JsonElement value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); if (!IsEmptyJsonElement(value)) { principal.AddClaim(type, value, issuer); } return principal; } /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, IDictionary? value) => identity.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, IDictionary? value) => principal.SetClaim(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim value corresponding to the given type. /// /// The identity. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsIdentity SetClaim(this ClaimsIdentity identity, string type, IDictionary? value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); if (value is { Count: > 0 }) { identity.AddClaim(type, value, issuer); } return identity; } /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claim. /// The value associated with the claim. /// The issuer associated with the claim. /// The claims identity. public static ClaimsPrincipal SetClaim(this ClaimsPrincipal principal, string type, IDictionary? value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); if (value is { Count: > 0 }) { principal.AddClaim(type, value, issuer); } return principal; } /// /// Sets the claim values corresponding to the given type. /// /// The identity. /// The type associated with the claims. /// The values associated with the claims. /// The claims identity. public static ClaimsIdentity SetClaims(this ClaimsIdentity identity, string type, ImmutableArray values) => identity.SetClaims(type, values, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim values corresponding to the given type. /// /// The principal. /// The type associated with the claims. /// The values associated with the claims. /// The claims identity. public static ClaimsPrincipal SetClaims(this ClaimsPrincipal principal, string type, ImmutableArray values) => principal.SetClaims(type, values, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim values corresponding to the given type. /// /// The identity. /// The type associated with the claims. /// The values associated with the claims. /// The issuer associated with the claims. /// The claims identity. public static ClaimsIdentity SetClaims(this ClaimsIdentity identity, string type, ImmutableArray values, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); foreach (var value in values.Distinct(StringComparer.Ordinal)) { identity.AddClaim(type, value, issuer); } return identity; } /// /// Sets the claim values corresponding to the given type. /// /// The principal. /// The type associated with the claims. /// The values associated with the claims. /// The issuer associated with the claims. /// The claims identity. public static ClaimsPrincipal SetClaims(this ClaimsPrincipal principal, string type, ImmutableArray values, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); foreach (var value in values.Distinct(StringComparer.Ordinal)) { principal.AddClaim(type, value, issuer); } return principal; } /// /// Sets the claim values corresponding to the given type. /// /// The identity. /// The type associated with the claims. /// The JSON array from which claim values are extracted. /// The claims identity. public static ClaimsIdentity SetClaims(this ClaimsIdentity identity, string type, JsonElement value) => identity.SetClaims(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim values corresponding to the given type. /// /// The principal. /// The type associated with the claims. /// The JSON array from which claim values are extracted. /// The claims identity. public static ClaimsPrincipal SetClaims(this ClaimsPrincipal principal, string type, JsonElement value) => principal.SetClaims(type, value, ClaimsIdentity.DefaultIssuer); /// /// Sets the claim values corresponding to the given type. /// /// The identity. /// The type associated with the claims. /// The JSON array from which claim values are extracted. /// The issuer associated with the claims. /// The claims identity. public static ClaimsIdentity SetClaims(this ClaimsIdentity identity, string type, JsonElement value, string issuer) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } identity.RemoveClaims(type); if (!IsEmptyJsonElement(value)) { identity.AddClaims(type, value, issuer); } return identity; } /// /// Sets the claim value corresponding to the given type. /// /// The principal. /// The type associated with the claims. /// The JSON array from which claim values are extracted. /// The issuer associated with the claims. /// The claims identity. public static ClaimsPrincipal SetClaims(this ClaimsPrincipal principal, string type, JsonElement value, string issuer) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0184), nameof(type)); } principal.RemoveClaims(type); if (!IsEmptyJsonElement(value)) { principal.AddClaims(type, value, issuer); } return principal; } /// /// Gets the creation date stored in the claims identity. /// /// The claims identity. /// The creation date or if the claim cannot be found. public static DateTimeOffset? GetCreationDate(this ClaimsIdentity identity) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } var claim = identity.FindFirst(Claims.Private.CreationDate); if (claim is null) { return null; } if (!DateTimeOffset.TryParseExact(claim.Value, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out var value)) { return null; } return value; } /// /// Gets the creation date stored in the claims principal. /// /// The claims principal. /// The creation date or if the claim cannot be found. public static DateTimeOffset? GetCreationDate(this ClaimsPrincipal principal) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } var claim = principal.FindFirst(Claims.Private.CreationDate); if (claim is null) { return null; } if (!DateTimeOffset.TryParseExact(claim.Value, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out var value)) { return null; } return value; } /// /// Gets the expiration date stored in the claims identity. /// /// The claims identity. /// The expiration date or if the claim cannot be found. public static DateTimeOffset? GetExpirationDate(this ClaimsIdentity identity) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } var claim = identity.FindFirst(Claims.Private.ExpirationDate); if (claim is null) { return null; } if (!DateTimeOffset.TryParseExact(claim.Value, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out var value)) { return null; } return value; } /// /// Gets the expiration date stored in the claims principal. /// /// The claims principal. /// The expiration date or if the claim cannot be found. public static DateTimeOffset? GetExpirationDate(this ClaimsPrincipal principal) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } var claim = principal.FindFirst(Claims.Private.ExpirationDate); if (claim is null) { return null; } if (!DateTimeOffset.TryParseExact(claim.Value, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out var value)) { return null; } return value; } /// /// Gets the audiences list stored in the claims identity. /// /// The claims identity. /// The audiences list or an empty set if the claims cannot be found. public static ImmutableArray GetAudiences(this ClaimsIdentity identity) => identity.GetClaims(Claims.Private.Audience); /// /// Gets the audiences list stored in the claims principal. /// /// The claims principal. /// The audiences list or an empty set if the claims cannot be found. public static ImmutableArray GetAudiences(this ClaimsPrincipal principal) => principal.GetClaims(Claims.Private.Audience); /// /// Gets the presenters list stored in the claims identity. /// /// The claims identity. /// The presenters list or an empty set if the claims cannot be found. public static ImmutableArray GetPresenters(this ClaimsIdentity identity) => identity.GetClaims(Claims.Private.Presenter); /// /// Gets the presenters list stored in the claims principal. /// /// The claims principal. /// The presenters list or an empty set if the claims cannot be found. public static ImmutableArray GetPresenters(this ClaimsPrincipal principal) => principal.GetClaims(Claims.Private.Presenter); /// /// Gets the resources list stored in the claims identity. /// /// The claims identity. /// The resources list or an empty set if the claims cannot be found. public static ImmutableArray GetResources(this ClaimsIdentity identity) => identity.GetClaims(Claims.Private.Resource); /// /// Gets the resources list stored in the claims principal. /// /// The claims principal. /// The resources list or an empty set if the claims cannot be found. public static ImmutableArray GetResources(this ClaimsPrincipal principal) => principal.GetClaims(Claims.Private.Resource); /// /// Gets the scopes list stored in the claims identity. /// /// The claims identity. /// The scopes list or an empty set if the claim cannot be found. public static ImmutableArray GetScopes(this ClaimsIdentity identity) => identity.GetClaims(Claims.Private.Scope); /// /// Gets the scopes list stored in the claims principal. /// /// The claims principal. /// The scopes list or an empty set if the claim cannot be found. public static ImmutableArray GetScopes(this ClaimsPrincipal principal) => principal.GetClaims(Claims.Private.Scope); /// /// Gets the access token lifetime associated with the claims identity. /// /// The claims identity. /// The access token lifetime or if the claim cannot be found. public static TimeSpan? GetAccessTokenLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.AccessTokenLifetime); /// /// Gets the access token lifetime associated with the claims principal. /// /// The claims principal. /// The access token lifetime or if the claim cannot be found. public static TimeSpan? GetAccessTokenLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.AccessTokenLifetime); /// /// Gets the authorization code lifetime associated with the claims identity. /// /// The claims identity. /// The authorization code lifetime or if the claim cannot be found. public static TimeSpan? GetAuthorizationCodeLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.AuthorizationCodeLifetime); /// /// Gets the authorization code lifetime associated with the claims principal. /// /// The claims principal. /// The authorization code lifetime or if the claim cannot be found. public static TimeSpan? GetAuthorizationCodeLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.AuthorizationCodeLifetime); /// /// Gets the device code lifetime associated with the claims identity. /// /// The claims identity. /// The device code lifetime or if the claim cannot be found. public static TimeSpan? GetDeviceCodeLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.DeviceCodeLifetime); /// /// Gets the device code lifetime associated with the claims principal. /// /// The claims principal. /// The device code lifetime or if the claim cannot be found. public static TimeSpan? GetDeviceCodeLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.DeviceCodeLifetime); /// /// Gets the identity token lifetime associated with the claims identity. /// /// The claims identity. /// The identity token lifetime or if the claim cannot be found. public static TimeSpan? GetIdentityTokenLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.IdentityTokenLifetime); /// /// Gets the identity token lifetime associated with the claims principal. /// /// The claims principal. /// The identity token lifetime or if the claim cannot be found. public static TimeSpan? GetIdentityTokenLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.IdentityTokenLifetime); /// /// Gets the refresh token lifetime associated with the claims identity. /// /// The claims identity. /// The refresh token lifetime or if the claim cannot be found. public static TimeSpan? GetRefreshTokenLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.RefreshTokenLifetime); /// /// Gets the refresh token lifetime associated with the claims principal. /// /// The claims principal. /// The refresh token lifetime or if the claim cannot be found. public static TimeSpan? GetRefreshTokenLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.RefreshTokenLifetime); /// /// Gets the state token lifetime associated with the claims identity. /// /// The claims identity. /// The state token lifetime or if the claim cannot be found. public static TimeSpan? GetStateTokenLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.StateTokenLifetime); /// /// Gets the state token lifetime associated with the claims principal. /// /// The claims principal. /// The state token lifetime or if the claim cannot be found. public static TimeSpan? GetStateTokenLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.StateTokenLifetime); /// /// Gets the user code lifetime associated with the claims identity. /// /// The claims identity. /// The user code lifetime or if the claim cannot be found. public static TimeSpan? GetUserCodeLifetime(this ClaimsIdentity identity) => GetLifetime(identity, Claims.Private.UserCodeLifetime); /// /// Gets the user code lifetime associated with the claims principal. /// /// The claims principal. /// The user code lifetime or if the claim cannot be found. public static TimeSpan? GetUserCodeLifetime(this ClaimsPrincipal principal) => GetLifetime(principal, Claims.Private.UserCodeLifetime); /// /// Gets the internal authorization identifier associated with the claims identity. /// /// The claims identity. /// The unique identifier or if the claim cannot be found. public static string? GetAuthorizationId(this ClaimsIdentity identity) => identity.GetClaim(Claims.Private.AuthorizationId); /// /// Gets the internal authorization identifier associated with the claims principal. /// /// The claims principal. /// The unique identifier or if the claim cannot be found. public static string? GetAuthorizationId(this ClaimsPrincipal principal) => principal.GetClaim(Claims.Private.AuthorizationId); /// /// Gets the internal token identifier associated with the claims identity. /// /// The claims identity. /// The unique identifier or if the claim cannot be found. public static string? GetTokenId(this ClaimsIdentity identity) => identity.GetClaim(Claims.Private.TokenId); /// /// Gets the internal token identifier associated with the claims principal. /// /// The claims principal. /// The unique identifier or if the claim cannot be found. public static string? GetTokenId(this ClaimsPrincipal principal) => principal.GetClaim(Claims.Private.TokenId); /// /// Gets the token type associated with the claims identity. /// /// The claims identity. /// The token type or if the claim cannot be found. public static string? GetTokenType(this ClaimsIdentity identity) => identity.GetClaim(Claims.Private.TokenType); /// /// Gets the token type associated with the claims principal. /// /// The claims principal. /// The token type or if the claim cannot be found. public static string? GetTokenType(this ClaimsPrincipal principal) => principal.GetClaim(Claims.Private.TokenType); /// /// Determines whether the claims identity contains the given audience. /// /// The claims identity. /// The audience. /// if the identity contains the given audience. public static bool HasAudience(this ClaimsIdentity identity, string audience) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(audience)) { throw new ArgumentException(SR.GetResourceString(SR.ID0186), nameof(audience)); } return identity.HasClaim(Claims.Private.Audience, audience); } /// /// Determines whether the claims principal contains the given audience. /// /// The claims principal. /// The audience. /// if the principal contains the given audience. public static bool HasAudience(this ClaimsPrincipal principal, string audience) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(audience)) { throw new ArgumentException(SR.GetResourceString(SR.ID0186), nameof(audience)); } return principal.HasClaim(Claims.Private.Audience, audience); } /// /// Determines whether the claims identity contains the given presenter. /// /// The claims identity. /// The presenter. /// if the identity contains the given presenter. public static bool HasPresenter(this ClaimsIdentity identity, string presenter) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(presenter)) { throw new ArgumentException(SR.GetResourceString(SR.ID0187), nameof(presenter)); } return identity.HasClaim(Claims.Private.Presenter, presenter); } /// /// Determines whether the claims principal contains the given presenter. /// /// The claims principal. /// The presenter. /// if the principal contains the given presenter. public static bool HasPresenter(this ClaimsPrincipal principal, string presenter) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(presenter)) { throw new ArgumentException(SR.GetResourceString(SR.ID0187), nameof(presenter)); } return principal.HasClaim(Claims.Private.Presenter, presenter); } /// /// Determines whether the claims identity contains the given resource. /// /// The claims identity. /// The resource. /// if the identity contains the given resource. public static bool HasResource(this ClaimsIdentity identity, string resource) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(resource)) { throw new ArgumentException(SR.GetResourceString(SR.ID0062), nameof(resource)); } return identity.HasClaim(Claims.Private.Resource, resource); } /// /// Determines whether the claims principal contains the given resource. /// /// The claims principal. /// The resource. /// if the principal contains the given resource. public static bool HasResource(this ClaimsPrincipal principal, string resource) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(resource)) { throw new ArgumentException(SR.GetResourceString(SR.ID0062), nameof(resource)); } return principal.HasClaim(Claims.Private.Resource, resource); } /// /// Determines whether the claims identity contains the given scope. /// /// The claims identity. /// The scope. /// if the identity contains the given scope. public static bool HasScope(this ClaimsIdentity identity, string scope) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(scope)) { throw new ArgumentException(SR.GetResourceString(SR.ID0180), nameof(scope)); } return identity.HasClaim(Claims.Private.Scope, scope); } /// /// Determines whether the claims principal contains the given scope. /// /// The claims principal. /// The scope. /// if the principal contains the given scope. public static bool HasScope(this ClaimsPrincipal principal, string scope) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(scope)) { throw new ArgumentException(SR.GetResourceString(SR.ID0180), nameof(scope)); } return principal.HasClaim(Claims.Private.Scope, scope); } /// /// Determines whether the token type associated with the claims identity matches the specified type. /// /// The claims identity. /// The token type. /// if the token type matches the specified type. public static bool HasTokenType(this ClaimsIdentity identity, string type) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0188), nameof(type)); } return string.Equals(identity.GetTokenType(), type, StringComparison.OrdinalIgnoreCase); } /// /// Determines whether the token type associated with the claims principal matches the specified type. /// /// The claims principal. /// The token type. /// if the token type matches the specified type. public static bool HasTokenType(this ClaimsPrincipal principal, string type) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } if (string.IsNullOrEmpty(type)) { throw new ArgumentException(SR.GetResourceString(SR.ID0188), nameof(type)); } return string.Equals(principal.GetTokenType(), type, StringComparison.OrdinalIgnoreCase); } /// /// Sets the creation date in the claims identity. /// /// The claims identity. /// The creation date /// The claims identity. public static ClaimsIdentity SetCreationDate(this ClaimsIdentity identity, DateTimeOffset? date) => identity.SetClaim(Claims.Private.CreationDate, date?.ToString("r", CultureInfo.InvariantCulture)); /// /// Sets the creation date in the claims principal. /// /// The claims principal. /// The creation date /// The claims principal. public static ClaimsPrincipal SetCreationDate(this ClaimsPrincipal principal, DateTimeOffset? date) => principal.SetClaim(Claims.Private.CreationDate, date?.ToString("r", CultureInfo.InvariantCulture)); /// /// Sets the expiration date in the claims identity. /// /// The claims identity. /// The expiration date /// The claims identity. public static ClaimsIdentity SetExpirationDate(this ClaimsIdentity identity, DateTimeOffset? date) => identity.SetClaim(Claims.Private.ExpirationDate, date?.ToString("r", CultureInfo.InvariantCulture)); /// /// Sets the expiration date in the claims principal. /// /// The claims principal. /// The expiration date /// The claims principal. public static ClaimsPrincipal SetExpirationDate(this ClaimsPrincipal principal, DateTimeOffset? date) => principal.SetClaim(Claims.Private.ExpirationDate, date?.ToString("r", CultureInfo.InvariantCulture)); /// /// Sets the audiences list in the claims identity. /// Note: this method automatically excludes duplicate audiences. /// /// The claims identity. /// The audiences to store. /// The claims identity. public static ClaimsIdentity SetAudiences(this ClaimsIdentity identity, ImmutableArray audiences) => identity.SetClaims(Claims.Private.Audience, audiences); /// /// Sets the audiences list in the claims principal. /// Note: this method automatically excludes duplicate audiences. /// /// The claims principal. /// The audiences to store. /// The claims principal. public static ClaimsPrincipal SetAudiences(this ClaimsPrincipal principal, ImmutableArray audiences) => principal.SetClaims(Claims.Private.Audience, audiences); /// /// Sets the audiences list in the claims identity. /// Note: this method automatically excludes duplicate audiences. /// /// The claims identity. /// The audiences to store. /// The claims identity. public static ClaimsIdentity SetAudiences(this ClaimsIdentity identity, IEnumerable? audiences) => identity.SetAudiences(audiences?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the audiences list in the claims principal. /// Note: this method automatically excludes duplicate audiences. /// /// The claims principal. /// The audiences to store. /// The claims principal. public static ClaimsPrincipal SetAudiences(this ClaimsPrincipal principal, IEnumerable? audiences) => principal.SetAudiences(audiences?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the audiences list in the claims identity. /// Note: this method automatically excludes duplicate audiences. /// /// The claims identity. /// The audiences to store. /// The claims identity. public static ClaimsIdentity SetAudiences(this ClaimsIdentity identity, params string[]? audiences) => identity.SetAudiences(audiences?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the audiences list in the claims principal. /// Note: this method automatically excludes duplicate audiences. /// /// The claims principal. /// The audiences to store. /// The claims principal. public static ClaimsPrincipal SetAudiences(this ClaimsPrincipal principal, params string[]? audiences) => principal.SetAudiences(audiences?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the presenters list in the claims identity. /// Note: this method automatically excludes duplicate presenters. /// /// The claims identity. /// The presenters to store. /// The claims identity. public static ClaimsIdentity SetPresenters(this ClaimsIdentity identity, ImmutableArray presenters) => identity.SetClaims(Claims.Private.Presenter, presenters); /// /// Sets the presenters list in the claims principal. /// Note: this method automatically excludes duplicate presenters. /// /// The claims principal. /// The presenters to store. /// The claims principal. public static ClaimsPrincipal SetPresenters(this ClaimsPrincipal principal, ImmutableArray presenters) => principal.SetClaims(Claims.Private.Presenter, presenters); /// /// Sets the presenters list in the claims identity. /// Note: this method automatically excludes duplicate presenters. /// /// The claims identity. /// The presenters to store. /// The claims identity. public static ClaimsIdentity SetPresenters(this ClaimsIdentity identity, IEnumerable? presenters) => identity.SetPresenters(presenters?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the presenters list in the claims principal. /// Note: this method automatically excludes duplicate presenters. /// /// The claims principal. /// The presenters to store. /// The claims principal. public static ClaimsPrincipal SetPresenters(this ClaimsPrincipal principal, IEnumerable? presenters) => principal.SetPresenters(presenters?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the presenters list in the claims identity. /// Note: this method automatically excludes duplicate presenters. /// /// The claims identity. /// The presenters to store. /// The claims identity. public static ClaimsIdentity SetPresenters(this ClaimsIdentity identity, params string[]? presenters) => identity.SetPresenters(presenters?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the presenters list in the claims principal. /// Note: this method automatically excludes duplicate presenters. /// /// The claims principal. /// The presenters to store. /// The claims principal. public static ClaimsPrincipal SetPresenters(this ClaimsPrincipal principal, params string[]? presenters) => principal.SetPresenters(presenters?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the resources list in the claims identity. /// Note: this method automatically excludes duplicate resources. /// /// The claims identity. /// The resources to store. /// The claims identity. public static ClaimsIdentity SetResources(this ClaimsIdentity identity, ImmutableArray resources) => identity.SetClaims(Claims.Private.Resource, resources); /// /// Sets the resources list in the claims principal. /// Note: this method automatically excludes duplicate resources. /// /// The claims principal. /// The resources to store. /// The claims principal. public static ClaimsPrincipal SetResources(this ClaimsPrincipal principal, ImmutableArray resources) => principal.SetClaims(Claims.Private.Resource, resources); /// /// Sets the resources list in the claims identity. /// Note: this method automatically excludes duplicate resources. /// /// The claims identity. /// The resources to store. /// The claims identity. public static ClaimsIdentity SetResources(this ClaimsIdentity identity, IEnumerable? resources) => identity.SetResources(resources?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the resources list in the claims principal. /// Note: this method automatically excludes duplicate resources. /// /// The claims principal. /// The resources to store. /// The claims principal. public static ClaimsPrincipal SetResources(this ClaimsPrincipal principal, IEnumerable? resources) => principal.SetResources(resources?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the resources list in the claims identity. /// Note: this method automatically excludes duplicate resources. /// /// The claims identity. /// The resources to store. /// The claims identity. public static ClaimsIdentity SetResources(this ClaimsIdentity identity, params string[]? resources) => identity.SetResources(resources?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the resources list in the claims principal. /// Note: this method automatically excludes duplicate resources. /// /// The claims principal. /// The resources to store. /// The claims principal. public static ClaimsPrincipal SetResources(this ClaimsPrincipal principal, params string[]? resources) => principal.SetResources(resources?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the scopes list in the claims identity. /// Note: this method automatically excludes duplicate scopes. /// /// The claims identity. /// The scopes to store. /// The claims identity. public static ClaimsIdentity SetScopes(this ClaimsIdentity identity, ImmutableArray scopes) => identity.SetClaims(Claims.Private.Scope, scopes); /// /// Sets the scopes list in the claims principal. /// Note: this method automatically excludes duplicate scopes. /// /// The claims principal. /// The scopes to store. /// The claims principal. public static ClaimsPrincipal SetScopes(this ClaimsPrincipal principal, ImmutableArray scopes) => principal.SetClaims(Claims.Private.Scope, scopes); /// /// Sets the scopes list in the claims identity. /// Note: this method automatically excludes duplicate scopes. /// /// The claims identity. /// The scopes to store. /// The claims identity. public static ClaimsIdentity SetScopes(this ClaimsIdentity identity, IEnumerable? scopes) => identity.SetScopes(scopes?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the scopes list in the claims principal. /// Note: this method automatically excludes duplicate scopes. /// /// The claims principal. /// The scopes to store. /// The claims principal. public static ClaimsPrincipal SetScopes(this ClaimsPrincipal principal, IEnumerable? scopes) => principal.SetScopes(scopes?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the scopes list in the claims identity. /// Note: this method automatically excludes duplicate scopes. /// /// The claims identity. /// The scopes to store. /// The claims identity. public static ClaimsIdentity SetScopes(this ClaimsIdentity identity, params string[]? scopes) => identity.SetScopes(scopes?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the scopes list in the claims principal. /// Note: this method automatically excludes duplicate scopes. /// /// The claims principal. /// The scopes to store. /// The claims principal. public static ClaimsPrincipal SetScopes(this ClaimsPrincipal principal, params string[]? scopes) => principal.SetScopes(scopes?.ToImmutableArray() ?? ImmutableArray.Create()); /// /// Sets the access token lifetime associated with the claims identity. /// /// The claims identity. /// The access token lifetime to store. /// The claims identity. public static ClaimsIdentity SetAccessTokenLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.AccessTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the access token lifetime associated with the claims principal. /// /// The claims principal. /// The access token lifetime to store. /// The claims principal. public static ClaimsPrincipal SetAccessTokenLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.AccessTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the authorization code lifetime associated with the claims identity. /// /// The claims identity. /// The authorization code lifetime to store. /// The claims identity. public static ClaimsIdentity SetAuthorizationCodeLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.AuthorizationCodeLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the authorization code lifetime associated with the claims principal. /// /// The claims principal. /// The authorization code lifetime to store. /// The claims principal. public static ClaimsPrincipal SetAuthorizationCodeLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.AuthorizationCodeLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the device code lifetime associated with the claims identity. /// /// The claims identity. /// The device code lifetime to store. /// The claims identity. public static ClaimsIdentity SetDeviceCodeLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.DeviceCodeLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the device code lifetime associated with the claims principal. /// /// The claims principal. /// The device code lifetime to store. /// The claims principal. public static ClaimsPrincipal SetDeviceCodeLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.DeviceCodeLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the identity token lifetime associated with the claims identity. /// /// The claims identity. /// The identity token lifetime to store. /// The claims identity. public static ClaimsIdentity SetIdentityTokenLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.IdentityTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the identity token lifetime associated with the claims principal. /// /// The claims principal. /// The identity token lifetime to store. /// The claims principal. public static ClaimsPrincipal SetIdentityTokenLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.IdentityTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the refresh token lifetime associated with the claims identity. /// /// The claims identity. /// The refresh token lifetime to store. /// The claims identity. public static ClaimsIdentity SetRefreshTokenLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.RefreshTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the refresh token lifetime associated with the claims principal. /// /// The claims principal. /// The refresh token lifetime to store. /// The claims principal. public static ClaimsPrincipal SetRefreshTokenLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.RefreshTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the state token lifetime associated with the claims identity. /// /// The claims identity. /// The state token lifetime to store. /// The claims identity. public static ClaimsIdentity SetStateTokenLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.StateTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the state token lifetime associated with the claims principal. /// /// The claims principal. /// The state token lifetime to store. /// The claims principal. public static ClaimsPrincipal SetStateTokenLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.StateTokenLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the user code lifetime associated with the claims identity. /// /// The claims identity. /// The user code lifetime to store. /// The claims identity. public static ClaimsIdentity SetUserCodeLifetime(this ClaimsIdentity identity, TimeSpan? lifetime) => identity.SetClaim(Claims.Private.UserCodeLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the user code lifetime associated with the claims principal. /// /// The claims principal. /// The user code lifetime to store. /// The claims principal. public static ClaimsPrincipal SetUserCodeLifetime(this ClaimsPrincipal principal, TimeSpan? lifetime) => principal.SetClaim(Claims.Private.UserCodeLifetime, (long?) lifetime?.TotalSeconds); /// /// Sets the internal authorization identifier associated with the claims identity. /// /// The claims identity. /// The unique identifier to store. /// The claims identity. public static ClaimsIdentity SetAuthorizationId(this ClaimsIdentity identity, string? identifier) => identity.SetClaim(Claims.Private.AuthorizationId, identifier); /// /// Sets the internal authorization identifier associated with the claims principal. /// /// The claims principal. /// The unique identifier to store. /// The claims principal. public static ClaimsPrincipal SetAuthorizationId(this ClaimsPrincipal principal, string? identifier) => principal.SetClaim(Claims.Private.AuthorizationId, identifier); /// /// Sets the internal token identifier associated with the claims identity. /// /// The claims identity. /// The unique identifier to store. /// The claims identity. public static ClaimsIdentity SetTokenId(this ClaimsIdentity identity, string? identifier) => identity.SetClaim(Claims.Private.TokenId, identifier); /// /// Sets the internal token identifier associated with the claims principal. /// /// The claims principal. /// The unique identifier to store. /// The claims principal. public static ClaimsPrincipal SetTokenId(this ClaimsPrincipal principal, string? identifier) => principal.SetClaim(Claims.Private.TokenId, identifier); /// /// Sets the token type associated with the claims identity. /// /// The claims identity. /// The token type to store. /// The claims identity. public static ClaimsIdentity SetTokenType(this ClaimsIdentity identity, string? type) => identity.SetClaim(Claims.Private.TokenType, type); /// /// Sets the token type associated with the claims principal. /// /// The claims principal. /// The token type to store. /// The claims principal. public static ClaimsPrincipal SetTokenType(this ClaimsPrincipal principal, string? type) => principal.SetClaim(Claims.Private.TokenType, type); private static ImmutableArray GetValues(string? source, char[] separators) { Debug.Assert(separators is { Length: > 0 }, SR.GetResourceString(SR.ID4001)); if (string.IsNullOrEmpty(source)) { return ImmutableArray.Create(); } var builder = ImmutableArray.CreateBuilder(); foreach (var element in new StringTokenizer(source, separators)) { var segment = Trim(element, separators); if (!segment.HasValue || segment.Length is 0) { continue; } if (builder.Contains(segment.Value, StringComparer.Ordinal)) { continue; } builder.Add(segment.Value); } return builder.ToImmutable(); } private static bool HasValue(string? source, string value, char[] separators) { Debug.Assert(!string.IsNullOrEmpty(value), SR.GetResourceString(SR.ID4002)); Debug.Assert(separators is { Length: > 0 }, SR.GetResourceString(SR.ID4001)); if (string.IsNullOrEmpty(source)) { return false; } foreach (var element in new StringTokenizer(source, separators)) { var segment = Trim(element, separators); if (!segment.HasValue || segment.Length is 0) { continue; } if (segment.Equals(value, StringComparison.Ordinal)) { return true; } } return false; } private static StringSegment TrimStart(StringSegment segment, char[] separators) { Debug.Assert(separators is { Length: > 0 }, SR.GetResourceString(SR.ID4001)); if (!segment.HasValue || segment.Length is 0) { return segment; } var index = segment.Offset; while (index < segment.Offset + segment.Length) { if (!IsSeparator(segment.Buffer[index], separators)) { break; } index++; } return new StringSegment(segment.Buffer, index, segment.Offset + segment.Length - index); } private static StringSegment TrimEnd(StringSegment segment, char[] separators) { Debug.Assert(separators is { Length: > 0 }, SR.GetResourceString(SR.ID4001)); if (!segment.HasValue || segment.Length is 0) { return segment; } var index = segment.Offset + segment.Length - 1; while (index >= segment.Offset) { if (!IsSeparator(segment.Buffer[index], separators)) { break; } index--; } return new StringSegment(segment.Buffer, segment.Offset, index - segment.Offset + 1); } private static StringSegment Trim(StringSegment segment, char[] separators) { Debug.Assert(separators is { Length: > 0 }, SR.GetResourceString(SR.ID4001)); return TrimEnd(TrimStart(segment, separators), separators); } private static bool IsSeparator(char character, char[] separators) { Debug.Assert(separators is { Length: > 0 }, SR.GetResourceString(SR.ID4001)); for (var index = 0; index < separators!.Length; index++) { if (character == separators[index]) { return true; } } return false; } private static string GetClaimValueType(JsonElement element) => element.ValueKind switch { JsonValueKind.String => ClaimValueTypes.String, JsonValueKind.True or JsonValueKind.False => ClaimValueTypes.Boolean, JsonValueKind.Number when element.TryGetInt32(out _) => ClaimValueTypes.Integer32, JsonValueKind.Number when element.TryGetInt64(out _) => ClaimValueTypes.Integer64, JsonValueKind.Number when element.TryGetUInt32(out _) => ClaimValueTypes.UInteger32, JsonValueKind.Number when element.TryGetUInt64(out _) => ClaimValueTypes.UInteger64, JsonValueKind.Number when element.TryGetDouble(out _) => ClaimValueTypes.Double, JsonValueKind.Null or JsonValueKind.Undefined => "JSON_NULL", JsonValueKind.Array => "JSON_ARRAY", JsonValueKind.Object or _ => "JSON" }; private static TimeSpan? GetLifetime(ClaimsIdentity identity, string type) { if (identity is null) { throw new ArgumentNullException(nameof(identity)); } var value = identity.GetClaim(type); if (string.IsNullOrEmpty(value)) { return null; } if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) { return TimeSpan.FromSeconds(result); } return null; } private static TimeSpan? GetLifetime(ClaimsPrincipal principal, string type) { if (principal is null) { throw new ArgumentNullException(nameof(principal)); } var value = principal.GetClaim(type); if (string.IsNullOrEmpty(value)) { return null; } if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) { return TimeSpan.FromSeconds(result); } return null; } private static bool IsEmptyJsonElement(JsonElement element) { switch (element.ValueKind) { case JsonValueKind.Undefined or JsonValueKind.Null: return true; case JsonValueKind.String: return string.IsNullOrEmpty(element.GetString()); case JsonValueKind.Array: return element.GetArrayLength() is 0; case JsonValueKind.Object: using (var enumerator = element.EnumerateObject()) { return !enumerator.MoveNext(); } default: return false; } } }