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

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 321c83c1090e6274b685d9f597d7f6579d7c9b9d
Author: Benoit TELLIER <[email protected]>
AuthorDate: Fri Jan 16 21:30:34 2026 +0100

    [ENHANCEMENT] Validate aud without introspect
---
 .../org/apache/james/jwt/JwtTokenVerifier.java     | 26 ++++++++--------------
 .../org/apache/james/jwt/OidcJwtTokenVerifier.java | 16 ++++++++-----
 2 files changed, 20 insertions(+), 22 deletions(-)

diff --git 
a/server/protocols/jwt/src/main/java/org/apache/james/jwt/JwtTokenVerifier.java 
b/server/protocols/jwt/src/main/java/org/apache/james/jwt/JwtTokenVerifier.java
index f5b79927ec..7fb8350c15 100644
--- 
a/server/protocols/jwt/src/main/java/org/apache/james/jwt/JwtTokenVerifier.java
+++ 
b/server/protocols/jwt/src/main/java/org/apache/james/jwt/JwtTokenVerifier.java
@@ -29,7 +29,6 @@ import java.util.Optional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.github.fge.lambdas.Throwing;
 import com.google.common.collect.ImmutableList;
 
 import io.jsonwebtoken.Claims;
@@ -38,7 +37,6 @@ import io.jsonwebtoken.JwtException;
 import io.jsonwebtoken.JwtParser;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.Locator;
-import io.jsonwebtoken.MalformedJwtException;
 import io.jsonwebtoken.io.CompressionAlgorithm;
 
 public class JwtTokenVerifier {
@@ -122,15 +120,15 @@ public class JwtTokenVerifier {
     }
 
     public <T> Optional<T> verifyAndExtractClaim(String token, String 
claimName, Class<T> returnType) {
-        try {
-            // if the token contains a kid, verify only with the corresponding 
key (or fail)
-            return verifyAndExtractClaim(token, claimName, returnType, 
kidJwtParser);
-        } catch (NullPointerException npe) { // our own key locator throws NPE 
when there is no kid
-            // if token does not specify kid, fallback to trying all keys
-            return jwtParsers.stream()
-                .flatMap(parser -> verifyAndExtractClaim(token, claimName, 
returnType, parser).stream())
-                .findFirst();
-        }
+        return verify(token)
+            .flatMap(claims -> {
+                try {
+                    return Optional.ofNullable(claims.get(claimName, 
returnType));
+                } catch (JwtException e) {
+                    LOGGER.info("Failed Jwt verification", e);
+                    return Optional.empty();
+                }
+            });
     }
 
     public Optional<Claims> verify(String token) {
@@ -145,12 +143,6 @@ public class JwtTokenVerifier {
         }
     }
 
-    private <T> Optional<T> verifyAndExtractClaim(String token, String 
claimName, Class<T> returnType, JwtParser parser) {
-        return retrieveClaims(token, parser)
-            .map(Throwing.function(claims -> 
Optional.ofNullable(claims.get(claimName, returnType))
-                .orElseThrow(() -> new MalformedJwtException("'" + claimName + 
"' field in token is mandatory"))));
-    }
-
     private Optional<Claims> retrieveClaims(String token, JwtParser parser) {
         try {
             Jws<Claims> jws = parser.parseSignedClaims(token);
diff --git 
a/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java
 
b/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java
index 965013a96b..8e5eed7383 100644
--- 
a/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java
+++ 
b/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java
@@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 
+import io.jsonwebtoken.JwtException;
 import reactor.core.publisher.Mono;
 
 public class OidcJwtTokenVerifier {
@@ -72,11 +73,16 @@ public class OidcJwtTokenVerifier {
 
     @VisibleForTesting
     Optional<String> verifySignatureAndExtractClaim(String jwtToken) {
-        return new 
JwtTokenVerifier(JwksPublicKeyProvider.of(oidcSASLConfiguration.getJwksURL()))
-            .verify(jwtToken)
-            .filter(claims -> oidcSASLConfiguration.getAud().map(expectedAud 
-> claims.getAudience().contains(expectedAud))
-                .orElse(true)) // true if no aud is configured
-            .flatMap(claims -> 
Optional.ofNullable(claims.get(oidcSASLConfiguration.getClaim(), 
String.class)));
+        try {
+            return new 
JwtTokenVerifier(JwksPublicKeyProvider.of(oidcSASLConfiguration.getJwksURL()))
+                .verify(jwtToken)
+                .filter(claims -> 
oidcSASLConfiguration.getAud().map(expectedAud -> 
claims.getAudience().contains(expectedAud))
+                    .orElse(true)) // true if no aud is configured
+                .flatMap(claims -> 
Optional.ofNullable(claims.get(oidcSASLConfiguration.getClaim(), 
String.class)));
+        } catch (JwtException e) {
+            LOGGER.info("Failed Jwt verification", e);
+            return Optional.empty();
+        }
     }
 
     @VisibleForTesting


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to