Browse Source

Introduce specialized event handlers for validating discovery parameters

pull/1417/head
Kévin Chalet 4 years ago
parent
commit
0737996382
  1. 2
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  2. 155
      src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
  3. 20
      src/OpenIddict.Client/OpenIddictClientHandlers.Exchange.cs
  4. 20
      src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs
  5. 143
      src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
  6. 136
      src/OpenIddict.Validation/OpenIddictValidationHandlers.Introspection.cs

2
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -1524,7 +1524,7 @@ Reference the 'OpenIddict.Client.SystemNetHttp' package and call 'services.AddOp
<value>The token was rejected by the remote authentication server.</value>
</data>
<data name="ID2107" xml:space="preserve">
<value>The '{0}' claim is malformed or isn't of the expected type.</value>
<value>The '{0}' parameter is malformed or isn't of the expected type.</value>
</data>
<data name="ID2108" xml:space="preserve">
<value>An introspection response containing a malformed issuer was returned.</value>

155
src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs

@ -5,6 +5,7 @@
*/
using System.Collections.Immutable;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;
namespace OpenIddict.Client;
@ -18,6 +19,7 @@ public static partial class OpenIddictClientHandlers
* Configuration response handling:
*/
HandleErrorResponse<HandleConfigurationResponseContext>.Descriptor,
ValidateWellKnownConfigurationParameters.Descriptor,
ValidateIssuer.Descriptor,
ExtractAuthorizationEndpoint.Descriptor,
ExtractCryptographyEndpoint.Descriptor,
@ -35,8 +37,92 @@ public static partial class OpenIddictClientHandlers
* Cryptography response handling:
*/
HandleErrorResponse<HandleCryptographyResponseContext>.Descriptor,
ValidateWellKnownCryptographyParameters.Descriptor,
ExtractSigningKeys.Descriptor);
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the configuration response.
/// </summary>
public class ValidateWellKnownConfigurationParameters : IOpenIddictClientHandler<HandleConfigurationResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleConfigurationResponseContext>()
.UseSingletonHandler<ValidateWellKnownConfigurationParameters>()
.SetOrder(HandleErrorResponse<HandleConfigurationResponseContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleConfigurationResponseContext context!!)
{
foreach (var parameter in context.Response.GetParameters())
{
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
}
}
return default;
// Note: in the typical case, the response parameters should be deserialized from a
// JSON response and thus natively stored as System.Text.Json.JsonElement instances.
//
// In the rare cases where the underlying value wouldn't be a JsonElement instance
// (e.g when custom parameters are manually added to the response), the static
// conversion operator would take care of converting the underlying value to a
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The following parameters MUST be formatted as unique strings:
Metadata.AuthorizationEndpoint or
Metadata.Issuer or
Metadata.JwksUri or
Metadata.TokenEndpoint or
Metadata.UserinfoEndpoint
=> ((JsonElement) value).ValueKind is JsonValueKind.String,
// The following parameters MUST be formatted as arrays of strings:
Metadata.CodeChallengeMethodsSupported or
Metadata.GrantTypesSupported or
Metadata.ResponseModesSupported or
Metadata.ResponseTypesSupported or
Metadata.ScopesSupported or
Metadata.TokenEndpointAuthMethodsSupported
=> ((JsonElement) value) is JsonElement element &&
element.ValueKind is JsonValueKind.Array && ValidateStringArray(element),
// The following parameters MUST be formatted as booleans:
Metadata.AuthorizationResponseIssParameterSupported
=> ((JsonElement) value).ValueKind is JsonValueKind.True or JsonValueKind.False,
// Parameters that are not in the well-known list can be of any type.
_ => true
};
static bool ValidateStringArray(JsonElement element)
{
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind is not JsonValueKind.String)
{
return false;
}
}
return true;
}
}
}
/// <summary>
/// Contains the logic responsible for extracting the issuer from the discovery document.
/// </summary>
@ -48,7 +134,7 @@ public static partial class OpenIddictClientHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleConfigurationResponseContext>()
.UseSingletonHandler<ValidateIssuer>()
.SetOrder(HandleErrorResponse<HandleConfigurationResponseContext>.Descriptor.Order + 1_000)
.SetOrder(ValidateWellKnownConfigurationParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -503,6 +589,71 @@ public static partial class OpenIddictClientHandlers
}
}
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the JWKS response.
/// </summary>
public class ValidateWellKnownCryptographyParameters : IOpenIddictClientHandler<HandleCryptographyResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
.UseSingletonHandler<ValidateWellKnownCryptographyParameters>()
.SetOrder(HandleErrorResponse<HandleCryptographyResponseContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context!!)
{
foreach (var parameter in context.Response.GetParameters())
{
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
}
}
return default;
// Note: in the typical case, the response parameters should be deserialized from a
// JSON response and thus natively stored as System.Text.Json.JsonElement instances.
//
// In the rare cases where the underlying value wouldn't be a JsonElement instance
// (e.g when custom parameters are manually added to the response), the static
// conversion operator would take care of converting the underlying value to a
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The following parameters MUST be formatted as arrays of objects:
JsonWebKeySetParameterNames.Keys => ((JsonElement) value) is JsonElement element &&
element.ValueKind is JsonValueKind.Array && ValidateObjectArray(element),
// Parameters that are not in the well-known list can be of any type.
_ => true
};
static bool ValidateObjectArray(JsonElement element)
{
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind is not JsonValueKind.Object)
{
return false;
}
}
return true;
}
}
}
/// <summary>
/// Contains the logic responsible for extracting the signing keys from the JWKS document.
/// </summary>
@ -514,7 +665,7 @@ public static partial class OpenIddictClientHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
.UseSingletonHandler<ExtractSigningKeys>()
.SetOrder(HandleErrorResponse<HandleCryptographyResponseContext>.Descriptor.Order + 1_000)
.SetOrder(ValidateWellKnownCryptographyParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();

20
src/OpenIddict.Client/OpenIddictClientHandlers.Exchange.cs

@ -40,17 +40,15 @@ public static partial class OpenIddictClientHandlers
{
foreach (var parameter in context.Response.GetParameters())
{
if (ValidateParameterType(parameter.Key, parameter.Value))
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
continue;
}
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
return default;
}
}
return default;
@ -64,11 +62,11 @@ public static partial class OpenIddictClientHandlers
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The 'access_token', 'id_token' and 'refresh_token' parameters MUST be formatted as unique strings.
// The following parameters MUST be formatted as unique strings:
Parameters.AccessToken or Parameters.IdToken or Parameters.RefreshToken
=> ((JsonElement) value).ValueKind is JsonValueKind.String,
// The 'expires_in' parameter MUST be formatted as a numeric date value.
// The following parameters MUST be formatted as numeric dates:
Parameters.ExpiresIn => ((JsonElement) value).ValueKind is JsonValueKind.Number,
// Parameters that are not in the well-known list can be of any type.

