diff --git a/shared/OpenIddict.Extensions/OpenIddictHelpers.cs b/shared/OpenIddict.Extensions/OpenIddictHelpers.cs index 382ba763..6844c0b1 100644 --- a/shared/OpenIddict.Extensions/OpenIddictHelpers.cs +++ b/shared/OpenIddict.Extensions/OpenIddictHelpers.cs @@ -13,6 +13,7 @@ using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Primitives; namespace OpenIddict.Extensions; @@ -1066,6 +1067,61 @@ internal static class OpenIddictHelpers } #endif + /// + /// Determines whether the specified represents a null, undefined or empty JSON node. + /// + /// The . + /// + /// if the JSON node is null, undefined or empty otherwise. + /// + public static bool IsNullOrEmpty(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: +#if SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT + return element.GetPropertyCount() is 0; +#else + using (var enumerator = element.EnumerateObject()) + { + return !enumerator.MoveNext(); + } +#endif + default: return false; + } + } + + /// + /// Determines whether the specified represents a null or empty JSON node. + /// + /// The . + /// + /// if the JSON node is null or empty otherwise. + /// + public static bool IsNullOrEmpty([NotNullWhen(false)] JsonNode? node) => node switch + { + null => true, + + JsonArray value => value.Count is 0, + JsonObject value => value.Count is 0, + + JsonValue value when value.TryGetValue(out string? result) => string.IsNullOrEmpty(result), + JsonValue value when value.TryGetValue(out JsonElement element) => IsNullOrEmpty(element), + + // If the JSON node cannot be mapped to a primitive type, convert it to + // a JsonElement instance and infer the corresponding claim value type. + JsonNode value => IsNullOrEmpty(value.Deserialize(OpenIddictSerializer.Default.JsonElement)) + }; + /// /// Determines whether the items contained in /// are of the specified . diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs index 4aec04ee..c982ce18 100644 --- a/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs +++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Security.Claims; @@ -15,6 +14,7 @@ using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Nodes; using Microsoft.Extensions.Primitives; +using OpenIddict.Extensions; namespace OpenIddict.Abstractions; @@ -2261,7 +2261,7 @@ public static class OpenIddictExtensions identity.RemoveClaims(type); - if (!IsEmptyJsonElement(value)) + if (!OpenIddictHelpers.IsNullOrEmpty(value)) { identity.AddClaim(type, value, issuer); } @@ -2291,7 +2291,7 @@ public static class OpenIddictExtensions principal.RemoveClaims(type); - if (!IsEmptyJsonElement(value)) + if (!OpenIddictHelpers.IsNullOrEmpty(value)) { principal.AddClaim(type, value, issuer); } @@ -2341,7 +2341,7 @@ public static class OpenIddictExtensions identity.RemoveClaims(type); - if (!IsEmptyJsonNode(value)) + if (!OpenIddictHelpers.IsNullOrEmpty(value)) { identity.AddClaim(type, value, issuer); } @@ -2371,7 +2371,7 @@ public static class OpenIddictExtensions principal.RemoveClaims(type); - if (!IsEmptyJsonNode(value)) + if (!OpenIddictHelpers.IsNullOrEmpty(value)) { principal.AddClaim(type, value, issuer); } @@ -2591,7 +2591,7 @@ public static class OpenIddictExtensions identity.RemoveClaims(type); - if (!IsEmptyJsonElement(value)) + if (!OpenIddictHelpers.IsNullOrEmpty(value)) { identity.AddClaims(type, value, issuer); } @@ -2621,7 +2621,7 @@ public static class OpenIddictExtensions principal.RemoveClaims(type); - if (!IsEmptyJsonElement(value)) + if (!OpenIddictHelpers.IsNullOrEmpty(value)) { principal.AddClaims(type, value, issuer); } @@ -3932,6 +3932,8 @@ public static class OpenIddictExtensions JsonArray => "JSON_ARRAY", JsonObject => "JSON", + JsonValue value when value.TryGetValue(out JsonElement element) => GetClaimValueType(element), + // If the JSON node cannot be mapped to a primitive type, convert it to // a JsonElement instance and infer the corresponding claim value type. JsonNode value => GetClaimValueType(value.Deserialize(OpenIddictSerializer.Default.JsonElement)) @@ -3978,41 +3980,4 @@ public static class OpenIddictExtensions 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; - } - } - - private static bool IsEmptyJsonNode([NotNullWhen(false)] JsonNode? node) => node switch - { - null => true, - - JsonArray value => value.Count is 0, - JsonObject value => value.Count is 0, - - JsonValue value when value.TryGetValue(out string? result) => string.IsNullOrEmpty(result), - - // If the JSON node cannot be mapped to a primitive type, convert it to - // a JsonElement instance and infer the corresponding claim value type. - JsonNode value => IsEmptyJsonElement(value.Deserialize(OpenIddictSerializer.Default.JsonElement)) - }; } diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs index d6779738..96b14d0b 100644 --- a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs +++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs @@ -12,6 +12,7 @@ using System.Runtime.InteropServices; using System.Text.Json; using System.Text.Json.Nodes; using Microsoft.Extensions.Primitives; +using OpenIddict.Extensions; namespace OpenIddict.Abstractions; @@ -634,14 +635,13 @@ public readonly struct OpenIddictParameter : IEquatable JsonElement value => value.ToString(), - JsonValue value when value.TryGetValue(out JsonElement element) - => element.ValueKind switch - { - JsonValueKind.True => "true", - JsonValueKind.False => "false", + JsonValue value when value.TryGetValue(out JsonElement element) => element.ValueKind switch + { + JsonValueKind.True => "true", + JsonValueKind.False => "false", - _ => element.ToString() - }, + _ => element.ToString() + }, JsonValue value when value.TryGetValue(out bool result) => result ? "true" : "false", @@ -1310,8 +1310,7 @@ public readonly struct OpenIddictParameter : IEquatable JsonValue value when value.TryGetValue(out string? result) => [result], // When the parameter is a JsonValue wrapping a boolean, return an array with its string representation. - JsonValue value when value.TryGetValue(out bool result) - => [result ? "true" : "false"], + JsonValue value when value.TryGetValue(out bool result) => [result ? "true" : "false"], // When the parameter is a JsonValue wrapping an integer, return an array with its string representation. JsonValue value when value.TryGetValue(out int result) @@ -1483,45 +1482,21 @@ public readonly struct OpenIddictParameter : IEquatable string value => value.Length is 0, string?[] value => value.Length is 0, - JsonElement value => IsEmptyJsonElement(value), + JsonElement value => OpenIddictHelpers.IsNullOrEmpty(value), JsonArray value => value.Count is 0, JsonObject value => value.Count is 0, - JsonValue value when value.TryGetValue(out JsonElement element) - => IsEmptyJsonElement(element), + JsonValue value when value.TryGetValue(out string? result) => string.IsNullOrEmpty(result), - JsonValue value when value.TryGetValue(out string? result) - => string.IsNullOrEmpty(result), + JsonValue value when value.TryGetValue(out JsonElement element) + => OpenIddictHelpers.IsNullOrEmpty(element), JsonNode value when JsonSerializer.SerializeToElement(value, OpenIddictSerializer.Default.JsonNode) is JsonElement element - => IsEmptyJsonElement(element), + => OpenIddictHelpers.IsNullOrEmpty(element), _ => false }; - - static bool IsEmptyJsonElement(JsonElement element) - { - switch (element.ValueKind) - { - case JsonValueKind.String: - return string.IsNullOrEmpty(element.GetString()); - - case JsonValueKind.Array: - return element.GetArrayLength() is 0; - - case JsonValueKind.Object: -#if SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT - return element.GetPropertyCount() is 0; -#else - using (var enumerator = element.EnumerateObject()) - { - return !enumerator.MoveNext(); - } -#endif - default: return false; - } - } } }