You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by ti...@apache.org on 2023/10/10 15:45:17 UTC

[pulsar] branch master updated: [fix][sec] Fix MultiRoles token provider when using anonymous clients (#21338)

This is an automated email from the ASF dual-hosted git repository.

tison 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 84204207c19 [fix][sec] Fix MultiRoles token provider when using anonymous clients (#21338)
84204207c19 is described below

commit 84204207c19cad0bf9986088af2bbd954b85288b
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue Oct 10 23:45:10 2023 +0800

    [fix][sec] Fix MultiRoles token provider when using anonymous clients (#21338)
    
    Co-authored-by: Lari Hotari <lh...@apache.org>
---
 .../MultiRolesTokenAuthorizationProvider.java      | 45 +++++++++++++---------
 .../MultiRolesTokenAuthorizationProviderTest.java  | 31 +++++++++++----
 2 files changed, 50 insertions(+), 26 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 db5f4f18e8c..6376b60217f 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
@@ -97,7 +97,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
         if (role != null && superUserRoles.contains(role)) {
             return CompletableFuture.completedFuture(true);
         }
-        Set<String> roles = getRoles(authenticationData);
+        Set<String> roles = getRoles(role, authenticationData);
         if (roles.isEmpty()) {
             return CompletableFuture.completedFuture(false);
         }
@@ -112,7 +112,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                     if (isSuperUser) {
                         return CompletableFuture.completedFuture(true);
                     }
-                    Set<String> roles = getRoles(authData);
+                    Set<String> roles = getRoles(role, authData);
                     if (roles.isEmpty()) {
                         return CompletableFuture.completedFuture(false);
                     }
@@ -143,7 +143,11 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                 });
     }
 
