This is an automated email from the ASF dual-hosted git repository.
technoboy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/master by this push:
new 270120ce6e3 [improve][misc] Upgrade jjwt library version to 0.13.0
(#25043)
270120ce6e3 is described below
commit 270120ce6e33e5a084397ca31186f1bb87835e48
Author: Lari Hotari <[email protected]>
AuthorDate: Tue Dec 9 03:49:06 2025 +0200
[improve][misc] Upgrade jjwt library version to 0.13.0 (#25043)
---
distribution/server/src/assemble/LICENSE.bin.txt | 6 +--
pom.xml | 16 ++-----
pulsar-broker-auth-oidc/pom.xml | 4 --
.../AuthenticationProviderToken.java | 27 +++++------
.../MultiRolesTokenAuthorizationProvider.java | 55 ++++++++++++----------
.../AuthenticationProviderTokenTest.java | 12 ++---
.../MultiRolesTokenAuthorizationProviderTest.java | 10 ++--
.../pulsar/utils/auth/tokens/TokensCliUtils.java | 4 +-
.../utils/auth/tokens/TokensCliUtilsTest.java | 12 ++---
9 files changed, 68 insertions(+), 78 deletions(-)
diff --git a/distribution/server/src/assemble/LICENSE.bin.txt
b/distribution/server/src/assemble/LICENSE.bin.txt
index 5af59139404..3950efbf886 100644
--- a/distribution/server/src/assemble/LICENSE.bin.txt
+++ b/distribution/server/src/assemble/LICENSE.bin.txt
@@ -488,9 +488,9 @@ The Apache Software License, Version 2.0
* OpenHFT
- net.openhft-zero-allocation-hashing-0.16.jar
* Java JSON WebTokens
- - io.jsonwebtoken-jjwt-api-0.11.1.jar
- - io.jsonwebtoken-jjwt-impl-0.11.1.jar
- - io.jsonwebtoken-jjwt-jackson-0.11.1.jar
+ - io.jsonwebtoken-jjwt-api-0.13.0.jar
+ - io.jsonwebtoken-jjwt-impl-0.13.0.jar
+ - io.jsonwebtoken-jjwt-jackson-0.13.0.jar
* JCTools - Java Concurrency Tools for the JVM
- org.jctools-jctools-core-4.0.5.jar
* Vertx
diff --git a/pom.xml b/pom.xml
index 162c3be16a3..9394d73db50 100644
--- a/pom.xml
+++ b/pom.xml
@@ -250,7 +250,7 @@ flexible messaging model and an intuitive client
API.</description>
<debezium.version>3.2.5.Final</debezium.version>
<debezium.postgresql.version>${postgresql-jdbc.version}</debezium.postgresql.version>
<debezium.mysql.version>9.4.0</debezium.mysql.version>
- <jsonwebtoken.version>0.11.1</jsonwebtoken.version>
+ <jsonwebtoken.version>0.13.0</jsonwebtoken.version>
<opencensus.version>0.28.0</opencensus.version>
<hadoop3.version>3.4.2</hadoop3.version>
<dnsjava3.version>3.6.2</dnsjava3.version>
@@ -1208,18 +1208,10 @@ flexible messaging model and an intuitive client
API.</description>
<dependency>
<groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-api</artifactId>
- <version>${jsonwebtoken.version}</version>
- </dependency>
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-impl</artifactId>
- <version>${jsonwebtoken.version}</version>
- </dependency>
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-jackson</artifactId>
+ <artifactId>jjwt-bom</artifactId>
<version>${jsonwebtoken.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
</dependency>
<dependency>
diff --git a/pulsar-broker-auth-oidc/pom.xml b/pulsar-broker-auth-oidc/pom.xml
index f50423e144e..14ec21bb58e 100644
--- a/pulsar-broker-auth-oidc/pom.xml
+++ b/pulsar-broker-auth-oidc/pom.xml
@@ -34,10 +34,6 @@
<description>Open ID Connect authentication plugin for broker</description>
<name>Pulsar Broker Auth OIDC</name>
- <properties>
- <jsonwebtoken.version>0.11.5</jsonwebtoken.version>
- </properties>
-
<dependencies>
<dependency>
diff --git
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java
index 74bc85ad3ff..7a1b518831f 100644
---
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java
+++
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java
@@ -23,7 +23,7 @@ import static
org.apache.pulsar.broker.web.AuthenticationFilter.AuthenticatedDat
import static
org.apache.pulsar.broker.web.AuthenticationFilter.AuthenticatedRoleAttributeName;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.Jwt;
+import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
@@ -33,8 +33,9 @@ import io.jsonwebtoken.security.SignatureException;
import java.io.IOException;
import java.net.SocketAddress;
import java.security.Key;
+import java.util.Collection;
import java.util.Date;
-import java.util.List;
+import java.util.Optional;
import javax.naming.AuthenticationException;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletRequest;
@@ -137,7 +138,7 @@ public class AuthenticationProviderToken implements
AuthenticationProvider {
long allowedSkew = getConfTokenAllowedClockSkewSeconds(config);
- this.parser = Jwts.parserBuilder()
+ this.parser = Jwts.parser()
.setAllowedClockSkewSeconds(allowedSkew)
.setSigningKey(this.validationKey)
.build();
@@ -228,9 +229,9 @@ public class AuthenticationProviderToken implements
AuthenticationProvider {
}
@SuppressWarnings("unchecked")
- private Jwt<?, Claims> authenticateToken(final String token) throws
AuthenticationException {
+ private Jws<Claims> authenticateToken(final String token) throws
AuthenticationException {
try {
- Jwt<?, Claims> jwt = parser.parseClaimsJws(token);
+ Jws<Claims> jwt = parser.parseClaimsJws(token);
if (audienceClaim != null) {
Object object = jwt.getBody().get(audienceClaim);
@@ -238,8 +239,8 @@ public class AuthenticationProviderToken implements
AuthenticationProvider {
throw new JwtException("Found null Audience in token, for
claimed field: " + audienceClaim);
}
- if (object instanceof List) {
- List<String> audiences = (List<String>) object;
+ if (object instanceof Collection) {
+ Collection<String> audiences = (Collection<String>) object;
// audience not contains this broker, throw exception.
if (audiences.stream().noneMatch(audienceInToken ->
audienceInToken.equals(audience))) {
incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);
@@ -272,15 +273,13 @@ public class AuthenticationProviderToken implements
AuthenticationProvider {
}
}
- private String getPrincipal(Jwt<?, Claims> jwt) {
+ private String getPrincipal(Jws<Claims> jwt) {
try {
return jwt.getBody().get(roleClaim, String.class);
} catch (RequiredTypeException requiredTypeException) {
- List list = jwt.getBody().get(roleClaim, List.class);
- if (list != null && !list.isEmpty() && list.get(0) instanceof
String) {
- return (String) list.get(0);
- }
- return null;
+ Collection list = jwt.getBody().get(roleClaim, Collection.class);
+ Optional<String> firstEntry =
list.stream().findFirst().map(Object::toString);
+ return firstEntry.orElse(null);
}
}
@@ -358,7 +357,7 @@ public class AuthenticationProviderToken implements
AuthenticationProvider {
private final SocketAddress remoteAddress;
private final SSLSession sslSession;
private AuthenticationDataSource authenticationDataSource;
- private Jwt<?, Claims> jwt;
+ private Jws<Claims> jwt;
private long expiration;
TokenAuthenticationState(
diff --git
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProvider.java
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProvider.java
index fdab233a510..6009da001bf 100644
---
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProvider.java
+++
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProvider.java
@@ -18,13 +18,16 @@
*/
package org.apache.pulsar.broker.authorization;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwt;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.RequiredTypeException;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -64,12 +67,16 @@ public class MultiRolesTokenAuthorizationProvider extends
PulsarAuthorizationPro
// The token's claim that corresponds to the "role" string
static final String CONF_TOKEN_AUTH_CLAIM = "tokenAuthClaim";
+ static final String DEFAULT_ROLE_CLAIM = "roles";
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+
private final JwtParser parser;
private String roleClaim;
public MultiRolesTokenAuthorizationProvider() {
- this.roleClaim = Claims.SUBJECT;
- this.parser = Jwts.parserBuilder().build();
+ this.roleClaim = DEFAULT_ROLE_CLAIM;
+ this.parser = Jwts.parser().unsecured().build();
}
@Override
@@ -179,30 +186,26 @@ public class MultiRolesTokenAuthorizationProvider extends
PulsarAuthorizationPro
log.warn("Unable to extract additional roles from JWT token");
return Collections.emptySet();
}
- String unsignedToken = splitToken[0] + "." + splitToken[1] + ".";
+ String unsignedToken = replaceAlgWithNoneInHeader(splitToken[0]) + "."
+ splitToken[1] + ".";
+ Object jwtRole =
parser.parseUnsecuredClaims(unsignedToken).getBody().get(roleClaim);
+ if (jwtRole instanceof String) {
+ return new HashSet<String>(Collections.singletonList((String)
jwtRole));
+ } else if (jwtRole instanceof Collection) {
+ return new HashSet<>((Collection<String>) jwtRole);
+ } else {
+ return Collections.emptySet();
+ }
+ }
- Jwt<?, Claims> jwt = parser.parseClaimsJwt(unsignedToken);
+ // replace alg with none in header so that it can be parsed in unsecured
mode
+ private static String replaceAlgWithNoneInHeader(String header) {
try {
- final String jwtRole = jwt.getBody().get(roleClaim, String.class);
- if (jwtRole == null) {
- if (log.isDebugEnabled()) {
- log.debug("Do not have corresponding claim in jwt token.
claim={}", roleClaim);
- }
- return Collections.emptySet();
- }
- return new HashSet<>(Collections.singletonList(jwtRole));
- } catch (RequiredTypeException requiredTypeException) {
- try {
- List list = jwt.getBody().get(roleClaim, List.class);
- if (list != null) {
- return new HashSet<String>(list);
- }
- } catch (RequiredTypeException requiredTypeException1) {
- return Collections.emptySet();
- }
+ JsonNode jsonNode =
mapper.readTree(Base64.getDecoder().decode(header));
+ ((ObjectNode) jsonNode).put("alg", "none");
+ return
Base64.getEncoder().withoutPadding().encodeToString(mapper.writeValueAsBytes(jsonNode));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
}
-
- return Collections.emptySet();
}
public CompletableFuture<Boolean> authorize(String role,
AuthenticationDataSource authenticationData,
diff --git
a/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderTokenTest.java
b/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderTokenTest.java
index 8e1aa54522d..a2daace307a 100644
---
a/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderTokenTest.java
+++
b/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderTokenTest.java
@@ -31,7 +31,7 @@ import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import com.google.common.collect.Lists;
import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwt;
+import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@@ -92,10 +92,10 @@ public class AuthenticationProviderTokenTest {
.compact();
@SuppressWarnings("unchecked")
- Jwt<?, Claims> jwt = Jwts.parserBuilder()
+ Jws<Claims> jwt = Jwts.parser()
.setSigningKey(AuthTokenUtils.decodeSecretKey(secretKey.getEncoded()))
.build()
- .parse(token);
+ .parseSignedClaims(token);
assertNotNull(jwt);
assertNotNull(jwt.getBody());
@@ -115,10 +115,10 @@ public class AuthenticationProviderTokenTest {
Optional.empty());
@SuppressWarnings("unchecked")
- Jwt<?, Claims> jwt = Jwts.parserBuilder().setSigningKey(
-
AuthTokenUtils.decodePublicKey(Decoders.BASE64.decode(publicKey),
SignatureAlgorithm.RS256))
+ Jws<Claims> jwt = Jwts.parser().setSigningKey(
+
AuthTokenUtils.decodePublicKey(Decoders.BASE64.decode(publicKey),
SignatureAlgorithm.RS256))
.build()
- .parse(token);
+ .parseSignedClaims(token);
assertNotNull(jwt);
assertNotNull(jwt.getBody());
diff --git
a/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProviderTest.java
b/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProviderTest.java
index e6818dca4c0..fd3e24c676b 100644
---
a/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProviderTest.java
+++
b/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProviderTest.java
@@ -43,7 +43,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
SecretKey secretKey =
AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);
String userA = "user-a";
String userB = "user-b";
- String token = Jwts.builder().claim("sub", new String[]{userA,
userB}).signWith(secretKey).compact();
+ String token = Jwts.builder().claim("roles", new String[]{userA,
userB}).signWith(secretKey).compact();
MultiRolesTokenAuthorizationProvider provider = new
MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
@@ -84,7 +84,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
@Test
public void testMultiRolesAuthzWithEmptyRoles() throws Exception {
SecretKey secretKey =
AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);
- String token = Jwts.builder().claim("sub", new
String[]{}).signWith(secretKey).compact();
+ String token = Jwts.builder().claim("roles", new
String[]{}).signWith(secretKey).compact();
MultiRolesTokenAuthorizationProvider provider = new
MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
@@ -113,7 +113,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
public void testMultiRolesAuthzWithSingleRole() throws Exception {
SecretKey secretKey =
AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);
String testRole = "test-role";
- String token = Jwts.builder().claim("sub",
testRole).signWith(secretKey).compact();
+ String token = Jwts.builder().claim("roles",
testRole).signWith(secretKey).compact();
MultiRolesTokenAuthorizationProvider provider = new
MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
@@ -147,7 +147,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
public void testMultiRolesAuthzWithoutClaim() throws Exception {
final SecretKey secretKey =
AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);
final String testRole = "test-role";
- // broker will use "sub" as the claim by default.
+ // broker will use "roles" as the claim by default.
final String token = Jwts.builder()
.claim("whatever", testRole).signWith(secretKey).compact();
ServiceConfiguration conf = new ServiceConfiguration();
@@ -268,7 +268,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
public void testMultiRolesAuthzWithSuperUser() throws Exception {
SecretKey secretKey =
AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);
String testAdminRole = "admin";
- String token = Jwts.builder().claim("sub",
testAdminRole).signWith(secretKey).compact();
+ String token = Jwts.builder().claim("roles",
testAdminRole).signWith(secretKey).compact();
ServiceConfiguration conf = new ServiceConfiguration();
conf.setSuperUserRoles(Set.of(testAdminRole));
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
b/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
index 6f718601646..b2cf1f2006f 100644
---
a/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
+++
b/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
@@ -20,7 +20,7 @@ package org.apache.pulsar.utils.auth.tokens;
import com.google.common.annotations.VisibleForTesting;
import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwt;
+import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
@@ -291,7 +291,7 @@ public class TokensCliUtils {
}
// Validate the token
- Jwt<?, Claims> jwt = Jwts.parserBuilder()
+ Jws<Claims> jwt = Jwts.parser()
.setSigningKey(validationKey)
.build()
.parseClaimsJws(token);
diff --git
a/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
b/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
index 005b160887e..aae379dae14 100644
---
a/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
+++
b/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
@@ -21,8 +21,8 @@ package org.apache.pulsar.utils.auth.tokens;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
-import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import java.io.ByteArrayOutputStream;
@@ -73,12 +73,12 @@ public class TokensCliUtilsTest {
};
new TokensCliUtils().execute(command);
- String token = baoStream.toString();
+ String token = baoStream.toString().trim();
- Jwt<?, ?> jwt = Jwts.parserBuilder()
+ Jws<Claims> jwt = Jwts.parser()
.setSigningKey(Decoders.BASE64.decode(secretKey))
.build()
- .parseClaimsJws(token);
+ .parseSignedClaims(token);
JwsHeader header = (JwsHeader) jwt.getHeader();
String keyId = header.getKeyId();
@@ -108,13 +108,13 @@ public class TokensCliUtilsTest {
};
new TokensCliUtils().execute(command);
- String token = baoStream.toString();
+ String token = baoStream.toString().trim();
Instant start = (new Date().toInstant().plus(expireAsSec - 5,
ChronoUnit.SECONDS));
Instant stop = (new Date().toInstant().plus(expireAsSec + 5,
ChronoUnit.SECONDS));
//Act
- Claims jwt = Jwts.parserBuilder()
+ Claims jwt = Jwts.parser()
.setSigningKey(Decoders.BASE64.decode("u+FxaxYWpsTfxeEmMh8fQeS3g2jfXw4+sGIv+PTY+BY="))
.build()
.parseClaimsJws(token)