From ddf6312f4d37d9798a892bdd58dbea23f9bc8216 Mon Sep 17 00:00:00 2001 From: Ruguo Yu Date: Tue, 14 Dec 2021 12:25:48 +0800 Subject: [PATCH] [Broker] Remove tenant admin verification when listing partitioned topics (#13138) * [Broker] Remove tenant permission verification when list partitioned-topic * Improve test * Update annotation --- .../admin/impl/PersistentTopicsBase.java | 1 - .../broker/admin/v1/PersistentTopics.java | 4 ++-- .../broker/admin/v2/PersistentTopics.java | 4 ++-- .../AuthorizationProducerConsumerTest.java | 20 ++++++++++++++++++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java index ce586ebff18fa..123964810c37f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java @@ -171,7 +171,6 @@ protected List internalGetList() { } protected List internalGetPartitionedTopicList() { - validateAdminAccessForTenant(namespaceName.getTenant()); validateNamespaceOperation(namespaceName, NamespaceOperation.GET_TOPICS); // Validate that namespace exists, throws 404 if it doesn't exist try { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/PersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/PersistentTopics.java index 3d80f0aa99aba..c2187a31645c9 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/PersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/PersistentTopics.java @@ -69,7 +69,7 @@ public class PersistentTopics extends PersistentTopicsBase { @Path("/{property}/{cluster}/{namespace}") @ApiOperation(hidden = true, value = "Get the list of topics under a namespace.", response = String.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), + @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin or consume permission on namespace"), @ApiResponse(code = 404, message = "Namespace doesn't exist")}) public void getList(@Suspended final AsyncResponse asyncResponse, @PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace) { @@ -87,7 +87,7 @@ public void getList(@Suspended final AsyncResponse asyncResponse, @PathParam("pr @Path("/{property}/{cluster}/{namespace}/partitioned") @ApiOperation(hidden = true, value = "Get the list of partitioned topics under a namespace.", response = String.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), + @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin or consume permission on namespace"), @ApiResponse(code = 404, message = "Namespace doesn't exist")}) public List getPartitionedTopicList(@PathParam("property") String property, @PathParam("cluster") String cluster, @PathParam("namespace") String namespace) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java index 352b10fee03fe..ef221209d5279 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java @@ -85,7 +85,7 @@ public class PersistentTopics extends PersistentTopicsBase { response = String.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), + @ApiResponse(code = 403, message = "Don't have admin or consume permission on namespace"), @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), @ApiResponse(code = 412, message = "Namespace name is not valid"), @ApiResponse(code = 500, message = "Internal server error")}) @@ -111,7 +111,7 @@ public void getList( response = String.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), + @ApiResponse(code = 403, message = "Don't have admin or consume permission on namespace"), @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), @ApiResponse(code = 412, message = "Namespace name is not valid"), @ApiResponse(code = 500, message = "Internal server error")}) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/AuthorizationProducerConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/AuthorizationProducerConsumerTest.java index cb030656f1b4d..efb982769b803 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/AuthorizationProducerConsumerTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/AuthorizationProducerConsumerTest.java @@ -24,6 +24,7 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.io.IOException; @@ -365,6 +366,7 @@ public void testClearBacklogPermission() throws Exception { conf.setAuthorizationProvider(PulsarAuthorizationProvider.class.getName()); setup(); + final String tenantRole = "tenant-role"; final String subscriptionRole = "sub-role"; final String subscriptionName = "sub1"; final String namespace = "my-property/my-ns-sub-auth"; @@ -377,6 +379,11 @@ public void testClearBacklogPermission() throws Exception { PulsarAdmin superAdmin = spy(PulsarAdmin.builder().serviceHttpUrl(brokerUrl.toString()) .authentication(adminAuthentication).build()); + Authentication tenantAdminAuthentication = new ClientAuthentication(tenantRole); + @Cleanup + PulsarAdmin tenantAdmin = spy(PulsarAdmin.builder().serviceHttpUrl(brokerUrl.toString()) + .authentication(tenantAdminAuthentication).build()); + Authentication subAdminAuthentication = new ClientAuthentication(subscriptionRole); @Cleanup PulsarAdmin sub1Admin = spy(PulsarAdmin.builder().serviceHttpUrl(brokerUrl.toString()) @@ -385,9 +392,11 @@ public void testClearBacklogPermission() throws Exception { superAdmin.clusters().createCluster("test", ClusterData.builder().serviceUrl(brokerUrl.toString()).build()); superAdmin.tenants().createTenant("my-property", - new TenantInfoImpl(Sets.newHashSet(), Sets.newHashSet("test"))); + new TenantInfoImpl(Sets.newHashSet(tenantRole), Sets.newHashSet("test"))); superAdmin.namespaces().createNamespace(namespace, Sets.newHashSet("test")); superAdmin.topics().createPartitionedTopic(topicName, 1); + assertEquals(tenantAdmin.topics().getPartitionedTopicList(namespace), + Lists.newArrayList(topicName)); // grant topic consume&produce authorization to the subscriptionRole superAdmin.topics().grantPermission(topicName, subscriptionRole, @@ -416,6 +425,13 @@ public void testClearBacklogPermission() throws Exception { .get(subscriptionName).getMsgBacklog(), 10); // subscriptionRole doesn't have namespace-level authorization, so it will fail to clear backlog + try { + sub1Admin.topics().getPartitionedTopicList(namespace); + fail("should have failed with authorization exception"); + } catch (Exception e) { + assertTrue(e.getMessage().startsWith( + "Unauthorized to validateNamespaceOperation for operation [GET_TOPICS]")); + } try { sub1Admin.namespaces().clearNamespaceBundleBacklog(namespace, "0x00000000_0xffffffff"); fail("should have failed with authorization exception"); @@ -427,6 +443,8 @@ public void testClearBacklogPermission() throws Exception { superAdmin.namespaces().grantPermissionOnNamespace(namespace, subscriptionRole, Sets.newHashSet(AuthAction.consume)); // now, subscriptionRole have consume authorization on namespace, so it will successfully clear backlog + assertEquals(sub1Admin.topics().getPartitionedTopicList(namespace), + Lists.newArrayList(topicName)); sub1Admin.namespaces().clearNamespaceBundleBacklog(namespace, "0x00000000_0xffffffff"); assertEquals(sub1Admin.topics().getStats(topicName + "-partition-0").getSubscriptions() .get(subscriptionName).getMsgBacklog(), 0);