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

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


The following commit(s) were added to refs/heads/auth by this push:
     new 878bb06ae18 Cl auth it (#11064)
878bb06ae18 is described below

commit 878bb06ae18c0975f44bc8b39d7d465371758f9b
Author: Colin Li <[email protected]>
AuthorDate: Wed Sep 6 22:20:38 2023 +0800

    Cl auth it (#11064)
---
 .../org/apache/iotdb/db/it/auth/IoTDBAuthIT.java   | 250 +++++++++++++++++----
 .../iotdb/confignode/persistence/AuthorInfo.java   |   2 +-
 .../org/apache/iotdb/db/auth/AuthorityChecker.java |  15 +-
 .../iotdb/db/auth/ClusterAuthorityFetcher.java     |   9 +-
 .../iotdb/db/auth/AuthorizerManagerTest.java       | 113 ++++++++++
 .../org/apache/iotdb/commons/auth/entity/Role.java |   3 +
 .../iotdb/commons/auth/user/BasicUserManager.java  |  21 ++
 7 files changed, 353 insertions(+), 60 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 7aa31c79060..f6a7fa7cf62 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
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.it.auth;
 
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
 import org.apache.iotdb.it.env.EnvFactory;
 import org.apache.iotdb.it.framework.IoTDBTestRunner;
@@ -488,32 +489,41 @@ public class IoTDBAuthIT {
       adminStmt.execute("GRANT READ_SCHEMA ON root.a.b TO USER user1");
       adminStmt.execute("CREATE ROLE role1");
       adminStmt.execute("GRANT READ_SCHEMA,WRITE_DATA ON root.a.b.c TO ROLE 
role1");
-      adminStmt.execute("GRANT READ_SCHEMA,WRITE_DATA ON root.d.b.c TO ROLE 
role1");
-      adminStmt.execute("GRANT role1 TO user1");
+      adminStmt.execute(
+          "GRANT READ_SCHEMA,WRITE_DATA ON root.d.b.c TO ROLE role1 WITH GRANT 
OPTION");
+      adminStmt.execute("GRANT ROLE role1 TO user1");
 
-      ResultSet resultSet = adminStmt.executeQuery("LIST PRIVILEGES USER 
user1");
+      ResultSet resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF USER 
user1");
       String ans =
-          ",root.a.b : READ_SCHEMA"
-              + ",\n"
-              + "role1,root.a.b.c : WRITE_DATA READ_SCHEMA"
-              + ",\n"
-              + "role1,root.d.b.c : WRITE_DATA READ_SCHEMA"
-              + ",\n";
+          ",root.a.b,READ_SCHEMA,false,\n"
+              + "role1,root.a.b.c,WRITE_DATA,false,\n"
+              + "role1,root.a.b.c,READ_SCHEMA,false,\n"
+              + "role1,root.d.b.c,READ_SCHEMA,true,\n"
+              + "role1,root.d.b.c,WRITE_DATA,true,\n";
       try {
         validateResultSet(resultSet, ans);
 
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES USER user1 ON 
root.a.b.c");
-        ans = "role1,root.a.b.c : WRITE_DATA READ_SCHEMA,\n";
-        validateResultSet(resultSet, ans);
-
-        adminStmt.execute("REVOKE role1 from user1");
+        adminStmt.execute("REVOKE ROLE role1 from user1");
 
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES USER user1");
-        ans = ",root.a.b : READ_SCHEMA,\n";
+        resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF USER user1");
+        ans = ",root.a.b,READ_SCHEMA,false,\n";
         validateResultSet(resultSet, ans);
-
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES USER user1 ON 
root.a.**");
-        ans = ",root.a.b : READ_SCHEMA,\n";
+        resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF USER root");
+        ans =
+            ",,MANAGE_USER,true,\n"
+                + ",,MANAGE_ROLE,true,\n"
+                + ",,USE_TRIGGER,true,\n"
+                + ",,USE_UDF,true,\n"
+                + ",,USE_CQ,true,\n"
+                + ",,USE_PIPE,true,\n"
+                + ",,EXTEND_TEMPLATE,true,\n"
+                + ",,MANAGE_DATABASE,true,\n"
+                + ",,MAINTAIN,true,\n"
+                + ",,AUDIT,true,\n"
+                + ",root.**,READ_DATA,true,\n"
+                + ",root.**,WRITE_DATA,true,\n"
+                + ",root.**,READ_SCHEMA,true,\n"
+                + ",root.**,WRITE_SCHEMA,true,\n";
         validateResultSet(resultSet, ans);
       } finally {
         resultSet.close();
@@ -531,30 +541,24 @@ public class IoTDBAuthIT {
 
     try {
       adminStmt.execute("CREATE ROLE role1");
-      ResultSet resultSet = adminStmt.executeQuery("LIST PRIVILEGES ROLE 
role1");
+      ResultSet resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF ROLE 
role1");
       String ans = "";
       try {
         // not granted list role privilege, should return empty
         validateResultSet(resultSet, ans);
 
-        adminStmt.execute("GRANT ROLE role1 PRIVILEGES READ_SCHEMA,WRITE_DATA 
ON root.a.b.c");
-        adminStmt.execute("GRANT ROLE role1 PRIVILEGES READ_SCHEMA,WRITE_DATA 
ON root.d.b.c");
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES ROLE role1");
-        ans = "root.a.b.c : WRITE_DATA READ_SCHEMA,\n" + "root.d.b.c : 
WRITE_DATA READ_SCHEMA,\n";
-        validateResultSet(resultSet, ans);
-
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES ROLE role1 ON 
root.a.b.c");
-        ans = "root.a.b.c : WRITE_DATA READ_SCHEMA,\n";
+        adminStmt.execute("GRANT READ_SCHEMA,WRITE_DATA ON root.a.b.c TO ROLE 
role1");
+        adminStmt.execute(
+            "GRANT READ_SCHEMA,WRITE_DATA ON root.d.b.c TO ROLE role1 WITH 
GRANT OPTION");
+        resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF ROLE role1");
+        ans =
+            
"role1,root.a.b.c,WRITE_DATA,false,\nrole1,root.a.b.c,READ_SCHEMA,false,\nrole1,root.d.b.c,READ_SCHEMA,true,\nrole1,root.d.b.c,WRITE_DATA,true,\n";
         validateResultSet(resultSet, ans);
 
-        adminStmt.execute("REVOKE ROLE role1 PRIVILEGES READ_SCHEMA,WRITE_DATA 
ON root.a.b.c");
-
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES ROLE role1");
-        ans = "root.d.b.c : WRITE_DATA READ_SCHEMA,\n";
-        validateResultSet(resultSet, ans);
+        adminStmt.execute("REVOKE READ_SCHEMA,WRITE_DATA ON root.a.b.c FROM 
ROLE role1");
 
-        resultSet = adminStmt.executeQuery("LIST PRIVILEGES ROLE role1 ON 
root.a.b.c");
-        ans = "";
+        resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF ROLE role1");
+        ans = "role1,root.d.b.c,WRITE_DATA,true,\n" + 
"role1,root.d.b.c,READ_SCHEMA,true,\n";
         validateResultSet(resultSet, ans);
       } finally {
         resultSet.close();
@@ -579,19 +583,19 @@ public class IoTDBAuthIT {
       adminStmt.execute("CREATE ROLE zhazha");
       adminStmt.execute("CREATE ROLE hakase");
 
-      adminStmt.execute("GRANT xijing TO chenduxiu");
-      adminStmt.execute("GRANT dalao TO chenduxiu");
-      adminStmt.execute("GRANT shenshi TO chenduxiu");
-      adminStmt.execute("GRANT zhazha TO chenduxiu");
-      adminStmt.execute("GRANT hakase TO chenduxiu");
+      adminStmt.execute("GRANT ROLE xijing TO chenduxiu");
+      adminStmt.execute("GRANT ROLE dalao TO chenduxiu");
+      adminStmt.execute("GRANT ROLE shenshi TO chenduxiu");
+      adminStmt.execute("GRANT ROLE zhazha TO chenduxiu");
+      adminStmt.execute("GRANT ROLE hakase TO chenduxiu");
 
       ResultSet resultSet = adminStmt.executeQuery("LIST ROLE OF USER 
chenduxiu");
       String ans = "xijing,\n" + "dalao,\n" + "shenshi,\n" + "zhazha,\n" + 
"hakase,\n";
       try {
         validateResultSet(resultSet, ans);
 
-        adminStmt.execute("REVOKE dalao FROM chenduxiu");
-        adminStmt.execute("REVOKE hakase FROM chenduxiu");
+        adminStmt.execute("REVOKE ROLE dalao FROM chenduxiu");
+        adminStmt.execute("REVOKE ROLE hakase FROM chenduxiu");
 
         resultSet = adminStmt.executeQuery("LIST ROLE OF USER chenduxiu");
         ans = "xijing,\n" + "shenshi,\n" + "zhazha,\n";
@@ -634,10 +638,10 @@ public class IoTDBAuthIT {
 
       for (int i = 0; i < members.length - 1; i++) {
         adminStmt.execute("CREATE USER " + members[i] + " 'a666666'");
-        adminStmt.execute("GRANT dalao TO  " + members[i]);
+        adminStmt.execute("GRANT ROLE dalao TO  " + members[i]);
       }
       adminStmt.execute("CREATE USER RiverSky 'a2333333'");
-      adminStmt.execute("GRANT zhazha TO RiverSky");
+      adminStmt.execute("GRANT ROLE zhazha TO RiverSky");
 
       ResultSet resultSet = adminStmt.executeQuery("LIST USER OF ROLE dalao");
       String ans =
@@ -662,7 +666,7 @@ public class IoTDBAuthIT {
         ans = "RiverSky,\n";
         validateResultSet(resultSet, ans);
 
-        adminStmt.execute("REVOKE zhazha from RiverSky");
+        adminStmt.execute("REVOKE ROLE zhazha from RiverSky");
         resultSet = adminStmt.executeQuery("LIST USER OF ROLE zhazha");
         ans = "";
         validateResultSet(resultSet, ans);
@@ -716,7 +720,7 @@ public class IoTDBAuthIT {
       try {
         Assert.assertThrows(SQLException.class, () -> userStmt.execute("LIST 
USER"));
         // with list user privilege
-        adminStmt.execute("GRANT USER tempuser PRIVILEGES MANAGE_USER on 
root.**");
+        adminStmt.execute("GRANT MANAGE_USER on root.** TO USER tempuser");
         ResultSet resultSet = userStmt.executeQuery("LIST USER");
         String ans =
             "root,\n"
@@ -832,4 +836,158 @@ public class IoTDBAuthIT {
       }
     }
   }
+
+  @Test
+  public void testGrantAndGrantOpt() throws SQLException {
+    // 1. CREATE USER1. USER2. USER3
+    Connection adminCon = EnvFactory.getEnv().getConnection();
+    Statement adminStmt = adminCon.createStatement();
+    adminStmt.execute("CREATE USER user1 'password'");
+    adminStmt.execute("CREATE USER user2 'password'");
+    adminStmt.execute("CREATE USER user3 'password'");
+    adminStmt.execute("CREATE ROLE testRole");
+    adminStmt.execute("GRANT MANAGE_DATABASE ON root.** TO ROLE testRole WITH 
GRANT OPTION");
+    adminStmt.execute("GRANT READ_DATA ON root.t1.** TO ROLE testRole");
+    adminStmt.execute("GRANT READ_SCHEMA ON root.t3.t2.** TO ROLE testRole 
WITH GRANT OPTION");
+
+    // 2. USER1 has all privileges on root.**
+    for (PrivilegeType item : PrivilegeType.values()) {
+      String sql = "GRANT %s on root.** to USER user1";
+      adminStmt.execute(String.format(sql, item.toString()));
+    }
+    // 3.admin lists privileges of user1
+    ResultSet resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF USER 
user1");
+    String ans =
+        ",,MANAGE_USER,false,\n"
+            + ",,MANAGE_ROLE,false,\n"
+            + ",,USE_TRIGGER,false,\n"
+            + ",,USE_UDF,false,\n"
+            + ",,USE_CQ,false,\n"
+            + ",,USE_PIPE,false,\n"
+            + ",,EXTEND_TEMPLATE,false,\n"
+            + ",,MANAGE_DATABASE,false,\n"
+            + ",,MAINTAIN,false,\n"
+            + ",,AUDIT,false,\n"
+            + ",root.**,READ_DATA,false,\n"
+            + ",root.**,WRITE_DATA,false,\n"
+            + ",root.**,READ_SCHEMA,false,\n"
+            + ",root.**,WRITE_SCHEMA,false,\n";
+    validateResultSet(resultSet, ans);
+
+    // 4. USER2 has all privilegs on root.** with grant option;
+    for (PrivilegeType item : PrivilegeType.values()) {
+      String sql = "GRANT %s on root.** to USER user2 with grant option";
+      adminStmt.execute(String.format(sql, item.toString()));
+    }
+    resultSet = adminStmt.executeQuery("LIST PRIVILEGES OF USER user2");
+    ans =
+        ",,MANAGE_USER,true,\n"
+            + ",,MANAGE_ROLE,true,\n"
+            + ",,USE_TRIGGER,true,\n"
+            + ",,USE_UDF,true,\n"
+            + ",,USE_CQ,true,\n"
+            + ",,USE_PIPE,true,\n"
+            + ",,EXTEND_TEMPLATE,true,\n"
+            + ",,MANAGE_DATABASE,true,\n"
+            + ",,MAINTAIN,true,\n"
+            + ",,AUDIT,true,\n"
+            + ",root.**,READ_DATA,true,\n"
+            + ",root.**,WRITE_DATA,true,\n"
+            + ",root.**,READ_SCHEMA,true,\n"
+            + ",root.**,WRITE_SCHEMA,true,\n";
+    validateResultSet(resultSet, ans);
+
+    // now user1 has all privileges, user2 has all privileges with grant 
option, user3 doesn't have
+    // privileges
+
+    // 5. Login user1 to list user2 privileges will success
+    // user1 cannot grant any privilegs to user3
+    try (Connection userCon = EnvFactory.getEnv().getConnection("user1", 
"password");
+        Statement userStmt = userCon.createStatement()) {
+      try {
+        resultSet = userStmt.executeQuery("LIST PRIVILEGES OF USER user1");
+        ans =
+            ",,MANAGE_USER,false,\n"
+                + ",,MANAGE_ROLE,false,\n"
+                + ",,USE_TRIGGER,false,\n"
+                + ",,USE_UDF,false,\n"
+                + ",,USE_CQ,false,\n"
+                + ",,USE_PIPE,false,\n"
+                + ",,EXTEND_TEMPLATE,false,\n"
+                + ",,MANAGE_DATABASE,false,\n"
+                + ",,MAINTAIN,false,\n"
+                + ",,AUDIT,false,\n"
+                + ",root.**,READ_DATA,false,\n"
+                + ",root.**,WRITE_DATA,false,\n"
+                + ",root.**,READ_SCHEMA,false,\n"
+                + ",root.**,WRITE_SCHEMA,false,\n";
+        validateResultSet(resultSet, ans);
+        Assert.assertThrows(
+            SQLException.class,
+            () -> userStmt.execute("GRANT MANAGE_ROLE ON root.** TO USER 
user3"));
+        Assert.assertThrows(
+            SQLException.class,
+            () -> userStmt.execute("REVOKE MANAGE_ROLE ON root.** FROM USER 
user2"));
+      } finally {
+        userStmt.close();
+      }
+    }
+    // 6.Login user2 grant and revoke will success.
+    try (Connection userCon = EnvFactory.getEnv().getConnection("user2", 
"password");
+        Statement userStmt = userCon.createStatement()) {
+      try {
+        resultSet = userStmt.executeQuery("LIST PRIVILEGES OF USER user1");
+        validateResultSet(resultSet, ans);
+        userStmt.execute("GRANT MANAGE_ROLE ON root.** TO USER user3");
+        resultSet = userStmt.executeQuery("LIST PRIVILEGES OF USER user3");
+        ans = ",,MANAGE_ROLE,false,\n";
+        validateResultSet(resultSet, ans);
+
+        userStmt.execute("REVOKE MANAGE_ROLE ON root.** FROM USER user1");
+        resultSet = userStmt.executeQuery("LIST PRIVILEGES OF USER user1");
+        ans =
+            ",,MANAGE_USER,false,\n"
+                + ",,USE_TRIGGER,false,\n"
+                + ",,USE_UDF,false,\n"
+                + ",,USE_CQ,false,\n"
+                + ",,USE_PIPE,false,\n"
+                + ",,EXTEND_TEMPLATE,false,\n"
+                + ",,MANAGE_DATABASE,false,\n"
+                + ",,MAINTAIN,false,\n"
+                + ",,AUDIT,false,\n"
+                + ",root.**,READ_DATA,false,\n"
+                + ",root.**,WRITE_DATA,false,\n"
+                + ",root.**,READ_SCHEMA,false,\n"
+                + ",root.**,WRITE_SCHEMA,false,\n";
+        validateResultSet(resultSet, ans);
+      } finally {
+        userStmt.close();
+      }
+    }
+    adminStmt.execute("GRANT ROLE testRole TO user3");
+    // now user has:
+    // 1. MANAGE_ROLE
+    // 2. MANAGE_DATABASE with grant option
+    // 3. READ_DATA on root.t1.**
+    // 4. READ_SCHEMA on root.t3.t2.**
+
+    try (Connection userCon = EnvFactory.getEnv().getConnection("user3", 
"password");
+        Statement userStmt = userCon.createStatement()) {
+      try {
+        // because role's privilege
+        userStmt.execute("GRANT MANAGE_DATABASE ON root.** TO USER user1");
+        Assert.assertThrows(
+            SQLException.class,
+            () -> userStmt.execute("GRANT READ_DATA ON root.t1.** TO USER 
user1"));
+        userStmt.execute("GRANT READ_SCHEMA ON root.t3.t2.t3 TO USER user1");
+        Assert.assertThrows(
+            SQLException.class,
+            () -> userStmt.execute("GRANT READ_DATA ON root.t1.t2.t3 TO USER 
user1"));
+      } finally {
+        userStmt.close();
+      }
+    }
+
+    adminStmt.close();
+  }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
index 2b4d533112e..ada2b0d21a0 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
@@ -115,7 +115,7 @@ public class AuthorInfo implements SnapshotProcessor {
     return result;
   }
 
-  // if All paths fail, return No permission;
+  // if All paths fail, return No permission
   // if some paths fail, return SUCCESS and failed index list
   // if all path success, return success and empty index list
   public TPermissionInfoResp checkUserPrivileges(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
index 39680c183d2..da7836dd039 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
@@ -204,29 +204,26 @@ public class AuthorityChecker {
     boolean listRoleUser = false;
     if (authResp.tag.equals(IoTDBConstant.COLUMN_ROLE)
         || authResp.tag.equals(IoTDBConstant.COLUMN_USER)) {
-      // if list role/user, just return 1 column.
       listRoleUser = true;
-      types.add(TSDataType.TEXT);
-    } else {
-      // if list privilege, return : rolename, path, privilege, grant option
-      types.add(TSDataType.TEXT);
-      types.add(TSDataType.TEXT);
-      types.add(TSDataType.TEXT);
-      types.add(TSDataType.BOOLEAN);
     }
 
-    TsBlockBuilder builder = new TsBlockBuilder(types);
     List<ColumnHeader> headerList = new ArrayList<>();
 
     if (listRoleUser) {
       headerList.add(new ColumnHeader(authResp.getTag(), TSDataType.TEXT));
+      types.add(TSDataType.TEXT);
     } else {
       headerList.add(new ColumnHeader(new String("ROLE"), TSDataType.TEXT));
+      types.add(TSDataType.TEXT);
       headerList.add(new ColumnHeader(new String("PATH"), TSDataType.TEXT));
+      types.add(TSDataType.TEXT);
       headerList.add(new ColumnHeader(new String("PRIVILEGES"), 
TSDataType.TEXT));
+      types.add(TSDataType.TEXT);
       headerList.add(new ColumnHeader(new String("GRANT OPTION"), 
TSDataType.BOOLEAN));
+      types.add(TSDataType.BOOLEAN);
     }
 
+    TsBlockBuilder builder = new TsBlockBuilder(types);
     if (listRoleUser) {
       for (String name : authResp.getMemberInfo()) {
         builder.getTimeColumnBuilder().writeLong(0L);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java
index 410347e9c9b..3f5cfa34573 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.db.auth;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.auth.AuthException;
 import org.apache.iotdb.commons.auth.entity.PathPrivilege;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.commons.auth.entity.Role;
 import org.apache.iotdb.commons.auth.entity.User;
 import org.apache.iotdb.commons.client.IClientManager;
@@ -127,7 +128,7 @@ public class ClusterAuthorityFetcher implements 
IAuthorityFetcher {
     boolean grantOpt;
     if (user != null) {
       if (!user.isOpenIdUser()) {
-        if (!paths.isEmpty()) {
+        if (PrivilegeType.values()[permission].isPathRelevant()) {
           for (PartialPath path : paths) {
             grantOpt = user.checkPathPrivilegeGrantOpt(path, permission);
             if (!grantOpt) {
@@ -152,9 +153,7 @@ public class ClusterAuthorityFetcher implements 
IAuthorityFetcher {
           }
           return true;
         } else {
-          grantOpt =
-              user.getSysPrivilege().contains(permission)
-                  && user.getSysPriGrantOpt().contains(permission);
+          grantOpt = user.checkSysPriGrantOpt(permission);
           if (!grantOpt) {
             for (String roleName : user.getRoleList()) {
               Role role = iAuthorCache.getRoleCache(roleName);
@@ -169,6 +168,7 @@ public class ClusterAuthorityFetcher implements 
IAuthorityFetcher {
                 return checkUserPrivilegeGrantOptFromConfigNode(username, 
paths, permission);
               }
             }
+            return false;
           } else {
             return true;
           }
@@ -363,6 +363,7 @@ public class ClusterAuthorityFetcher implements 
IAuthorityFetcher {
     return iAuthorCache;
   }
 
+  @Override
   public void refreshToken() {
     long currentTime = System.currentTimeMillis();
     if (heartBeatTimeStamp == 0) {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java
index 4542956d9d0..fea562a9489 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java
@@ -187,4 +187,117 @@ public class AuthorizerManagerTest {
     Assert.assertNull(user1);
     Assert.assertNull(role1);
   }
+
+  @Test
+  public void grantOptTest() throws IllegalPathException {
+    User user = new User();
+    Role role = new Role();
+
+    Set<Integer> sysPri = new HashSet<>();
+    sysPri.add(PrivilegeType.MANAGE_DATABASE.ordinal());
+    sysPri.add(PrivilegeType.USE_PIPE.ordinal());
+    user.setSysPrivilegeSet(sysPri);
+
+    Set<Integer> sysGrantOpt = new HashSet<>();
+    sysGrantOpt.add(PrivilegeType.USE_PIPE.ordinal());
+    user.setSysPriGrantOpt(sysGrantOpt);
+
+    List<PathPrivilege> pathList = new ArrayList<>();
+    PartialPath pathRoot = new PartialPath("root.**");
+    PartialPath path1 = new PartialPath("root.d1.**");
+    PathPrivilege priv1 = new PathPrivilege(path1);
+    priv1.grantPrivilege(PrivilegeType.READ_DATA.ordinal(), false);
+    priv1.grantPrivilege(PrivilegeType.WRITE_SCHEMA.ordinal(), true);
+    pathList.add(priv1);
+
+    user.setPrivilegeList(pathList);
+
+    user.setName("user1");
+    user.setPassword("123456");
+
+    // user's priv:
+    // 1. MANAGE_DATABASE
+    // 2. USE_PIPE with grant option
+    // 3. READ_DATA root.d1.**
+    // 4. WRITE_SCHEMA root.d1.** with grant option
+
+    // role's priv:
+    // 1. USE_UDF
+    // 2. USE_CQ with grant option
+    // 3. READ_DATA root.t9.** with grant option
+
+    role.setName("role1");
+    Set<Integer> sysPriRole = new HashSet<>();
+    sysPriRole.add(PrivilegeType.USE_UDF.ordinal());
+    sysPriRole.add(PrivilegeType.USE_CQ.ordinal());
+    role.setSysPrivilegeSet(sysPriRole);
+
+    Set<Integer> sysGrantOptRole = new HashSet<>();
+    sysGrantOptRole.add(PrivilegeType.USE_CQ.ordinal());
+    role.setSysPriGrantOpt(sysGrantOptRole);
+
+    PathPrivilege privRole = new PathPrivilege(new PartialPath("root.t9.**"));
+    privRole.grantPrivilege(PrivilegeType.READ_DATA.ordinal(), true);
+    role.setPrivilegeList(Collections.singletonList(privRole));
+    user.setRoleList(Collections.singletonList("role1"));
+
+    authorityFetcher.getAuthorCache().putUserCache("user1", user);
+    authorityFetcher.getAuthorCache().putRoleCache("role1", role);
+
+    // for system priv. we have USE_PIPE grant option.
+    Assert.assertTrue(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1", Collections.singletonList(pathRoot), 
PrivilegeType.USE_PIPE.ordinal()));
+    Assert.assertFalse(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1", Collections.singletonList(pathRoot), 
PrivilegeType.MANAGE_USER.ordinal()));
+
+    // for path priv. we have write_schema on root.d1.** with grant option.
+    // require root.d1.** with write_schema, return true
+    Assert.assertTrue(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1", Collections.singletonList(path1), 
PrivilegeType.WRITE_SCHEMA.ordinal()));
+    // require root.** with write_schema, return false
+    Assert.assertFalse(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1", Collections.singletonList(pathRoot), 
PrivilegeType.WRITE_SCHEMA.ordinal()));
+    // reuqire root.d1.d2 with write_schema, return true
+    Assert.assertTrue(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1",
+            Collections.singletonList(new PartialPath(new 
String("root.d1.d2"))),
+            PrivilegeType.WRITE_SCHEMA.ordinal()));
+
+    // require root.d1.d2 with read_schema, return false
+    Assert.assertFalse(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1",
+            Collections.singletonList(new PartialPath(new 
String("root.d1.d2"))),
+            PrivilegeType.READ_SCHEMA.ordinal()));
+
+    // role test
+    Assert.assertTrue(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1",
+            Collections.singletonList(new PartialPath(new 
String("root.t9.**"))),
+            PrivilegeType.READ_DATA.ordinal()));
+
+    Assert.assertTrue(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1",
+            Collections.singletonList(new PartialPath(new 
String("root.t9.t10"))),
+            PrivilegeType.READ_DATA.ordinal()));
+
+    Assert.assertFalse(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1",
+            Collections.singletonList(new PartialPath(new 
String("root.t9.**"))),
+            PrivilegeType.WRITE_DATA.ordinal()));
+    Assert.assertFalse(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1", Collections.singletonList(pathRoot), 
PrivilegeType.USE_TRIGGER.ordinal()));
+    Assert.assertTrue(
+        authorityFetcher.checkUserPrivilegeGrantOpt(
+            "user1", Collections.singletonList(pathRoot), 
PrivilegeType.USE_CQ.ordinal()));
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
index 12e4e8e20a1..2be5feb3ab4 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
@@ -222,6 +222,9 @@ public class Role {
     return sysPrivilegeSet.contains(privilegeId);
   }
 
+  public boolean checkSysPriGrantOpt(int privilegeId) {
+    return sysPrivilegeSet.contains(privilegeId) && 
sysPriGrantOpt.contains(privilegeId);
+  }
   /** ----------- misc --------------------* */
   @Override
   public boolean equals(Object o) {
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
index bd1a54e5b25..118df0265eb 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
@@ -19,9 +19,13 @@
 package org.apache.iotdb.commons.auth.user;
 
 import org.apache.iotdb.commons.auth.AuthException;
+import org.apache.iotdb.commons.auth.entity.PathPrivilege;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.commons.auth.entity.User;
 import org.apache.iotdb.commons.concurrent.HashLock;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
+import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.utils.AuthUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
@@ -84,6 +88,23 @@ public abstract class BasicUserManager implements 
IUserManager {
           true);
       
setUserUseWaterMark(CommonDescriptor.getInstance().getConfig().getAdminName(), 
false);
     }
+    admin = getUser(CommonDescriptor.getInstance().getConfig().getAdminName());
+    try {
+      PartialPath rootPath = new PartialPath(new 
String(IoTDBConstant.PATH_ROOT + ".**"));
+      PathPrivilege pathPri = new PathPrivilege(rootPath);
+      for (PrivilegeType item : PrivilegeType.values()) {
+        if (!item.isPathRelevant()) {
+          admin.getSysPrivilege().add(item.ordinal());
+          admin.getSysPriGrantOpt().add(item.ordinal());
+        } else {
+          pathPri.grantPrivilege(item.ordinal(), true);
+        }
+      }
+      admin.getPathPrivilegeList().add(pathPri);
+    } catch (IllegalPathException e) {
+      // This error only results in a lack of permissions for list.
+      logger.warn("Got an wrong path for root to init");
+    }
     logger.info("Admin initialized");
   }
 

Reply via email to