From 9579485cd61e4177282f8eed3119c9723d087514 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Tue, 25 Jul 2023 15:28:54 +0100 Subject: [PATCH] Fix OIDC token verification failure message --- .../oidc/runtime/OidcIdentityProvider.java | 35 +++++++++++++------ .../io/quarkus/oidc/runtime/OidcProvider.java | 12 ++++--- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java index 92b31d9072835..ece219a5ef052 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java @@ -424,12 +424,12 @@ private Uni verifyTokenUni(TenantConfigContext resolved } } LOG.debug("Starting the opaque token introspection"); - return introspectTokenUni(resolvedContext, token); + return introspectTokenUni(resolvedContext, token, false); } else if (resolvedContext.provider.getMetadata().getJsonWebKeySetUri() == null || resolvedContext.oidcConfig.token.requireJwtIntrospectionOnly) { // Verify JWT token with the remote introspection LOG.debug("Starting the JWT token introspection"); - return introspectTokenUni(resolvedContext, token); + return introspectTokenUni(resolvedContext, token, false); } else { // Verify JWT token with the local JWK keys with a possible remote introspection fallback try { @@ -458,32 +458,47 @@ private Uni verifySelfSignedTokenUni(TenantConfigContex private Uni refreshJwksAndVerifyTokenUni(TenantConfigContext resolvedContext, String token, boolean enforceAudienceVerification) { return resolvedContext.provider.refreshJwksAndVerifyJwtToken(token, enforceAudienceVerification) - .onFailure(f -> f.getCause() instanceof UnresolvableKeyException - && resolvedContext.oidcConfig.token.allowJwtIntrospection) - .recoverWithUni(f -> introspectTokenUni(resolvedContext, token)); + .onFailure(f -> fallbackToIntrospectionIfNoMatchingKey(f, resolvedContext)) + .recoverWithUni(f -> introspectTokenUni(resolvedContext, token, true)); } - private Uni introspectTokenUni(TenantConfigContext resolvedContext, final String token) { + private static boolean fallbackToIntrospectionIfNoMatchingKey(Throwable f, TenantConfigContext resolvedContext) { + if (!(f.getCause() instanceof UnresolvableKeyException)) { + LOG.debug("Local JWT token verification has failed, skipping the token introspection"); + return false; + } else if (!resolvedContext.oidcConfig.token.allowJwtIntrospection) { + LOG.debug("JWT token does not have a matching verification key but JWT token introspection is disabled"); + return false; + } else { + LOG.debug("Local JWT token verification has failed, attempting the token introspection"); + return true; + } + + } + + private Uni introspectTokenUni(TenantConfigContext resolvedContext, final String token, + boolean fallbackFromJwkMatch) { TokenIntrospectionCache tokenIntrospectionCache = tenantResolver.getTokenIntrospectionCache(); Uni tokenIntrospectionUni = tokenIntrospectionCache == null ? null : tokenIntrospectionCache .getIntrospection(token, resolvedContext.oidcConfig, getIntrospectionRequestContext); if (tokenIntrospectionUni == null) { - tokenIntrospectionUni = newTokenIntrospectionUni(resolvedContext, token); + tokenIntrospectionUni = newTokenIntrospectionUni(resolvedContext, token, fallbackFromJwkMatch); } else { tokenIntrospectionUni = tokenIntrospectionUni.onItem().ifNull() .switchTo(new Supplier>() { @Override public Uni get() { - return newTokenIntrospectionUni(resolvedContext, token); + return newTokenIntrospectionUni(resolvedContext, token, fallbackFromJwkMatch); } }); } return tokenIntrospectionUni.onItem().transform(t -> new TokenVerificationResult(null, t)); } - private Uni newTokenIntrospectionUni(TenantConfigContext resolvedContext, String token) { - Uni tokenIntrospectionUni = resolvedContext.provider.introspectToken(token); + private Uni newTokenIntrospectionUni(TenantConfigContext resolvedContext, String token, + boolean fallbackFromJwkMatch) { + Uni tokenIntrospectionUni = resolvedContext.provider.introspectToken(token, fallbackFromJwkMatch); if (tenantResolver.getTokenIntrospectionCache() == null || !resolvedContext.oidcConfig.allowTokenIntrospectionCache) { return tokenIntrospectionUni; } else { diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java index 9757fbd93b4f0..9df7e34a2c4a3 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java @@ -267,13 +267,15 @@ public Uni apply(Void v) { }); } - public Uni introspectToken(String token) { + public Uni introspectToken(String token, boolean fallbackFromJwkMatch) { if (client.getMetadata().getIntrospectionUri() == null) { - LOG.debugf( - "Token issued to client %s can not be introspected because the introspection endpoint address is unknown - " - + "please check if your OpenId Connect Provider supports the token introspection", + String errorMessage = String.format("Token issued to client %s " + + (fallbackFromJwkMatch ? "does not have a matching verification key and it " : "") + + "can not be introspected because the introspection endpoint address is unknown - " + + "please check if your OpenId Connect Provider supports the token introspection", oidcConfig.clientId.get()); - throw new AuthenticationFailedException(); + + throw new AuthenticationFailedException(errorMessage); } return client.introspectToken(token).onItemOrFailure() .transform(new BiFunction() {