From 682af18392a68934cc07adaccb630c3eae5d3279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Wed, 8 Jul 2020 03:25:57 +0200 Subject: [PATCH] Update the TypeValidator custom delegate to avoid throwing when the JWT token has no "typ" header but contains a "token_usage" claim --- src/OpenIddict.Server/OpenIddictServerHandlers.cs | 2 +- src/OpenIddict.Server/OpenIddictServerOptions.cs | 14 ++++++++------ .../OpenIddictValidationHandlers.cs | 2 +- .../OpenIddictValidationOptions.cs | 14 ++++++++------ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs index 7373d134..fc258233 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs @@ -451,7 +451,7 @@ namespace OpenIddict.Server { // If no specific token type is expected, accept all token types at this stage. // Additional filtering can be made based on the resolved/actual token type. - var type when string.IsNullOrEmpty(type) => Array.Empty(), + var type when string.IsNullOrEmpty(type) => null, // For access tokens, both "at+jwt" and "application/at+jwt" are valid. TokenTypeHints.AccessToken => new[] diff --git a/src/OpenIddict.Server/OpenIddictServerOptions.cs b/src/OpenIddict.Server/OpenIddictServerOptions.cs index 2ed562d8..f5658343 100644 --- a/src/OpenIddict.Server/OpenIddictServerOptions.cs +++ b/src/OpenIddict.Server/OpenIddictServerOptions.cs @@ -121,11 +121,6 @@ namespace OpenIddict.Server // This validator overrides the default logic used by IdentityModel to resolve the type from this claim. TypeValidator = (type, token, parameters) => { - if (string.IsNullOrEmpty(type)) - { - throw new SecurityTokenInvalidTypeException("The 'typ' header of the JWT token cannot be null or empty."); - } - // If available, try to resolve the actual type from the "token_usage" claim. if (((JsonWebToken) token).TryGetPayloadValue(OpenIddictConstants.Claims.TokenUsage, out string usage)) { @@ -138,7 +133,14 @@ namespace OpenIddict.Server }; } - // Unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons. + // At this point, throw an exception if the type cannot be resolved from the "typ" header + // (provided via the type delegate parameter) or inferred from the token_usage claim. + if (string.IsNullOrEmpty(type)) + { + throw new SecurityTokenInvalidTypeException("The type of the JWT token cannot be resolved or inferred."); + } + + // Note: unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons. if (parameters.ValidTypes != null && parameters.ValidTypes.Any() && !parameters.ValidTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) { diff --git a/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs b/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs index 6d031a2f..20448a4f 100644 --- a/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs +++ b/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs @@ -238,7 +238,7 @@ namespace OpenIddict.Validation { // If no specific token type is expected, accept all token types at this stage. // Additional filtering can be made based on the resolved/actual token type. - var type when string.IsNullOrEmpty(type) => Array.Empty(), + var type when string.IsNullOrEmpty(type) => null, // For access tokens, both "at+jwt" and "application/at+jwt" are valid. TokenTypeHints.AccessToken => new[] diff --git a/src/OpenIddict.Validation/OpenIddictValidationOptions.cs b/src/OpenIddict.Validation/OpenIddictValidationOptions.cs index 6ecdf1f9..a1efb09a 100644 --- a/src/OpenIddict.Validation/OpenIddictValidationOptions.cs +++ b/src/OpenIddict.Validation/OpenIddictValidationOptions.cs @@ -118,11 +118,6 @@ namespace OpenIddict.Validation // This validator overrides the default logic used by IdentityModel to resolve the type from this claim. TypeValidator = (type, token, parameters) => { - if (string.IsNullOrEmpty(type)) - { - throw new SecurityTokenInvalidTypeException("The 'typ' header of the JWT token cannot be null or empty."); - } - // If available, try to resolve the actual type from the "token_usage" claim. if (((JsonWebToken) token).TryGetPayloadValue(Claims.TokenUsage, out string usage)) { @@ -135,7 +130,14 @@ namespace OpenIddict.Validation }; } - // Unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons. + // At this point, throw an exception if the type cannot be resolved from the "typ" header + // (provided via the type delegate parameter) or inferred from the token_usage claim. + if (string.IsNullOrEmpty(type)) + { + throw new SecurityTokenInvalidTypeException("The type of the JWT token cannot be resolved or inferred."); + } + + // Note: unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons. if (parameters.ValidTypes != null && parameters.ValidTypes.Any() && !parameters.ValidTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) {