diff --git a/shared/OpenIddict.Extensions/OpenIddictHelpers.cs b/shared/OpenIddict.Extensions/OpenIddictHelpers.cs
index 7c9d83ef..382ba763 100644
--- a/shared/OpenIddict.Extensions/OpenIddictHelpers.cs
+++ b/shared/OpenIddict.Extensions/OpenIddictHelpers.cs
@@ -1094,6 +1094,34 @@ internal static class OpenIddictHelpers
return true;
}
+ ///
+ /// Determines whether the items contained in
+ /// are of the specified .
+ ///
+ /// The .
+ /// The expected .
+ ///
+ /// if the object doesn't contain any value or if all the items
+ /// are of the specified , otherwise.
+ ///
+ public static bool ValidateObjectElements(JsonElement element, JsonValueKind kind)
+ {
+ if (element.ValueKind is not JsonValueKind.Object)
+ {
+ throw new ArgumentOutOfRangeException(nameof(element));
+ }
+
+ foreach (var property in element.EnumerateObject())
+ {
+ if (property.Value.ValueKind != kind)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
///
/// Note: this implementation was taken from ASP.NET Core.
///
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
index 9fc48bd9..d6c24636 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
@@ -137,6 +137,12 @@ public static partial class OpenIddictClientHandlers
element.ValueKind is JsonValueKind.Array &&
OpenIddictHelpers.ValidateArrayElements(element, JsonValueKind.String),
+ // The following parameters MUST be formatted as JSON objects and only contain string values:
+ Metadata.MtlsEndpointAliases
+ => ((JsonElement) value) is JsonElement element &&
+ element.ValueKind is JsonValueKind.Object &&
+ OpenIddictHelpers.ValidateObjectElements(element, JsonValueKind.String),
+
// The following parameters MUST be formatted as booleans:
Metadata.AuthorizationResponseIssParameterSupported or
Metadata.RequirePushedAuthorizationRequests or
@@ -513,15 +519,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.DeviceAuthorizationEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.DeviceAuthorizationEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsDeviceAuthorizationEndpoint = uri;
@@ -555,15 +555,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.IntrospectionEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.IntrospectionEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsIntrospectionEndpoint = uri;
@@ -596,15 +590,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.PushedAuthorizationRequestEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.PushedAuthorizationRequestEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsPushedAuthorizationEndpoint = uri;
@@ -637,15 +625,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.RevocationEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.RevocationEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsRevocationEndpoint = uri;
@@ -678,15 +660,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.TokenEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.TokenEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsTokenEndpoint = uri;
@@ -719,15 +695,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.UserInfoEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.UserInfoEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsUserInfoEndpoint = uri;
diff --git a/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs b/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
index 7bedb22f..19684dab 100644
--- a/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
+++ b/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
@@ -99,6 +99,12 @@ public static partial class OpenIddictValidationHandlers
element.ValueKind is JsonValueKind.Array &&
OpenIddictHelpers.ValidateArrayElements(element, JsonValueKind.String),
+ // The following parameters MUST be formatted as JSON objects and only contain string values:
+ Metadata.MtlsEndpointAliases
+ => ((JsonElement) value) is JsonElement element &&
+ element.ValueKind is JsonValueKind.Object &&
+ OpenIddictHelpers.ValidateObjectElements(element, JsonValueKind.String),
+
// Parameters that are not in the well-known list can be of any type.
_ => true
};
@@ -331,15 +337,9 @@ public static partial class OpenIddictValidationHandlers
throw new ArgumentNullException(nameof(context));
}
- var aliases = context.Response[Metadata.MtlsEndpointAliases]?.GetNamedParameters();
- if (aliases is not { Count: > 0 })
- {
- return default;
- }
-
// Note: as recommended by the specification, values present in the "mtls_endpoint_aliases" node
// that can't be recognized as OAuth 2.0 endpoints or are not valid URIs are simply ignored.
- var endpoint = (string?) aliases[Metadata.IntrospectionEndpoint];
+ var endpoint = (string?) context.Response[Metadata.MtlsEndpointAliases]?[Metadata.IntrospectionEndpoint];
if (Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) && !OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Configuration.MtlsIntrospectionEndpoint = uri;