Skip to content

Commit

Permalink
[fix][broker] Fix MultiRoles token provider NPE when using anonymous …
Browse files Browse the repository at this point in the history
…clients (apache#21429)
  • Loading branch information
Technoboy- authored and nikhil-ctds committed Dec 20, 2023
1 parent 6c9995c commit 83715e3
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@ public boolean hasSubscription() {
public String getSubscription() {
return subscription;
}

public AuthenticationDataSource getAuthData() {
return authData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
import org.apache.pulsar.broker.authentication.AuthenticationDataSubscription;
import org.apache.pulsar.broker.resources.PulsarResources;
import org.apache.pulsar.common.naming.NamespaceName;
import org.apache.pulsar.common.naming.TopicName;
Expand Down Expand Up @@ -144,7 +145,8 @@ public CompletableFuture<Boolean> validateTenantAdminAccess(String tenantName, S
}

private Set<String> getRoles(String role, AuthenticationDataSource authData) {
if (authData == null) {
if (authData == null || (authData instanceof AuthenticationDataSubscription
&& ((AuthenticationDataSubscription) authData).getAuthData() == null)) {
return Collections.singleton(role);
}

Expand Down Expand Up @@ -198,13 +200,19 @@ private Set<String> getRoles(String role, AuthenticationDataSource authData) {

public CompletableFuture<Boolean> authorize(String role, AuthenticationDataSource authenticationData,
Function<String, CompletableFuture<Boolean>> authorizeFunc) {
Set<String> roles = getRoles(role, authenticationData);
if (roles.isEmpty()) {
return CompletableFuture.completedFuture(false);
}
List<CompletableFuture<Boolean>> futures = new ArrayList<>(roles.size());
roles.forEach(r -> futures.add(authorizeFunc.apply(r)));
return FutureUtil.waitForAny(futures, ret -> (boolean) ret).thenApply(v -> v.isPresent());
return isSuperUser(role, authenticationData, conf)
.thenCompose(superUser -> {
if (superUser) {
return CompletableFuture.completedFuture(true);
}
Set<String> roles = getRoles(role, authenticationData);
if (roles.isEmpty()) {
return CompletableFuture.completedFuture(false);
}
List<CompletableFuture<Boolean>> futures = new ArrayList<>(roles.size());
roles.forEach(r -> futures.add(authorizeFunc.apply(r)));
return FutureUtil.waitForAny(futures, ret -> (boolean) ret).thenApply(v -> v.isPresent());
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import lombok.Cleanup;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
import org.apache.pulsar.broker.authentication.AuthenticationDataSubscription;
import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils;
import org.apache.pulsar.broker.resources.PulsarResources;
import org.testng.annotations.Test;
Expand All @@ -46,6 +47,8 @@ public void testMultiRolesAuthz() throws Exception {
String token = Jwts.builder().claim("sub", new String[]{userA, userB}).signWith(secretKey).compact();

MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
provider.initialize(conf, mock(PulsarResources.class));

AuthenticationDataSource ads = new AuthenticationDataSource() {
@Override
Expand Down Expand Up @@ -85,6 +88,8 @@ public void testMultiRolesAuthzWithEmptyRoles() throws Exception {
String token = Jwts.builder().claim("sub", new String[]{}).signWith(secretKey).compact();

MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
provider.initialize(conf, mock(PulsarResources.class));

AuthenticationDataSource ads = new AuthenticationDataSource() {
@Override
Expand Down Expand Up @@ -112,6 +117,8 @@ public void testMultiRolesAuthzWithSingleRole() throws Exception {
String token = Jwts.builder().claim("sub", testRole).signWith(secretKey).compact();

MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
provider.initialize(conf, mock(PulsarResources.class));

AuthenticationDataSource ads = new AuthenticationDataSource() {
@Override
Expand Down Expand Up @@ -141,6 +148,9 @@ public String getHttpHeader(String name) {
public void testMultiRolesAuthzWithAnonymousUser() throws Exception {
@Cleanup
MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();

provider.initialize(conf, mock(PulsarResources.class));

Function<String, CompletableFuture<Boolean>> authorizeFunc = (String role) -> {
if (role.equals("test-role")) {
Expand All @@ -150,13 +160,16 @@ public void testMultiRolesAuthzWithAnonymousUser() throws Exception {
};
assertTrue(provider.authorize("test-role", null, authorizeFunc).get());
assertFalse(provider.authorize("test-role-x", null, authorizeFunc).get());
assertTrue(provider.authorize("test-role", new AuthenticationDataSubscription(null, "test-sub"), authorizeFunc).get());
}

@Test
public void testMultiRolesNotFailNonJWT() throws Exception {
String token = "a-non-jwt-token";

MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider();
ServiceConfiguration conf = new ServiceConfiguration();
provider.initialize(conf, mock(PulsarResources.class));

AuthenticationDataSource ads = new AuthenticationDataSource() {
@Override
Expand Down Expand Up @@ -246,5 +259,14 @@ public String getHttpHeader(String name) {
};

assertTrue(provider.isSuperUser(testAdminRole, ads, conf).get());
Function<String, CompletableFuture<Boolean>> authorizeFunc = (String role) -> {
if (role.equals("admin1")) {
return CompletableFuture.completedFuture(true);
}
return CompletableFuture.completedFuture(false);
};
assertTrue(provider.authorize(testAdminRole, ads, (String role) -> CompletableFuture.completedFuture(false)).get());
assertTrue(provider.authorize("admin1", null, authorizeFunc).get());
assertFalse(provider.authorize("admin2", null, authorizeFunc).get());
}
}

0 comments on commit 83715e3

Please sign in to comment.