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

mmerli pushed a commit to branch branch-2.11
in repository https://gitbox.apache.org/repos/asf/pulsar.git


The following commit(s) were added to refs/heads/branch-2.11 by this push:
     new 07e905687bc [fix][sec] Fix MultiRoles token provider when using 
anonymous clients (#21338)
07e905687bc is described below

commit 07e905687bcdf086ec37a5bc18998df0afd9b88a
Author: Matteo Merli <mme...@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 <lhot...@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 d29497b5a27..279e975214e 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 545b03487a4..ee6854703b6 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);
             }

Reply via email to