This is an automated email from the ASF dual-hosted git repository. chibenwa pushed a commit to branch 3.8.x in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 45e20f29ab6f25ea944712f9a9cd675d26332848 Author: Benoit TELLIER <[email protected]> AuthorDate: Fri Jan 16 21:30:34 2026 +0100 [ENHANCEMENT] Validate aud without introspect --- .../java/org/apache/james/jwt/JwtTokenVerifier.java | 20 +++++++++----------- .../org/apache/james/jwt/OidcJwtTokenVerifier.java | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 18 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 66daee29a2..f7a1909599 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 @@ -25,7 +25,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; @@ -33,7 +32,6 @@ import io.jsonwebtoken.Jws; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; public class JwtTokenVerifier { @@ -63,9 +61,15 @@ public class JwtTokenVerifier { } public <T> Optional<T> verifyAndExtractClaim(String token, String claimName, Class<T> returnType) { - 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) { @@ -74,12 +78,6 @@ public class JwtTokenVerifier { .findFirst(); } - 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.parseClaimsJws(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 b1ca932fe8..dea93ea239 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 @@ -77,15 +77,20 @@ public class OidcJwtTokenVerifier { @VisibleForTesting Optional<String> verifySignatureAndExtractClaim(String jwtToken) { - Optional<String> unverifiedClaim = getClaimWithoutSignatureVerification(jwtToken, "kid"); - PublicKeyProvider jwksPublicKeyProvider = unverifiedClaim + try { + Optional<String> unverifiedClaim = getClaimWithoutSignatureVerification(jwtToken, "kid"); + PublicKeyProvider jwksPublicKeyProvider = unverifiedClaim .map(kidValue -> JwksPublicKeyProvider.of(oidcSASLConfiguration.getJwksURL(), kidValue)) .orElse(JwksPublicKeyProvider.of(oidcSASLConfiguration.getJwksURL())); - return new JwtTokenVerifier(jwksPublicKeyProvider) - .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))); + return new JwtTokenVerifier(jwksPublicKeyProvider) + .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(); + } } private <T> Optional<T> getClaimWithoutSignatureVerification(String token, String claimName) { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