20
src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs

@ -49,17 +49,15 @@ public static partial class OpenIddictClientHandlers
foreach (var parameter in context.Response.GetParameters())
{
if (ValidateClaimType(parameter.Key, parameter.Value))
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
continue;
}
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
return default;
}
}
return default;
@ -71,9 +69,9 @@ public static partial class OpenIddictClientHandlers
// (e.g when custom parameters are manually added to the response), the static
// conversion operator would take care of converting the underlying value to a
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateClaimType(string name, OpenIddictParameter value) => name switch
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The 'sub' parameter MUST be formatted as a unique string value.
// The following parameters MUST be formatted as unique strings:
Claims.Subject => ((JsonElement) value).ValueKind is JsonValueKind.String,
// Parameters that are not in the well-known list can be of any type.

143
src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs

@ -5,6 +5,7 @@
*/
using System.Collections.Immutable;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;
namespace OpenIddict.Validation;
@ -18,6 +19,7 @@ public static partial class OpenIddictValidationHandlers
* Configuration response handling:
*/
HandleErrorResponse<HandleConfigurationResponseContext>.Descriptor,
ValidateWellKnownConfigurationParameters.Descriptor,
ValidateIssuer.Descriptor,
ExtractCryptographyEndpoint.Descriptor,
ExtractIntrospectionEndpoint.Descriptor,
@ -27,8 +29,80 @@ public static partial class OpenIddictValidationHandlers
* Cryptography response handling:
*/
HandleErrorResponse<HandleCryptographyResponseContext>.Descriptor,
ValidateWellKnownCryptographyParameters.Descriptor,
ExtractSigningKeys.Descriptor);
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the configuration response.
/// </summary>
public class ValidateWellKnownConfigurationParameters : IOpenIddictValidationHandler<HandleConfigurationResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleConfigurationResponseContext>()
.UseSingletonHandler<ValidateWellKnownConfigurationParameters>()
.SetOrder(HandleErrorResponse<HandleConfigurationResponseContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleConfigurationResponseContext context!!)
{
foreach (var parameter in context.Response.GetParameters())
{
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
}
}
return default;
// Note: in the typical case, the response parameters should be deserialized from a
// JSON response and thus natively stored as System.Text.Json.JsonElement instances.
//
// In the rare cases where the underlying value wouldn't be a JsonElement instance
// (e.g when custom parameters are manually added to the response), the static
// conversion operator would take care of converting the underlying value to a
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The following parameters MUST be formatted as unique strings:
Metadata.IntrospectionEndpoint or
Metadata.Issuer
=> ((JsonElement) value).ValueKind is JsonValueKind.String,
// The following parameters MUST be formatted as arrays of strings:
Metadata.IntrospectionEndpointAuthMethodsSupported
=> ((JsonElement) value) is JsonElement element &&
element.ValueKind is JsonValueKind.Array && ValidateStringArray(element),
// Parameters that are not in the well-known list can be of any type.
_ => true
};
static bool ValidateStringArray(JsonElement element)
{
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind is not JsonValueKind.String)
{
return false;
}
}
return true;
}
}
}
/// <summary>
/// Contains the logic responsible for extracting the issuer from the discovery document.
/// </summary>
@ -40,7 +114,7 @@ public static partial class OpenIddictValidationHandlers
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleConfigurationResponseContext>()
.UseSingletonHandler<ValidateIssuer>()
.SetOrder(HandleErrorResponse<HandleConfigurationResponseContext>.Descriptor.Order + 1_000)
.SetOrder(ValidateWellKnownConfigurationParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -199,6 +273,71 @@ public static partial class OpenIddictValidationHandlers
}
}
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the JWKS response.
/// </summary>
public class ValidateWellKnownCryptographyParameters : IOpenIddictValidationHandler<HandleCryptographyResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
.UseSingletonHandler<ValidateWellKnownCryptographyParameters>()
.SetOrder(HandleErrorResponse<HandleCryptographyResponseContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context!!)
{
foreach (var parameter in context.Response.GetParameters())
{
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
}
}
return default;
// Note: in the typical case, the response parameters should be deserialized from a
// JSON response and thus natively stored as System.Text.Json.JsonElement instances.
//
// In the rare cases where the underlying value wouldn't be a JsonElement instance
// (e.g when custom parameters are manually added to the response), the static
// conversion operator would take care of converting the underlying value to a
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The following parameters MUST be formatted as arrays of objects:
JsonWebKeySetParameterNames.Keys => ((JsonElement) value) is JsonElement element &&
element.ValueKind is JsonValueKind.Array && ValidateObjectArray(element),
// Parameters that are not in the well-known list can be of any type.
_ => true
};
static bool ValidateObjectArray(JsonElement element)
{
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind is not JsonValueKind.Object)
{
return false;
}
}
return true;
}
}
}
/// <summary>
/// Contains the logic responsible for extracting the signing keys from the JWKS document.
/// </summary>
@ -210,7 +349,7 @@ public static partial class OpenIddictValidationHandlers
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
.UseSingletonHandler<ExtractSigningKeys>()
.SetOrder(HandleErrorResponse<HandleCryptographyResponseContext>.Descriptor.Order + 1_000)
.SetOrder(ValidateWellKnownCryptographyParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();

136
src/OpenIddict.Validation/OpenIddictValidationHandlers.Introspection.cs

@ -26,8 +26,8 @@ public static partial class OpenIddictValidationHandlers
* Introspection response handling:
*/
HandleErrorResponse<HandleIntrospectionResponseContext>.Descriptor,
ValidateWellKnownParameters.Descriptor,
HandleInactiveResponse.Descriptor,
ValidateWellKnownClaims.Descriptor,
ValidateIssuer.Descriptor,
ValidateTokenUsage.Descriptor,
PopulateClaims.Descriptor);
@ -83,85 +83,34 @@ public static partial class OpenIddictValidationHandlers
}
/// <summary>
/// Contains the logic responsible for extracting the active: false marker from the response.
/// Contains the logic responsible for validating the well-known parameters contained in the introspection response.
/// </summary>
public class HandleInactiveResponse : IOpenIddictValidationHandler<HandleIntrospectionResponseContext>
public class ValidateWellKnownParameters : IOpenIddictValidationHandler<HandleIntrospectionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleIntrospectionResponseContext>()
.UseSingletonHandler<HandleInactiveResponse>()
.UseSingletonHandler<ValidateWellKnownParameters>()
.SetOrder(HandleErrorResponse<HandleIntrospectionResponseContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleIntrospectionResponseContext context!!)
{
// Note: the introspection specification requires that server return "active: false" instead of a proper
// OAuth 2.0 error when the token is invalid, expired, revoked or invalid for any other reason.
// While OpenIddict's server can be tweaked to return a proper error (by removing NormalizeErrorResponse)
// from the enabled handlers, supporting "active: false" is required to ensure total compatibility.
if (!context.Response.TryGetParameter(Parameters.Active, out var parameter))
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2105(Parameters.Active),
uri: SR.FormatID8000(SR.ID2105));
return default;
}
// Note: if the parameter cannot be converted to a boolean instance, the default value
// (false) is returned by the static operator, which is appropriate for this check.
if (!(bool) parameter)
{
context.Reject(
error: Errors.InvalidToken,
description: SR.GetResourceString(SR.ID2106),
uri: SR.FormatID8000(SR.ID2106));
return default;
}
return default;
}
}
/// <summary>
/// Contains the logic responsible for validating the well-known claims contained in the introspection response.
/// </summary>
public class ValidateWellKnownClaims : IOpenIddictValidationHandler<HandleIntrospectionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleIntrospectionResponseContext>()
.UseSingletonHandler<ValidateWellKnownClaims>()
.SetOrder(HandleInactiveResponse.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleIntrospectionResponseContext context!!)
{
foreach (var parameter in context.Response.GetParameters())
{
if (ValidateClaimType(parameter.Key, parameter.Value))
if (!ValidateParameterType(parameter.Key, parameter.Value))
{
continue;
}
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2107(parameter.Key),
uri: SR.FormatID8000(SR.ID2107));
return default;
return default;
}
}
return default;
@ -173,24 +122,27 @@ public static partial class OpenIddictValidationHandlers
// (e.g when custom parameters are manually added to the response), the static
// conversion operator would take care of converting the underlying value to a
// JsonElement instance using the same value type as the original parameter value.
static bool ValidateClaimType(string name, OpenIddictParameter value) => name switch
static bool ValidateParameterType(string name, OpenIddictParameter value) => name switch
{
// The 'jti', 'iss', 'scope' and 'token_usage' claims MUST be formatted as a unique string.
// The following parameters MUST be formatted as booleans:
Claims.Active => ((JsonElement) value).ValueKind is JsonValueKind.True or JsonValueKind.False,
// The following parameters MUST be formatted as unique strings:
Claims.JwtId or Claims.Issuer or Claims.Scope or Claims.TokenUsage
=> ((JsonElement) value).ValueKind is JsonValueKind.String,
// The 'aud' claim MUST be represented either as a unique string or as an array of strings.
// The following parameters MUST be formatted as strings or arrays of strings:
//
// Note: empty arrays and arrays that contain a single value are also considered valid.
Claims.Audience => ((JsonElement) value) is JsonElement element &&
element.ValueKind is JsonValueKind.String ||
(element.ValueKind is JsonValueKind.Array && ValidateStringArray(element)),
// The 'exp', 'iat' and 'nbf' claims MUST be formatted as numeric date values.
// The following parameters MUST be formatted as numeric dates:
Claims.ExpiresAt or Claims.IssuedAt or Claims.NotBefore
=> ((JsonElement) value).ValueKind is JsonValueKind.Number,
// Claims that are not in the well-known list can be of any type.
// Parameters that are not in the well-known list can be of any type.
_ => true
};
@ -209,6 +161,54 @@ public static partial class OpenIddictValidationHandlers
}
}
/// <summary>
/// Contains the logic responsible for extracting the active: false marker from the response.
/// </summary>
public class HandleInactiveResponse : IOpenIddictValidationHandler<HandleIntrospectionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleIntrospectionResponseContext>()
.UseSingletonHandler<HandleInactiveResponse>()
.SetOrder(ValidateWellKnownParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleIntrospectionResponseContext context!!)
{
// Note: the introspection specification requires that server return "active: false" instead of a proper
// OAuth 2.0 error when the token is invalid, expired, revoked or invalid for any other reason.
// While OpenIddict's server can be tweaked to return a proper error (by removing NormalizeErrorResponse)
// from the enabled handlers, supporting "active: false" is required to ensure total compatibility.
var active = (bool?) context.Response[Parameters.Active];
if (active is null)
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2105(Parameters.Active),
uri: SR.FormatID8000(SR.ID2105));
return default;
}
if (active is not true)
{
context.Reject(
error: Errors.InvalidToken,
description: SR.GetResourceString(SR.ID2106),
uri: SR.FormatID8000(SR.ID2106));
return default;
}
return default;
}
}
/// <summary>
/// Contains the logic responsible for extracting the issuer from the introspection response.
/// </summary>
@ -220,7 +220,7 @@ public static partial class OpenIddictValidationHandlers
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleIntrospectionResponseContext>()
.UseSingletonHandler<ValidateIssuer>()
.SetOrder(ValidateWellKnownClaims.Descriptor.Order + 1_000)
.SetOrder(ValidateWellKnownParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();

Loading…
Cancel
Save