This is an automated email from the ASF dual-hosted git repository.

diqiu50 pushed a commit to branch cherry-pick/10746-to-branch-1.2
in repository https://gitbox.apache.org/repos/asf/gravitino.git

commit a2fb26abade63a0a37a7e070aff7d172ddf9bc37
Author: Bharath Krishna <[email protected]>
AuthorDate: Sat Apr 11 00:29:29 2026 -0700

    [Cherry-pick to branch-1.2] [#10746] fix(auth): Cache JWKSource and 
downgrade token validation log to WARN (#10723)
---
 .../server/authentication/JwksTokenValidator.java  | 39 +++++++++++++++-------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authentication/JwksTokenValidator.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authentication/JwksTokenValidator.java
index e358a8998d..1db58ddc0a 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authentication/JwksTokenValidator.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authentication/JwksTokenValidator.java
@@ -57,6 +57,8 @@ public class JwksTokenValidator implements 
OAuthTokenValidator {
   private List<String> principalFields;
   private long allowSkewSeconds;
   private PrincipalMapper principalMapper;
+  private GroupMapper groupMapper;
+  private JWKSource<SecurityContext> jwkSource;
 
   @Override
   public void initialize(Config config) {
@@ -77,12 +79,17 @@ public class JwksTokenValidator implements 
OAuthTokenValidator {
           "JWKS URI must be configured when using JWKS-based OAuth providers");
     }
 
-    // Validate JWKS URI format
+    // Create the JWK source once at initialization. 
JWKSourceBuilder.create(url).build() enables
+    // rate-limiting (min 30 s between URL fetches) and caching with 
refresh-ahead by default:
+    //   - Cache TTL: 5 minutes (DEFAULT_CACHE_TIME_TO_LIVE)
+    //   - Refresh-ahead: 30 seconds before expiration on a background thread
+    // The Nimbus library handles key rotation transparently within these 
defaults.
     try {
-      new URL(jwksUri);
+      this.jwkSource = JWKSourceBuilder.create(new URL(jwksUri)).build();
     } catch (Exception e) {
-      LOG.error("Invalid JWKS URI format: {}", jwksUri);
-      throw new IllegalArgumentException("Invalid JWKS URI format: " + 
jwksUri, e);
+      LOG.error("Failed to create JWKS source from URI: {}", jwksUri, e);
+      throw new IllegalArgumentException(
+          "Invalid JWKS URI or failed to create JWKS source: " + jwksUri, e);
     }
   }
 
@@ -102,7 +109,6 @@ public class JwksTokenValidator implements 
OAuthTokenValidator {
       SignedJWT signedJWT = SignedJWT.parse(token);
 
       // Set up JWKS source and processor
-      JWKSource<SecurityContext> jwkSource = createJwkSource();
       JWSAlgorithm algorithm = 
JWSAlgorithm.parse(signedJWT.getHeader().getAlgorithm().getName());
       JWSKeySelector<SecurityContext> keySelector =
           new JWSVerificationKeySelector<>(algorithm, jwkSource);
@@ -143,18 +149,27 @@ public class JwksTokenValidator implements 
OAuthTokenValidator {
       return principalMapper.map(principal);
 
     } catch (Exception e) {
-      LOG.error("JWKS JWT validation error: {}", e.getMessage());
+      LOG.warn(
+          "JWKS JWT validation failed for principal [{}]: {}",
+          extractPrincipalForLogging(signedJWT),
+          e.getMessage());
       throw new UnauthorizedException(e, "JWKS JWT validation error");
     }
   }
 
-  /** Creates a JWK source from the configured JWKS URI. */
-  private JWKSource<SecurityContext> createJwkSource() throws Exception {
+  /**
+   * Extracts the principal from a parsed (but not yet verified) JWT for 
diagnostic logging. Safe to
+   * call with a null or invalid JWT.
+   */
+  String extractPrincipalForLogging(SignedJWT signedJWT) {
+    if (signedJWT == null) {
+      return "unknown";
+    }
     try {
-      return JWKSourceBuilder.create(new URL(jwksUri)).build();
-    } catch (Exception e) {
-      LOG.error("Failed to create JWKS source from URI: {}", jwksUri, e);
-      throw new Exception("Failed to create JWKS source: " + e.getMessage(), 
e);
+      String principal = extractPrincipal(signedJWT.getJWTClaimsSet());
+      return principal != null ? principal : "unknown";
+    } catch (Exception ex) {
+      return "unknown";
     }
   }
 

Reply via email to