Browse Source

Special-case JsonValue instances that wrap a JsonElement object

pull/2311/head
Kévin Chalet 9 months ago
parent
commit
9638ae410c
  1. 56
      shared/OpenIddict.Extensions/OpenIddictHelpers.cs
  2. 53
      src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs
  3. 51
      src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs

56
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
/// <summary>
/// Determines whether the specified <paramref name="element"/> represents a null, undefined or empty JSON node.
/// </summary>
/// <param name="element">The <see cref="JsonElement"/>.</param>
/// <returns>
/// <see langword="true"/> if the JSON node is null, undefined or empty <see langword="false"/> otherwise.
/// </returns>
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;
}
}
/// <summary>
/// Determines whether the specified <paramref name="node"/> represents a null or empty JSON node.
/// </summary>
/// <param name="node">The <see cref="JsonNode"/>.</param>
/// <returns>
/// <see langword="true"/> if the JSON node is null or empty <see langword="false"/> otherwise.
/// </returns>
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))
};
/// <summary>
/// Determines whether the items contained in <paramref name="element"/>
/// are of the specified <paramref name="kind"/>.

53
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))
};
}

51
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<OpenIddictParameter>
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<OpenIddictParameter>
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<OpenIddictParameter>
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;
}
}
}
}

Loading…
Cancel
Save