This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 8cd141895b1 Fix the check of grant option for tree model (#16845)
8cd141895b1 is described below
commit 8cd141895b11ee0bb91df646a0c88b3f4df9afc6
Author: shuwenwei <[email protected]>
AuthorDate: Tue Dec 2 13:59:39 2025 +0800
Fix the check of grant option for tree model (#16845)
---
.../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());
+ }
+}