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

RongtongJin pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/rocketmq.git


The following commit(s) were added to refs/heads/develop by this push:
     new 37808b38c1 fix(auth): tolerate blank subscription topics in heartbeats 
(#11082)
37808b38c1 is described below

commit 37808b38c1405c9bb433df04f0b88ea063dfd6e1
Author: dingshuangxi888 <[email protected]>
AuthorDate: Wed Sep 9 10:26:04 2026 +0800

    fix(auth): tolerate blank subscription topics in heartbeats (#11082)
    
    * fix(auth): tolerate empty topics in consumer heartbeats
    
    * fix(auth): skip blank heartbeat subscription topics
    
    ---------
    
    Co-authored-by: shuangxi.dsx <[email protected]>
---
 .../DefaultAuthorizationContextBuilder.java        |  3 ++
 .../DefaultAuthorizationContextBuilderTest.java    | 51 ++++++++++++++++++++--
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git 
a/auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java
 
b/auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java
index 54625ca527..00920de9a7 100644
--- 
a/auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java
+++ 
b/auth/src/main/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilder.java
@@ -350,6 +350,9 @@ public class DefaultAuthorizationContextBuilder implements 
AuthorizationContextB
                             if (subscriptionData == null) {
                                 throw new AuthorizationException("subscription 
is null.");
                             }
+                            if 
(StringUtils.isBlank(subscriptionData.getTopic())) {
+                                continue;
+                            }
                             String subscriptionTopic =
                                 requireResource(subscriptionData.getTopic(), 
"topic");
                             if (NamespaceUtil.isRetryTopic(subscriptionTopic)) 
{
diff --git 
a/auth/src/test/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilderTest.java
 
b/auth/src/test/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilderTest.java
index 8be1f126d9..f1591c86ea 100644
--- 
a/auth/src/test/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilderTest.java
+++ 
b/auth/src/test/java/org/apache/rocketmq/auth/authorization/builder/DefaultAuthorizationContextBuilderTest.java
@@ -1097,9 +1097,7 @@ public class DefaultAuthorizationContextBuilderTest {
         HeartbeatData heartbeatData = new HeartbeatData();
         ConsumerData consumerData = new ConsumerData();
         consumerData.setGroupName("group");
-        SubscriptionData subscriptionData = new SubscriptionData();
-        subscriptionData.setTopic(" ");
-        
consumerData.setSubscriptionDataSet(Collections.singleton(subscriptionData));
+        consumerData.setSubscriptionDataSet(Collections.singleton(null));
         heartbeatData.setConsumerDataSet(Collections.singleton(consumerData));
         Assert.assertThrows(AuthorizationException.class, () -> 
builder.build(channelHandlerContext,
             remotingRequest(RequestCode.HEART_BEAT, new 
HeartbeatRequestHeader(),
@@ -1446,6 +1444,53 @@ public class DefaultAuthorizationContextBuilderTest {
             remotingRequest(RequestCode.DELETE_SUBSCRIPTION_GROUP_LIST, null, 
invalidGroupList.encode())));
     }
 
+    @Test
+    public void buildHeartbeatSkipsBlankTopics() {
+        mockRemotingChannel();
+        ConsumerData consumerData = new ConsumerData();
+        consumerData.setGroupName("group");
+        consumerData.setSubscriptionDataSet(new LinkedHashSet<>(Arrays.asList(
+            new SubscriptionData(null, "*"),
+            new SubscriptionData("", "*"),
+            new SubscriptionData(" ", "*"),
+            new SubscriptionData("\t\r\n", "*"),
+            new SubscriptionData("topic", "*"),
+            new SubscriptionData("%RETRY%group", "*"))));
+        HeartbeatData heartbeatData = new HeartbeatData();
+        heartbeatData.setConsumerDataSet(Collections.singleton(consumerData));
+
+        List<DefaultAuthorizationContext> result = 
builder.build(channelHandlerContext,
+            remotingRequest(RequestCode.HEART_BEAT, new 
HeartbeatRequestHeader(), heartbeatData.encode()));
+
+        assertResourceOrder(result, "Group:group", "Topic:topic");
+        assertActions(result, "Group:group", Action.SUB);
+        assertActions(result, "Topic:topic", Action.SUB);
+    }
+
+    @Test
+    public void buildHeartbeatWithOnlyBlankTopicsStillChecksGroup() {
+        mockRemotingChannel();
+        ConsumerData consumerData = new ConsumerData();
+        consumerData.setGroupName("group");
+        consumerData.setSubscriptionDataSet(new LinkedHashSet<>(Arrays.asList(
+            new SubscriptionData(null, "*"),
+            new SubscriptionData("", "*"),
+            new SubscriptionData(" ", "*"),
+            new SubscriptionData("\t\r\n", "*"))));
+        HeartbeatData heartbeatData = new HeartbeatData();
+        heartbeatData.setConsumerDataSet(Collections.singleton(consumerData));
+
+        List<DefaultAuthorizationContext> result = 
builder.build(channelHandlerContext,
+            remotingRequest(RequestCode.HEART_BEAT, new 
HeartbeatRequestHeader(), heartbeatData.encode()));
+
+        assertResourceOrder(result, "Group:group");
+        assertActions(result, "Group:group", Action.SUB);
+
+        consumerData.setGroupName("");
+        Assert.assertThrows(AuthorizationException.class, () -> 
builder.build(channelHandlerContext,
+            remotingRequest(RequestCode.HEART_BEAT, new 
HeartbeatRequestHeader(), heartbeatData.encode())));
+    }
+
     @Test
     public void buildGrpcHeartbeatByClientShape() {
         Metadata metadata = new Metadata();

Reply via email to