This is an automated email from the ASF dual-hosted git repository. penghui pushed a commit to branch branch-2.8 in repository https://gitbox.apache.org/repos/asf/pulsar.git
commit dfacc1299312aaeb7c966667b379bbc27fcd94d0 Author: Zike Yang <[email protected]> AuthorDate: Sun May 8 23:08:45 2022 +0800 Support handling single role and non-jwt-token in MultiRolesTokenAuthorizationProvider (#14857) ### Motivation Currently, `MultiRolesTokenAuthorizationProvider` doesn't support handling the single string type role. It will return the empty role in that case. This PR adds support for handling the string-type role. This PR also adds support for handling the non-jwt-token. ### Modifications * Add support for handling the string-type role * Add support for handling the non-jwt-token ### Verifying this change This change is already covered by existing tests, such as *testMultiRolesAuthzWithSingleRole*. (cherry picked from commit 8bf6785c0803d314465b2d9156df6ca5bbb3c644) --- .../MultiRolesTokenAuthorizationProvider.java | 8 +- .../MultiRolesTokenAuthorizationProviderTest.java | 101 +++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) 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 f47f44ecf8c..9e4b71cdc6f 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 @@ -58,7 +58,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro // The token's claim that corresponds to the "role" string static final String CONF_TOKEN_AUTH_CLAIM = "tokenAuthClaim"; - private JwtParser parser; + private final JwtParser parser; private String roleClaim; public MultiRolesTokenAuthorizationProvider() { @@ -106,11 +106,15 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro return Collections.emptyList(); String[] splitToken = token.split("\\."); + if (splitToken.length < 2) { + log.warn("Unable to extract additional roles from JWT token"); + return Collections.emptyList(); + } String unsignedToken = splitToken[0] + "." + splitToken[1] + "."; Jwt<?, Claims> jwt = parser.parseClaimsJwt(unsignedToken); try { - Collections.singletonList(jwt.getBody().get(roleClaim, String.class)); + return Collections.singletonList(jwt.getBody().get(roleClaim, String.class)); } catch (RequiredTypeException requiredTypeException) { try { List list = jwt.getBody().get(roleClaim, List.class); 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 edd0baa42ae..078e2aad07a 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 @@ -18,10 +18,14 @@ */ package org.apache.pulsar.broker.authorization; +import static org.mockito.Mockito.mock; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import java.util.Properties; +import org.apache.pulsar.broker.ServiceConfiguration; import org.apache.pulsar.broker.authentication.AuthenticationDataSource; import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils; +import org.apache.pulsar.broker.resources.PulsarResources; import org.junit.Assert; import org.testng.annotations.Test; @@ -96,4 +100,101 @@ public class MultiRolesTokenAuthorizationProviderTest { Assert.assertFalse(provider.authorize(ads, role -> CompletableFuture.completedFuture(false)).get()); } + + @Test + 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(); + + MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider(); + + AuthenticationDataSource ads = new AuthenticationDataSource() { + @Override + public boolean hasDataFromHttp() { + return true; + } + + @Override + public String getHttpHeader(String name) { + if (name.equals("Authorization")) { + return "Bearer " + token; + } else { + throw new IllegalArgumentException("Wrong HTTP header"); + } + } + }; + + Assert.assertTrue(provider.authorize(ads, role -> { + if (role.equals(testRole)) { + return CompletableFuture.completedFuture(true); + } + return CompletableFuture.completedFuture(false); + }).get()); + } + + @Test + public void testMultiRolesNotFailNonJWT() throws Exception { + String token = "a-non-jwt-token"; + + MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider(); + + AuthenticationDataSource ads = new AuthenticationDataSource() { + @Override + public boolean hasDataFromHttp() { + return true; + } + + @Override + public String getHttpHeader(String name) { + if (name.equals("Authorization")) { + return "Bearer " + token; + } else { + throw new IllegalArgumentException("Wrong HTTP header"); + } + } + }; + + Assert.assertFalse(provider.authorize(ads, role -> CompletableFuture.completedFuture(false)).get()); + } + + @Test + public void testMultiRolesAuthzWithCustomRolesClaims() throws Exception { + SecretKey secretKey = AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256); + String testRole = "test-role"; + String customRolesClaims = "role"; + String token = Jwts.builder().claim(customRolesClaims, new String[]{testRole}).signWith(secretKey).compact(); + + Properties properties = new Properties(); + properties.setProperty("tokenSettingPrefix", "prefix_"); + properties.setProperty("prefix_tokenAuthClaim", customRolesClaims); + ServiceConfiguration conf = new ServiceConfiguration(); + conf.setProperties(properties); + + MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider(); + provider.initialize(conf, mock(PulsarResources.class)); + + AuthenticationDataSource ads = new AuthenticationDataSource() { + @Override + public boolean hasDataFromHttp() { + return true; + } + + @Override + public String getHttpHeader(String name) { + if (name.equals("Authorization")) { + return "Bearer " + token; + } else { + throw new IllegalArgumentException("Wrong HTTP header"); + } + } + }; + + Assert.assertTrue(provider.authorize(ads, role -> { + if (role.equals(testRole)) { + return CompletableFuture.completedFuture(true); + } + return CompletableFuture.completedFuture(false); + }).get()); + } }