-    private Set<String> getRoles(AuthenticationDataSource authData) {
+    private Set<String> getRoles(String role, AuthenticationDataSource authData) {
+        if (authData == null) {
+            return Collections.singleton(role);
+        }
+
         String token = null;
 
         if (authData.hasDataFromCommand()) {
@@ -192,9 +196,9 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
         return Collections.emptySet();
     }
 
-    public CompletableFuture<Boolean> authorize(AuthenticationDataSource authenticationData, Function<String,
-            CompletableFuture<Boolean>> authorizeFunc) {
-        Set<String> roles = getRoles(authenticationData);
+    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);
         }
@@ -212,7 +216,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
     @Override
     public CompletableFuture<Boolean> canProduceAsync(TopicName topicName, String role,
                                                       AuthenticationDataSource authenticationData) {
-        return authorize(authenticationData, r -> super.canProduceAsync(topicName, r, authenticationData));
+        return authorize(role, authenticationData, r -> super.canProduceAsync(topicName, r, authenticationData));
     }
 
     /**
@@ -227,7 +231,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
     public CompletableFuture<Boolean> canConsumeAsync(TopicName topicName, String role,
                                                       AuthenticationDataSource authenticationData,
                                                       String subscription) {
-        return authorize(authenticationData, r -> super.canConsumeAsync(topicName, r, authenticationData,
+        return authorize(role, authenticationData, r -> super.canConsumeAsync(topicName, r, authenticationData,
                 subscription));
     }
 
@@ -244,25 +248,27 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
     @Override
     public CompletableFuture<Boolean> canLookupAsync(TopicName topicName, String role,
                                                      AuthenticationDataSource authenticationData) {
-        return authorize(authenticationData, r -> super.canLookupAsync(topicName, r, authenticationData));
+        return authorize(role, authenticationData, r -> super.canLookupAsync(topicName, r, authenticationData));
     }
 
     @Override
     public CompletableFuture<Boolean> allowFunctionOpsAsync(NamespaceName namespaceName, String role,
                                                             AuthenticationDataSource authenticationData) {
-        return authorize(authenticationData, r -> super.allowFunctionOpsAsync(namespaceName, r, authenticationData));
+        return authorize(role, authenticationData,
+                r -> super.allowFunctionOpsAsync(namespaceName, r, authenticationData));
     }
 
     @Override
     public CompletableFuture<Boolean> allowSourceOpsAsync(NamespaceName namespaceName, String role,
                                                           AuthenticationDataSource authenticationData) {
-        return authorize(authenticationData, r -> super.allowSourceOpsAsync(namespaceName, r, authenticationData));
+        return authorize(role, authenticationData,
+                r -> super.allowSourceOpsAsync(namespaceName, r, authenticationData));
     }
 
     @Override
     public CompletableFuture<Boolean> allowSinkOpsAsync(NamespaceName namespaceName, String role,
                                                         AuthenticationDataSource authenticationData) {
-        return authorize(authenticationData, r -> super.allowSinkOpsAsync(namespaceName, r, authenticationData));
+        return authorize(role, authenticationData, r -> super.allowSinkOpsAsync(namespaceName, r, authenticationData));
     }
 
     @Override
@@ -270,7 +276,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                                                                 String role,
                                                                 TenantOperation operation,
                                                                 AuthenticationDataSource authData) {
-        return authorize(authData, r -> super.allowTenantOperationAsync(tenantName, r, operation, authData));
+        return authorize(role, authData, r -> super.allowTenantOperationAsync(tenantName, r, operation, authData));
     }
 
     @Override
@@ -278,7 +284,8 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                                                                    String role,
                                                                    NamespaceOperation operation,
                                                                    AuthenticationDataSource authData) {
-        return authorize(authData, r -> super.allowNamespaceOperationAsync(namespaceName, r, operation, authData));
+        return authorize(role, authData,
+                r -> super.allowNamespaceOperationAsync(namespaceName, r, operation, authData));
     }
 
     @Override
@@ -287,8 +294,8 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                                                                          PolicyOperation operation,
                                                                          String role,
                                                                          AuthenticationDataSource authData) {
-        return authorize(authData, r -> super.allowNamespacePolicyOperationAsync(namespaceName, policy, operation, r,
-                authData));
+        return authorize(role, authData,
+                r -> super.allowNamespacePolicyOperationAsync(namespaceName, policy, operation, r, authData));
     }
 
     @Override
@@ -296,7 +303,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                                                                String role,
                                                                TopicOperation operation,
                                                                AuthenticationDataSource authData) {
-        return authorize(authData, r -> super.allowTopicOperationAsync(topicName, r, operation, authData));
+        return authorize(role, authData, r -> super.allowTopicOperationAsync(topicName, r, operation, authData));
     }
 
     @Override
@@ -305,7 +312,7 @@ public class MultiRolesTokenAuthorizationProvider extends PulsarAuthorizationPro
                                                                      PolicyName policyName,
                                                                      PolicyOperation policyOperation,
                                                                      AuthenticationDataSource authData) {
-        return authorize(authData, r -> super.allowTopicPolicyOperationAsync(topicName, r, policyName, policyOperation,
-                authData));
+        return authorize(role, authData,
+                r -> super.allowTopicPolicyOperationAsync(topicName, r, policyName, policyOperation, authData));
     }
 }
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 f0a857bdd69..4b67f52075c 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
@@ -24,6 +24,8 @@ import static org.testng.Assert.assertTrue;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureAlgorithm;
 import java.util.Properties;
+import java.util.function.Function;
+import lombok.Cleanup;
 import org.apache.pulsar.broker.ServiceConfiguration;
 import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
 import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils;
@@ -61,18 +63,18 @@ public class MultiRolesTokenAuthorizationProviderTest {
             }
         };
 
-        assertTrue(provider.authorize(ads, role -> {
+        assertTrue(provider.authorize("test", ads, role -> {
             if (role.equals(userB)) {
                 return CompletableFuture.completedFuture(true); // only userB has permission
             }
             return CompletableFuture.completedFuture(false);
         }).get());
 
-        assertTrue(provider.authorize(ads, role -> {
+        assertTrue(provider.authorize("test", ads, role -> {
             return CompletableFuture.completedFuture(true); // all users has permission
         }).get());
 
-        assertFalse(provider.authorize(ads, role -> {
+        assertFalse(provider.authorize("test", ads, role -> {
             return CompletableFuture.completedFuture(false); // all users has no permission
         }).get());
     }
@@ -100,7 +102,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
             }
         };
 
-        assertFalse(provider.authorize(ads, role -> CompletableFuture.completedFuture(false)).get());
+        assertFalse(provider.authorize("test", ads, role -> CompletableFuture.completedFuture(false)).get());
     }
 
     @Test
@@ -127,7 +129,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
             }
         };
 
-        assertTrue(provider.authorize(ads, role -> {
+        assertTrue(provider.authorize("test", ads, role -> {
             if (role.equals(testRole)) {
                 return CompletableFuture.completedFuture(true);
             }
@@ -135,6 +137,21 @@ public class MultiRolesTokenAuthorizationProviderTest {
         }).get());
     }
 
+    @Test
+    public void testMultiRolesAuthzWithAnonymousUser() throws Exception {
+        @Cleanup
+        MultiRolesTokenAuthorizationProvider provider = new MultiRolesTokenAuthorizationProvider();
+
+        Function<String, CompletableFuture<Boolean>> authorizeFunc = (String role) -> {
+            if (role.equals("test-role")) {
+                return CompletableFuture.completedFuture(true);
+            }
+            return CompletableFuture.completedFuture(false);
+        };
+        assertTrue(provider.authorize("test-role", null, authorizeFunc).get());
+        assertFalse(provider.authorize("test-role-x", null, authorizeFunc).get());
+    }
+
     @Test
     public void testMultiRolesNotFailNonJWT() throws Exception {
         String token = "a-non-jwt-token";
@@ -157,7 +174,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
             }
         };
 
-        assertFalse(provider.authorize(ads, role -> CompletableFuture.completedFuture(false)).get());
+        assertFalse(provider.authorize("test", ads, role -> CompletableFuture.completedFuture(false)).get());
     }
 
     @Test
@@ -192,7 +209,7 @@ public class MultiRolesTokenAuthorizationProviderTest {
             }
         };
 
-        assertTrue(provider.authorize(ads, role -> {
+        assertTrue(provider.authorize("test", ads, role -> {
             if (role.equals(testRole)) {
                 return CompletableFuture.completedFuture(true);
             }