This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new a24826048 fix(acl): clear a Tencent role's permissions instead of
deleting the role (#4469)
a24826048 is described below
commit a248260484d714f4ed4d75c42f6f7bd4524ead10
Author: 0 <[email protected]>
AuthorDate: Mon Sep 21 11:57:10 2026 +0800
fix(acl): clear a Tencent role's permissions instead of deleting the role
(#4469)
On Tencent a role also owns the credentials, so DeleteRole removed the ACL
user
along with the rule. Revoke by clearing PermRead/PermWrite through
ModifyRole
instead, and hide permission-less roles from the rule list while keeping
them
visible as users so operators can re-enable them.
---
.../studio/provider/tencent/TencentAclService.java | 17 +++++++++--
.../provider/tencent/TencentAclServiceTest.java | 33 ++++++++++++++++++++++
2 files changed, 48 insertions(+), 2 deletions(-)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentAclService.java
b/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentAclService.java
index b656056e6..a7d5434fb 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentAclService.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentAclService.java
@@ -102,6 +102,12 @@ public class TencentAclService {
if (role == null || !StringUtils.hasText(role.getRoleName())) {
continue;
}
+ // A role with both permissions disabled has no effective ACL
rule; it is still
+ // listed as a user so operators can re-enable permissions.
+ if (!Boolean.TRUE.equals(role.getPermRead())
+ && !Boolean.TRUE.equals(role.getPermWrite())) {
+ continue;
+ }
if (requestedPrincipal != null
&& !requestedPrincipal.equals(role.getRoleName())) {
continue;
@@ -239,14 +245,21 @@ public class TencentAclService {
return createRule(instanceId, rule);
}
+ /**
+ * Revokes the cluster-wide rule for a Tencent role by clearing
PermRead/PermWrite.
+ * The role account itself must stay: on Tencent a role also owns the
credentials, so
+ * calling DeleteRole here would silently remove the ACL user.
+ */
public void deleteRule(String instanceId, String principal) {
Context context = resolve(instanceId);
String roleName = requireRoleName(principal, "ACL principal");
- DeleteRoleRequest request = new DeleteRoleRequest();
+ ModifyRoleRequest request = new ModifyRoleRequest();
request.setInstanceId(context.cloudInstanceId());
request.setRole(roleName);
+ request.setPermRead(false);
+ request.setPermWrite(false);
clientFactory.call(context.credentialId(), context.regionId(),
- client -> client.DeleteRole(request));
+ client -> client.ModifyRole(request));
}
private static String requireRulePrincipal(AclRuleVO rule) {
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentAclServiceTest.java
b/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentAclServiceTest.java
index 482277c9b..d83940c33 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentAclServiceTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentAclServiceTest.java
@@ -43,6 +43,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -275,6 +276,38 @@ class TencentAclServiceTest {
.satisfies(error -> assertThat(((BusinessException)
error).getCode()).isEqualTo(400));
}
+ @Test
+ void deleteRuleRevokesPermissionsWithoutDeletingTheRoleTest() throws
Exception {
+ service.deleteRule(INSTANCE_ID, " reader-role ");
+
+ ArgumentCaptor<ModifyRoleRequest> requestCaptor =
ArgumentCaptor.forClass(ModifyRoleRequest.class);
+ verify(client).ModifyRole(requestCaptor.capture());
+ ModifyRoleRequest request = requestCaptor.getValue();
+ assertThat(request.getRole()).isEqualTo("reader-role");
+ assertThat(request.getPermRead()).isFalse();
+ assertThat(request.getPermWrite()).isFalse();
+ verify(client, never()).DeleteRole(any());
+ }
+
+ @Test
+ void listRulesHidesPermissionlessRolesThatStillExistAsUsersTest() throws
Exception {
+ RoleItem active = role("active-role");
+ RoleItem revoked = new RoleItem();
+ revoked.setRoleName("revoked-role");
+ revoked.setPermRead(false);
+ revoked.setPermWrite(false);
+ DescribeRoleListResponse response = new DescribeRoleListResponse();
+ response.setData(new RoleItem[]{active, revoked});
+ when(client.DescribeRoleList(any())).thenReturn(response);
+
+ assertThat(service.listRules(INSTANCE_ID, null))
+ .extracting(AclRuleVO::getPrincipal)
+ .containsExactly("active-role");
+ assertThat(service.listUsers(INSTANCE_ID))
+ .extracting(AclUserVO::getUsername)
+ .containsExactly("active-role", "revoked-role");
+ }
+
private static RoleItem[] rolePage(Long offset, Long limit, int total) {
int start = offset == null ? 0 : offset.intValue();
int size = Math.min(limit == null ? TencentAclService.PAGE_SIZE :
limit.intValue(),