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
The following commit(s) were added to refs/heads/master by this push:
new 36c01ab JAMES-3680 JwtTokenVerifier should allow extracting a claim
(#779)
36c01ab is described below
commit 36c01ab93d1d2aa02965df7286dcb80210314108
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Dec 6 21:13:22 2021 +0700
JAMES-3680 JwtTokenVerifier should allow extracting a claim (#779)
---
.../org/apache/james/jwt/JwtTokenVerifier.java | 43 +++++++++-------------
.../org/apache/james/jwt/JwtTokenVerifierTest.java | 34 +++++++++++++++++
2 files changed, 51 insertions(+), 26 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 8a8feeb..cc6baba 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,8 +25,6 @@ import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Strings;
-
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
@@ -53,44 +51,37 @@ public class JwtTokenVerifier {
}
public Optional<String> verifyAndExtractLogin(String token) {
+ return verifyAndExtractClaim(token, "sub", String.class)
+ .filter(s -> !s.isEmpty());
+ }
+
+ public <T> Optional<T> verifyAndExtractClaim(String token, String
claimName, Class<T> returnType) {
return publicKeys.stream()
- .flatMap(key -> verifyAndExtractLogin(token, key).stream())
+ .flatMap(key -> verifyAndExtractClaim(token, claimName,
returnType, key).stream())
.findFirst();
}
- public Optional<String> verifyAndExtractLogin(String token, PublicKey key)
{
+ private <T> Optional<T> verifyAndExtractClaim(String token, String
claimName, Class<T> returnType, PublicKey publicKey) {
try {
- String subject = extractLogin(token, key);
- if (Strings.isNullOrEmpty(subject)) {
- throw new MalformedJwtException("'subject' field in token is
mandatory");
+ Jws<Claims> jws = parseToken(token, publicKey);
+ T claim = jws
+ .getBody()
+ .get(claimName, returnType);
+ if (claim == null) {
+ throw new MalformedJwtException("'" + claimName + "' field in
token is mandatory");
}
- return Optional.of(subject);
+ return Optional.of(claim);
} catch (JwtException e) {
LOGGER.info("Failed Jwt verification", e);
return Optional.empty();
}
}
- private String extractLogin(String token, PublicKey publicKey) throws
JwtException {
- Jws<Claims> jws = parseToken(token, publicKey);
- return jws
- .getBody()
- .getSubject();
- }
-
public boolean hasAttribute(String attributeName, Object expectedValue,
String token) {
- return publicKeys.stream()
- .anyMatch(key -> hasAttribute(attributeName, expectedValue, token,
key));
- }
-
- private boolean hasAttribute(String attributeName, Object expectedValue,
String token, PublicKey publicKey) {
try {
- Jwts
- .parser()
- .require(attributeName, expectedValue)
- .setSigningKey(publicKey)
- .parseClaimsJws(token);
- return true;
+ return verifyAndExtractClaim(token, attributeName, Object.class)
+ .map(expectedValue::equals)
+ .orElse(false);
} catch (JwtException e) {
LOGGER.info("Jwt validation failed for claim {} to {}",
attributeName, expectedValue, e);
return false;
diff --git
a/server/protocols/jwt/src/test/java/org/apache/james/jwt/JwtTokenVerifierTest.java
b/server/protocols/jwt/src/test/java/org/apache/james/jwt/JwtTokenVerifierTest.java
index 3bfe79b..3e67427 100644
---
a/server/protocols/jwt/src/test/java/org/apache/james/jwt/JwtTokenVerifierTest.java
+++
b/server/protocols/jwt/src/test/java/org/apache/james/jwt/JwtTokenVerifierTest.java
@@ -88,6 +88,40 @@ class JwtTokenVerifierTest {
}
@Test
+ void verifyAndExtractClaimShouldAllowExtractingClaim() {
+ assertThat(sut.verifyAndExtractClaim(VALID_TOKEN_WITHOUT_ADMIN,
"name", String.class))
+ .contains("John Doe");
+ }
+
+ @Test
+ void verifyAndExtractClaimShouldReturnEmptyWhenBadDatatype() {
+ assertThat(sut.verifyAndExtractClaim(VALID_TOKEN_WITHOUT_ADMIN,
"name", Integer.class))
+ .isEmpty();
+ }
+
+ @Test
+ void verifyAndExtractClaimShouldReturnEmptyWhenNotFound() {
+ assertThat(sut.verifyAndExtractClaim(VALID_TOKEN_WITHOUT_ADMIN,
"notFound", String.class))
+ .isEmpty();
+ }
+
+
+ @Test
+ void verifyAndExtractClaimShouldReturnEmptyWhenNoneAlgorithm() {
+ assertThat(sut.verifyAndExtractClaim(TOKEN_NONE_ALGORITHM, "name",
String.class))
+ .isEmpty();
+ }
+
+ @Test
+ void verifyAndExtractLoginShouldReturnEmptyOnMismatchingSigningKey() {
+ String invalidToken =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.Pd6t82"
+
+
"tPL3EZdkeYxw_DV2KimE1U2FvuLHmfR_mimJ5US3JFU4J2Gd94O7rwpSTGN1B9h-_lsTebo4ua4xHsTtmczZ9xa8a_kWKaSkqFjNFa"
+
+ "Fp6zcoD6ivCu03SlRqsQzSRHXo6TKbnqOt9D6Y2rNa3C4igSwoS0jUE4BgpXbc0";
+
+ assertThat(sut.verifyAndExtractClaim(invalidToken, "name",
String.class)).isEmpty();
+ }
+
+ @Test
void shouldReturnTrueOnValidSignatureWithMultipleKeys() {
PublicKeyProvider pubKeyProvider = new PublicKeyProvider(new
JwtConfiguration(ImmutableList.of(PUBLIC_PEM_KEY_2, PUBLIC_PEM_KEY)), new
PublicKeyReader());
JwtTokenVerifier sut = new JwtTokenVerifier(pubKeyProvider);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]