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

roryqi pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-1.3 by this push:
     new 3de4b5a92a [Cherry-pick to branch-1.3] [#13971] fix(auth): preserve 
UnauthorizedException from PrincipalMapper in JWKS validation (#13972) (#14025)
3de4b5a92a is described below

commit 3de4b5a92a3dfcb50e0bd4a42494e8fcc852f7f2
Author: MaSai <[email protected]>
AuthorDate: Wed Oct 21 14:33:19 2026 +0800

    [Cherry-pick to branch-1.3] [#13971] fix(auth): preserve 
UnauthorizedException from PrincipalMapper in JWKS validation (#13972) (#14025)
    
    **Cherry-pick Information:**
    - Original commit: 25bfe375f152a91dfd9ad01d789f929be6e645ef
    - Target branch: `branch-1.3`
    - Status: ✅ Clean cherry-pick (no conflicts)
    
    Co-authored-by: Cursor <[email protected]>
---
 .../server/authentication/JwksTokenValidator.java  |  2 +
 .../authentication/TestJwksTokenValidator.java     | 55 ++++++++++++++++++++++
 2 files changed, 57 insertions(+)

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 32e47b84e1..3605f016c9 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
@@ -170,6 +170,8 @@ public class JwksTokenValidator implements 
OAuthTokenValidator {
 
     } catch (ExpiredJWTException e) {
       throw new TokenExpiredException(e, "Authentication token is expired");
+    } catch (UnauthorizedException e) {
+      throw e;
     } catch (Exception e) {
       LOG.warn(
           "JWKS JWT validation failed for principal [{}]: {}",
diff --git 
a/server-common/src/test/java/org/apache/gravitino/server/authentication/TestJwksTokenValidator.java
 
b/server-common/src/test/java/org/apache/gravitino/server/authentication/TestJwksTokenValidator.java
index 2fb1c1f2f7..db0b56eea5 100644
--- 
a/server-common/src/test/java/org/apache/gravitino/server/authentication/TestJwksTokenValidator.java
+++ 
b/server-common/src/test/java/org/apache/gravitino/server/authentication/TestJwksTokenValidator.java
@@ -46,8 +46,10 @@ import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.gravitino.Config;
 import org.apache.gravitino.UserPrincipal;
+import org.apache.gravitino.auth.PrincipalMapper;
 import org.apache.gravitino.exceptions.TokenExpiredException;
 import org.apache.gravitino.exceptions.UnauthorizedException;
 import org.junit.jupiter.api.BeforeEach;
@@ -771,4 +773,57 @@ public class TestJwksTokenValidator {
       assertTrue(exception.getMessage().contains("expired"));
     }
   }
+
+  @Test
+  public void 
testValidateTokenPreservesUnauthorizedExceptionFromPrincipalMapper()
+      throws Exception {
+    RSAKey rsaKey =
+        new 
RSAKeyGenerator(2048).keyID("test-key-id").algorithm(JWSAlgorithm.RS256).generate();
+
+    JWTClaimsSet claimsSet =
+        new JWTClaimsSet.Builder()
+            .subject("disabled-user")
+            .audience("test-service")
+            .issuer("https://test-issuer.com";)
+            .expirationTime(Date.from(Instant.now().plusSeconds(3600)))
+            .issueTime(Date.from(Instant.now()))
+            .build();
+
+    SignedJWT signedJWT =
+        new SignedJWT(
+            new 
JWSHeader.Builder(JWSAlgorithm.RS256).keyID("test-key-id").build(), claimsSet);
+    signedJWT.sign(new RSASSASigner(rsaKey));
+    String tokenString = signedJWT.serialize();
+
+    try (MockedStatic<JWKSourceBuilder> mockedBuilder = 
mockStatic(JWKSourceBuilder.class)) {
+      @SuppressWarnings("unchecked")
+      JWKSource<SecurityContext> mockJwkSource = mock(JWKSource.class);
+      @SuppressWarnings("unchecked")
+      JWKSourceBuilder<SecurityContext> mockBuilder = 
mock(JWKSourceBuilder.class);
+
+      mockedBuilder.when(() -> 
JWKSourceBuilder.create(any(URL.class))).thenReturn(mockBuilder);
+      when(mockBuilder.build()).thenReturn(mockJwkSource);
+      when(mockJwkSource.get(any(), any())).thenReturn(Arrays.asList(rsaKey));
+
+      Map<String, String> config = new HashMap<>();
+      config.put(
+          "gravitino.authenticator.oauth.jwksUri", 
"https://test-jwks.com/.well-known/jwks.json";);
+      config.put("gravitino.authenticator.oauth.authority", 
"https://test-issuer.com";);
+      config.put("gravitino.authenticator.oauth.principalMapper", "regex");
+      
config.put("gravitino.authenticator.oauth.principalMapper.regex.pattern", 
"(.*)");
+      config.put("gravitino.authenticator.oauth.allowSkewSecs", "120");
+
+      validator.initialize(createConfig(config));
+
+      PrincipalMapper rejectingMapper = mock(PrincipalMapper.class);
+      when(rejectingMapper.map(any())).thenThrow(new 
UnauthorizedException("Invalid access token"));
+      FieldUtils.writeField(validator, "principalMapper", rejectingMapper, 
true);
+
+      UnauthorizedException exception =
+          assertThrows(
+              UnauthorizedException.class,
+              () -> validator.validateToken(tokenString, "test-service"));
+      assertEquals("Invalid access token", exception.getMessage());
+    }
+  }
 }

Reply via email to