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

jackietien pushed a commit to branch ty/object_type
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit e53f7e23e8e9d0db55f9ec921e7e205fc1458747
Author: shuwenwei <[email protected]>
AuthorDate: Tue Dec 2 13:59:39 2025 +0800

    Fix the check of grant option for tree model (#16845)
    
    (cherry picked from commit 8cd141895b11ee0bb91df646a0c88b3f4df9afc6)
---
 .../org/apache/iotdb/db/it/auth/IoTDBAuthIT.java   | 14 ++++
 .../security/TreeAccessCheckVisitor.java           | 15 +++-
 .../org/apache/iotdb/db/auth/TreeAccessTest.java   | 84 ++++++++++++++++++++++
 3 files changed, 111 insertions(+), 2 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java 
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
index 24204320f75..441dd1fdb5c 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
@@ -981,6 +981,8 @@ public class IoTDBAuthIT {
     adminStmt.execute("CREATE USER user1 'password123456'");
     adminStmt.execute("CREATE USER user2 'password123456'");
     adminStmt.execute("CREATE USER user3 'password123456'");
+    adminStmt.execute("CREATE USER user4 'password123456'");
+    adminStmt.execute("CREATE USER user5 'password123456'");
     adminStmt.execute("CREATE ROLE testRole");
     adminStmt.execute("GRANT system ON root.** TO ROLE testRole WITH GRANT 
OPTION");
     adminStmt.execute("GRANT READ_DATA ON root.t1.** TO ROLE testRole");
@@ -1095,6 +1097,18 @@ public class IoTDBAuthIT {
       }
     }
 
+    try (Connection userCon = EnvFactory.getEnv().getConnection("user4", 
"password123456");
+        Statement userStmt = userCon.createStatement()) {
+      adminStmt.execute("GRANT SYSTEM ON root.** TO USER user4");
+      try {
+        Assert.assertThrows(
+            SQLException.class, () -> userStmt.execute("GRANT SYSTEM ON 
root.** TO USER user5"));
+        adminStmt.execute("GRANT SYSTEM ON root.** TO USER user5");
+      } finally {
+        userStmt.close();
+      }
+    }
+
     adminStmt.close();
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
index 89daafccfbb..86f4dce2b84 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
@@ -643,7 +643,7 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
         for (String s : statement.getPrivilegeList()) {
           PrivilegeType privilegeType = PrivilegeType.valueOf(s.toUpperCase());
           if (privilegeType.isSystemPrivilege()) {
-            if (!checkHasGlobalAuth(context, privilegeType, auditObject)) {
+            if (!checkHasGlobalAuth(context, privilegeType, auditObject, 
true)) {
               return AuthorityChecker.getTSStatus(
                   false,
                   "Has no permission to execute "
@@ -1932,13 +1932,24 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
 
   protected boolean checkHasGlobalAuth(
       IAuditEntity context, PrivilegeType requiredPrivilege, Supplier<String> 
auditObject) {
+    return checkHasGlobalAuth(context, requiredPrivilege, auditObject, false);
+  }
+
+  protected boolean checkHasGlobalAuth(
+      IAuditEntity context,
+      PrivilegeType requiredPrivilege,
+      Supplier<String> auditObject,
+      boolean checkGrantOption) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       recordObjectAuthenticationAuditLog(
           context.setPrivilegeType(requiredPrivilege).setResult(true), 
auditObject);
       return true;
     }
     boolean result =
-        AuthorityChecker.checkSystemPermission(context.getUsername(), 
requiredPrivilege);
+        checkGrantOption
+            ? AuthorityChecker.checkSystemPermissionGrantOption(
+                context.getUsername(), requiredPrivilege)
+            : AuthorityChecker.checkSystemPermission(context.getUsername(), 
requiredPrivilege);
     recordObjectAuthenticationAuditLog(
         context.setPrivilegeType(requiredPrivilege).setResult(result), 
auditObject);
     return result;
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
new file mode 100644
index 00000000000..af8746fae3e
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.auth;
+
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.auth.entity.User;
+import 
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckContext;
+import 
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckVisitor;
+import org.apache.iotdb.db.queryengine.plan.statement.AuthorType;
+import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TreeAccessTest {
+
+  @Before
+  public void setup() {
+    AuthorityChecker.getAuthorityFetcher().getAuthorCache().invalidAllCache();
+  }
+
+  @After
+  public void teardown() {
+    AuthorityChecker.getAuthorityFetcher().getAuthorCache().invalidAllCache();
+  }
+
+  @Test
+  public void test1() {
+    User mockUser = Mockito.mock(User.class);
+    Mockito.when(mockUser.getName()).thenReturn("user1");
+    Mockito.when(mockUser.getUserId()).thenReturn(10000L);
+    
Mockito.when(mockUser.checkSysPriGrantOpt(PrivilegeType.SYSTEM)).thenReturn(false);
+    AuthorityChecker.getAuthorityFetcher()
+        .getAuthorCache()
+        .putUserCache(mockUser.getName(), mockUser);
+    User mockUser2 = Mockito.mock(User.class);
+    Mockito.when(mockUser2.getName()).thenReturn("user2");
+    Mockito.when(mockUser2.getUserId()).thenReturn(10001L);
+    AuthorityChecker.getAuthorityFetcher()
+        .getAuthorCache()
+        .putUserCache(mockUser.getName(), mockUser);
+    AuthorityChecker.getAuthorityFetcher()
+        .getAuthorCache()
+        .putUserCache(mockUser2.getName(), mockUser2);
+    TreeAccessCheckVisitor treeAccessCheckVisitor = new 
TreeAccessCheckVisitor();
+
+    AuthorStatement authorStatement = new 
AuthorStatement(AuthorType.GRANT_USER);
+    authorStatement.setPrivilegeList(new String[] {"SYSTEM"});
+    authorStatement.setUserName("user2");
+    authorStatement.setGrantOpt(true);
+    Assert.assertEquals(
+        TSStatusCode.NO_PERMISSION.getStatusCode(),
+        treeAccessCheckVisitor
+            .visitAuthor(authorStatement, new TreeAccessCheckContext(10000L, 
"user1", ""))
+            .getCode());
+    
Mockito.when(mockUser.checkSysPriGrantOpt(PrivilegeType.SYSTEM)).thenReturn(true);
+    Assert.assertEquals(
+        TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+        treeAccessCheckVisitor
+            .visitAuthor(authorStatement, new TreeAccessCheckContext(10000L, 
"user1", ""))
+            .getCode());
+  }
+}

Reply via email to