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

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

commit 6fc413b328e51a35ed860c3b3c337154568c54dd
Author: JackieTien97 <jackietie...@gmail.com>
AuthorDate: Thu Sep 18 12:06:44 2025 +0800

    finish db management
---
 .../request/read/database/CountDatabasePlan.java   | 13 ++++-
 .../request/read/database/GetDatabasePlan.java     | 10 +++-
 .../iotdb/confignode/manager/ConfigManager.java    |  8 ++-
 .../iotdb/confignode/persistence/AuthorInfo.java   | 25 ++++-----
 .../persistence/schema/ClusterSchemaInfo.java      | 20 +++++--
 .../confignode/persistence/schema/ConfigMTree.java |  7 ++-
 .../thrift/ConfigNodeRPCServiceProcessor.java      |  8 ++-
 .../persistence/schema/ClusterSchemaInfoTest.java  |  1 +
 .../persistence/schema/ConfigMTreeTest.java        | 22 +++++---
 .../iotdb/db/auth/ClusterAuthorityFetcher.java     | 15 ++----
 .../queryengine/plan/analyze/AnalyzeVisitor.java   | 11 ----
 .../analyze/cache/partition/PartitionCache.java    |  6 ++-
 .../execution/config/TableConfigTaskVisitor.java   | 39 ++++++++------
 .../config/executor/ClusterConfigTaskExecutor.java |  6 ++-
 .../relational/security/AccessControlImpl.java     | 41 +++++++-------
 .../relational/security/ITableAuthCheckerImpl.java | 57 ++++++++++++++++++++
 .../security/TreeAccessCheckVisitor.java           | 62 +++++++++++++++++++---
 .../plan/statement/metadata/CountStatement.java    |  9 ++++
 .../statement/metadata/ShowDatabaseStatement.java  |  9 ++++
 .../mtree/traverser/counter/DatabaseCounter.java   | 16 +++++-
 .../apache/iotdb/commons/auth/utils/AuthUtils.java | 49 +++++++++++++++++
 .../apache/iotdb/commons/schema/table/Audit.java}  | 42 +++++----------
 .../src/main/thrift/confignode.thrift              |  1 +
 23 files changed, 337 insertions(+), 140 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/CountDatabasePlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/CountDatabasePlan.java
index b32fef1a36f..b2bef37fbcf 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/CountDatabasePlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/CountDatabasePlan.java
@@ -31,26 +31,31 @@ public class CountDatabasePlan extends 
ConfigPhysicalReadPlan {
   private final String[] storageGroupPattern;
   private final PathPatternTree scope;
   private final boolean isTableModel;
+  private final boolean canSeeAuditDB;
 
   public CountDatabasePlan(
       final List<String> storageGroupPattern,
       final PathPatternTree scope,
-      final boolean isTableModel) {
+      final boolean isTableModel,
+      final boolean canSeeAuditDB) {
     super(ConfigPhysicalPlanType.CountDatabase);
     this.storageGroupPattern = storageGroupPattern.toArray(new String[0]);
     this.scope = scope;
     this.isTableModel = isTableModel;
+    this.canSeeAuditDB = canSeeAuditDB;
   }
 
   public CountDatabasePlan(
       final ConfigPhysicalPlanType type,
       final List<String> storageGroupPattern,
       final PathPatternTree scope,
-      final boolean isTableModel) {
+      final boolean isTableModel,
+      final boolean canSeeAuditDB) {
     super(type);
     this.storageGroupPattern = storageGroupPattern.toArray(new String[0]);
     this.scope = scope;
     this.isTableModel = isTableModel;
+    this.canSeeAuditDB = canSeeAuditDB;
   }
 
   public String[] getDatabasePattern() {
@@ -65,6 +70,10 @@ public class CountDatabasePlan extends 
ConfigPhysicalReadPlan {
     return isTableModel;
   }
 
+  public boolean isCanSeeAuditDB() {
+    return canSeeAuditDB;
+  }
+
   @Override
   public boolean equals(final Object o) {
     if (this == o) {
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/GetDatabasePlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/GetDatabasePlan.java
index b0adfe88d89..dc90c6e3ba5 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/GetDatabasePlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/database/GetDatabasePlan.java
@@ -31,8 +31,14 @@ public class GetDatabasePlan extends CountDatabasePlan {
       final List<String> storageGroupPathPattern,
       final PathPatternTree scope,
       final boolean isTableModel,
-      final boolean isShowDatabasePlan) {
-    super(ConfigPhysicalPlanType.GetDatabase, storageGroupPathPattern, scope, 
isTableModel);
+      final boolean isShowDatabasePlan,
+      final boolean canSeeAuditDB) {
+    super(
+        ConfigPhysicalPlanType.GetDatabase,
+        storageGroupPathPattern,
+        scope,
+        isTableModel,
+        canSeeAuditDB);
     this.isShowDatabasePlan = isShowDatabasePlan;
   }
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index b70a21d9117..18051e2aa54 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -294,6 +294,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 import static 
org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
+import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE;
 
 /** Entry of all management, AssignPartitionManager, AssignRegionManager. */
 public class ConfigManager implements IManager {
@@ -783,6 +784,10 @@ public class ConfigManager implements IManager {
           getClusterSchemaManager()
               .getMatchedDatabaseSchemasByName(
                   deletedPaths, tDeleteReq.isSetIsTableModel() && 
tDeleteReq.isIsTableModel());
+
+      // remove root.__audit
+      deleteDatabaseSchemaMap.remove(TREE_MODEL_AUDIT_DATABASE);
+
       if (deleteDatabaseSchemaMap.isEmpty()) {
         return RpcUtils.getStatus(
             TSStatusCode.PATH_NOT_EXIST.getStatusCode(),
@@ -1986,7 +1991,8 @@ public class ConfigManager implements IManager {
               req.getDatabasePathPattern(),
               scope,
               req.isSetIsTableModel() && req.isIsTableModel(),
-              true);
+              true,
+              !req.isSetCanSeeAuditDB() || req.isCanSeeAuditDB());
       return getClusterSchemaManager().showDatabase(getDatabasePlan);
     } else {
       return new TShowDatabaseResp().setStatus(status);
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 7550d888e55..e8dd341b15a 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
@@ -25,7 +25,6 @@ import 
org.apache.iotdb.commons.auth.authorizer.BasicAuthorizer;
 import org.apache.iotdb.commons.auth.authorizer.IAuthorizer;
 import org.apache.iotdb.commons.auth.authorizer.OpenIdAuthorizer;
 import org.apache.iotdb.commons.auth.entity.ModelType;
-import org.apache.iotdb.commons.auth.entity.PathPrivilege;
 import org.apache.iotdb.commons.auth.entity.PrivilegeModelType;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.commons.auth.entity.PrivilegeUnion;
@@ -70,6 +69,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static 
org.apache.iotdb.commons.auth.utils.AuthUtils.constructAuthorityScope;
+
 public class AuthorInfo implements SnapshotProcessor {
 
   // Works at config node.
@@ -610,19 +611,13 @@ public class AuthorInfo implements SnapshotProcessor {
       resp.setPrivilegeId(permission);
       return resp;
     }
-    for (PathPrivilege path : user.getPathPrivilegeList()) {
-      if (path.checkPrivilege(type)) {
-        pPtree.appendPathPattern(path.getPath());
-      }
-    }
-    for (String rolename : user.getRoleSet()) {
-      Role role = authorizer.getRole(rolename);
+
+    constructAuthorityScope(pPtree, user, type);
+
+    for (String roleName : user.getRoleSet()) {
+      Role role = authorizer.getRole(roleName);
       if (role != null) {
-        for (PathPrivilege path : role.getPathPrivilegeList()) {
-          if (path.checkPrivilege(type)) {
-            pPtree.appendPathPattern(path.getPath());
-          }
-        }
+        constructAuthorityScope(pPtree, role, type);
       }
     }
     pPtree.constructTree();
@@ -644,7 +639,7 @@ public class AuthorInfo implements SnapshotProcessor {
     return resp;
   }
 
-  public TPermissionInfoResp checkRoleOfUser(String username, String rolename)
+  public TPermissionInfoResp checkRoleOfUser(String username, String roleName)
       throws AuthException {
     TPermissionInfoResp result;
     User user = authorizer.getUser(username);
@@ -653,7 +648,7 @@ public class AuthorInfo implements SnapshotProcessor {
           TSStatusCode.USER_NOT_EXIST, String.format("No such user : %s", 
username));
     }
     result = getUserPermissionInfo(username, ModelType.ALL);
-    if (user.getRoleSet().contains(rolename)) {
+    if (user.getRoleSet().contains(roleName)) {
       result.setStatus(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS));
     } else {
       result.setStatus(RpcUtils.getStatus(TSStatusCode.USER_NOT_HAS_ROLE));
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
index d3a7b79305c..1fc4b04c2b6 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
@@ -134,6 +134,8 @@ import static 
org.apache.iotdb.commons.schema.SchemaConstant.ALL_MATCH_PATTERN;
 import static org.apache.iotdb.commons.schema.SchemaConstant.ALL_MATCH_SCOPE;
 import static org.apache.iotdb.commons.schema.SchemaConstant.ALL_TEMPLATE;
 import static 
org.apache.iotdb.commons.schema.SchemaConstant.SYSTEM_DATABASE_PATTERN;
+import static 
org.apache.iotdb.commons.schema.table.Audit.TABLE_MODEL_AUDIT_DATABASE;
+import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE;
 import static org.apache.iotdb.commons.schema.table.TsTable.TTL_PROPERTY;
 
 /**
@@ -323,9 +325,10 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
       databaseReadWriteLock.readLock().lock();
       try {
         final int count =
-            treeModelMTree.getDatabaseNum(ALL_MATCH_PATTERN, ALL_MATCH_SCOPE, 
false)
-                - treeModelMTree.getDatabaseNum(SYSTEM_DATABASE_PATTERN, 
ALL_MATCH_SCOPE, false)
-                + tableModelMTree.getDatabaseNum(ALL_MATCH_PATTERN, 
ALL_MATCH_SCOPE, false);
+            treeModelMTree.getDatabaseNum(ALL_MATCH_PATTERN, ALL_MATCH_SCOPE, 
false, false)
+                - treeModelMTree.getDatabaseNum(
+                    SYSTEM_DATABASE_PATTERN, ALL_MATCH_SCOPE, false, false)
+                + tableModelMTree.getDatabaseNum(ALL_MATCH_PATTERN, 
ALL_MATCH_SCOPE, false, false);
         if (count >= limit) {
           throw new SchemaQuotaExceededException(limit);
         }
@@ -345,7 +348,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor 
{
       final PartialPath patternPath = new 
PartialPath(plan.getDatabasePattern());
       result.setCount(
           (plan.isTableModel() ? tableModelMTree : treeModelMTree)
-              .getDatabaseNum(patternPath, plan.getScope(), false));
+              .getDatabaseNum(patternPath, plan.getScope(), false, 
plan.isCanSeeAuditDB()));
       result.setStatus(new 
TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()));
     } catch (final MetadataException e) {
       LOGGER.error(ERROR_NAME, e);
@@ -375,6 +378,15 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
             
mTree.getDatabaseNodeByDatabasePath(path).getAsMNode().getDatabaseSchema();
         schemaMap.put(schema.getName(), schema);
       }
+
+      // can not see audit db, remove it
+      if (!plan.isCanSeeAuditDB()) {
+        if (plan.isTableModel()) {
+          schemaMap.remove(TABLE_MODEL_AUDIT_DATABASE);
+        } else {
+          schemaMap.remove(TREE_MODEL_AUDIT_DATABASE);
+        }
+      }
       result.setSchemaMap(schemaMap);
       result.setStatus(new 
TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()));
     } catch (final MetadataException e) {
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
index cf3d6ad0786..18d57535339 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
@@ -277,10 +277,13 @@ public class ConfigMTree {
    * @param isPrefixMatch if true, the path pattern is used to match prefix 
path
    */
   public int getDatabaseNum(
-      final PartialPath pathPattern, final PathPatternTree scope, final 
boolean isPrefixMatch)
+      final PartialPath pathPattern,
+      final PathPatternTree scope,
+      final boolean isPrefixMatch,
+      final boolean needAuditDB)
       throws MetadataException {
     try (final DatabaseCounter<IConfigMNode> counter =
-        new DatabaseCounter<>(root, pathPattern, store, isPrefixMatch, scope)) 
{
+        new DatabaseCounter<>(root, pathPattern, store, isPrefixMatch, scope, 
needAuditDB)) {
       return (int) counter.count();
     }
   }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index 935aa1064e7..2eb35cc9da3 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -527,7 +527,10 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
             : 
PathPatternTree.deserialize(ByteBuffer.wrap(req.getScopePatternTree()));
     final CountDatabasePlan plan =
         new CountDatabasePlan(
-            req.getDatabasePathPattern(), scope, req.isSetIsTableModel() && 
req.isIsTableModel());
+            req.getDatabasePathPattern(),
+            scope,
+            req.isSetIsTableModel() && req.isIsTableModel(),
+            !req.isSetCanSeeAuditDB() || req.isCanSeeAuditDB());
     final CountDatabaseResp countDatabaseResp =
         (CountDatabaseResp) configManager.countMatchedDatabases(plan);
 
@@ -547,7 +550,8 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
             req.getDatabasePathPattern(),
             scope,
             req.isSetIsTableModel() && req.isIsTableModel(),
-            false);
+            false,
+            !req.isSetCanSeeAuditDB() || req.isCanSeeAuditDB());
     final DatabaseSchemaResp databaseSchemaResp =
         (DatabaseSchemaResp) configManager.getMatchedDatabaseSchemas(plan);
 
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
index cc5cb7ef666..a921e39eabe 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
@@ -115,6 +115,7 @@ public class ClusterSchemaInfoTest {
             Arrays.asList(PathUtils.splitPathToDetachedNodes("root.**")),
             ALL_MATCH_SCOPE,
             false,
+            false,
             false);
     Map<String, TDatabaseSchema> reloadResult =
         
clusterSchemaInfo.getMatchedDatabaseSchemas(getStorageGroupReq).getSchemaMap();
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
index 73fe77e40e7..0e887886dcc 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
@@ -202,14 +202,20 @@ public class ConfigMTreeTest {
     root.setStorageGroup(new PartialPath("root.sg3"));
     root.setStorageGroup(new PartialPath("root.a.b.sg3"));
 
-    assertEquals(7, root.getDatabaseNum(new PartialPath("root.**"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(3, root.getDatabaseNum(new PartialPath("root.*"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(2, root.getDatabaseNum(new PartialPath("root.*.*"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(2, root.getDatabaseNum(new PartialPath("root.*.*.*"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(1, root.getDatabaseNum(new PartialPath("root.*.sg1"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(2, root.getDatabaseNum(new PartialPath("root.**.sg1"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(1, root.getDatabaseNum(new PartialPath("root.sg3"), 
ALL_MATCH_SCOPE, false));
-    assertEquals(2, root.getDatabaseNum(new PartialPath("root.*.b.*"), 
ALL_MATCH_SCOPE, false));
+    assertEquals(7, root.getDatabaseNum(new PartialPath("root.**"), 
ALL_MATCH_SCOPE, false, false));
+    assertEquals(3, root.getDatabaseNum(new PartialPath("root.*"), 
ALL_MATCH_SCOPE, false, false));
+    assertEquals(
+        2, root.getDatabaseNum(new PartialPath("root.*.*"), ALL_MATCH_SCOPE, 
false, false));
+    assertEquals(
+        2, root.getDatabaseNum(new PartialPath("root.*.*.*"), ALL_MATCH_SCOPE, 
false, false));
+    assertEquals(
+        1, root.getDatabaseNum(new PartialPath("root.*.sg1"), ALL_MATCH_SCOPE, 
false, false));
+    assertEquals(
+        2, root.getDatabaseNum(new PartialPath("root.**.sg1"), 
ALL_MATCH_SCOPE, false, false));
+    assertEquals(
+        1, root.getDatabaseNum(new PartialPath("root.sg3"), ALL_MATCH_SCOPE, 
false, false));
+    assertEquals(
+        2, root.getDatabaseNum(new PartialPath("root.*.b.*"), ALL_MATCH_SCOPE, 
false, false));
   }
 
   @Test
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 38b840d8215..e26ae2a668e 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
@@ -21,7 +21,6 @@ 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.PrivilegeModelType;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.commons.auth.entity.PrivilegeUnion;
@@ -71,6 +70,8 @@ import java.util.List;
 import java.util.Set;
 import java.util.function.BiFunction;
 
+import static 
org.apache.iotdb.commons.auth.utils.AuthUtils.constructAuthorityScope;
+
 public class ClusterAuthorityFetcher implements IAuthorityFetcher {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(ClusterAuthorityFetcher.class);
   private static final CommonConfig CONFIG = 
CommonDescriptor.getInstance().getConfig();
@@ -340,19 +341,11 @@ public class ClusterAuthorityFetcher implements 
IAuthorityFetcher {
     PathPatternTree patternTree = new PathPatternTree();
     User user = iAuthorCache.getUserCache(username);
     if (user != null) {
-      for (PathPrivilege path : user.getPathPrivilegeList()) {
-        if (path.checkPrivilege(permission)) {
-          patternTree.appendPathPattern(path.getPath());
-        }
-      }
+      constructAuthorityScope(patternTree, user, permission);
       for (String roleName : user.getRoleSet()) {
         Role role = iAuthorCache.getRoleCache(roleName);
         if (role != null) {
-          for (PathPrivilege path : role.getPathPrivilegeList()) {
-            if (path.checkPrivilege(permission)) {
-              patternTree.appendPathPattern(path.getPath());
-            }
-          }
+          constructAuthorityScope(patternTree, role, permission);
         } else {
           return fetchAuthizedPatternTree(username, permission);
         }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
index d5558374cbf..216743e1f67 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
@@ -131,7 +131,6 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesSta
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowCurrentTimestampStatement;
-import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTTLStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement;
@@ -3172,16 +3171,6 @@ public class AnalyzeVisitor extends 
StatementVisitor<Analysis, MPPQueryContext>
     return analysis;
   }
 
-  @Override
-  public Analysis visitShowStorageGroup(
-      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
-    Analysis analysis = new Analysis();
-    analysis.setRealStatement(showDatabaseStatement);
-    analysis.setRespDatasetHeader(
-        
DatasetHeaderFactory.getShowDatabaseHeader(showDatabaseStatement.isDetailed()));
-    return analysis;
-  }
-
   @Override
   public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, 
MPPQueryContext context) {
     Analysis analysis = new Analysis();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
index 5d8a710ba3e..d873ca5f276 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
@@ -237,7 +237,8 @@ public class PartitionCache {
       if (!result.isSuccess()) {
         final TGetDatabaseReq req =
             new TGetDatabaseReq(ROOT_PATH, 
SchemaConstant.ALL_MATCH_SCOPE_BINARY)
-                .setIsTableModel(false);
+                .setIsTableModel(false)
+                .setCanSeeAuditDB(true);
         final TDatabaseSchemaResp databaseSchemaResp = 
client.getMatchedDatabaseSchemas(req);
         if (databaseSchemaResp.getStatus().getCode()
             == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
@@ -258,7 +259,8 @@ public class PartitionCache {
         configNodeClientManager.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) 
{
       final TGetDatabaseReq req =
           new TGetDatabaseReq(ROOT_PATH, SchemaConstant.ALL_MATCH_SCOPE_BINARY)
-              .setIsTableModel(true);
+              .setIsTableModel(true)
+              .setCanSeeAuditDB(true);
       final TDatabaseSchemaResp databaseSchemaResp = 
client.getMatchedDatabaseSchemas(req);
       if (databaseSchemaResp.getStatus().getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
         // update all database into cache
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
index 212497ef856..a5086c6ef58 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
@@ -1018,7 +1018,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   protected IConfigTask visitCreatePipe(final CreatePipe node, final 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
     final String userName = context.getSession().getUserName();
-    accessControl.checkUserIsAdmin(userName);
+    accessControl.checkUserGlobalSysPrivilege(userName);
 
     final Map<String, String> extractorAttributes = 
node.getExtractorAttributes();
     final String pipeName = node.getPipeName();
@@ -1144,7 +1144,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
     context.setQueryType(QueryType.WRITE);
 
     final String userName = context.getSession().getUserName();
-    accessControl.checkUserIsAdmin(userName);
+    accessControl.checkUserGlobalSysPrivilege(userName);
 
     final String pipeName = node.getPipeName();
     final Map<String, String> extractorAttributes = 
node.getExtractorAttributes();
@@ -1175,34 +1175,35 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitDropPipe(DropPipe node, MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new DropPipeTask(node);
   }
 
   @Override
   protected IConfigTask visitStartPipe(StartPipe node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new StartPipeTask(node);
   }
 
   @Override
   protected IConfigTask visitStopPipe(StopPipe node, MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new StopPipeTask(node);
   }
 
   @Override
   protected IConfigTask visitShowPipes(ShowPipes node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new ShowPipeTask(node, context.getSession().getUserName());
   }
 
   @Override
   protected IConfigTask visitCreatePipePlugin(CreatePipePlugin node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     if (node.getUriString() != null && isUriTrusted(node.getUriString())) {
       // 1. user specified uri and that uri is trusted
       // 2. user doesn't specify uri
@@ -1216,20 +1217,21 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitDropPipePlugin(DropPipePlugin node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new DropPipePluginTask(node);
   }
 
   @Override
   protected IConfigTask visitShowPipePlugins(ShowPipePlugins node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new ShowPipePluginsTask(node);
   }
 
   @Override
   protected IConfigTask visitCreateTopic(CreateTopic node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
 
     // Inject table model into the topic attributes
     node.getTopicAttributes()
@@ -1241,28 +1243,28 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitDropTopic(DropTopic node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new DropTopicTask(node);
   }
 
   @Override
   protected IConfigTask visitShowTopics(ShowTopics node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new ShowTopicsTask(node);
   }
 
   @Override
   protected IConfigTask visitShowSubscriptions(ShowSubscriptions node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.READ);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new ShowSubscriptionsTask(node);
   }
 
   @Override
   protected IConfigTask visitDropSubscription(DropSubscription node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new DropSubscriptionTask(node);
   }
 
@@ -1323,9 +1325,9 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitRelationalAuthorPlan(
       RelationalAuthorStatement node, MPPQueryContext context) {
+    context.setQueryType(node.getQueryType());
     accessControl.checkUserCanRunRelationalAuthorStatement(
         context.getSession().getUserName(), node);
-    context.setQueryType(node.getQueryType());
     if (node.getAuthorType() == AuthorRType.UPDATE_USER) {
       visitUpdateUser(node);
     }
@@ -1354,7 +1356,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitCreateFunction(CreateFunction node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     if (node.getUriString().map(ExecutableManager::isUriTrusted).orElse(true)) 
{
       // 1. user specified uri and that uri is trusted
       // 2. user doesn't specify uri
@@ -1374,7 +1376,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitDropFunction(DropFunction node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
-    accessControl.checkUserIsAdmin(context.getSession().getUserName());
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new DropFunctionTask(Model.TABLE, node.getUdfName());
   }
 
@@ -1418,7 +1420,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitCreateTraining(CreateTraining node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
-
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new CreateTrainingTask(
         node.getModelId(), node.getParameters(), node.getExistingModelId(), 
node.getTargetSql());
   }
@@ -1426,6 +1428,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitCreateModel(CreateModel node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     String uri = node.getUri();
     if (uri != null && ExecutableManager.isUriTrusted(uri)) {
       // user specified uri and that uri is trusted
@@ -1444,12 +1447,14 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitDropModel(DropModel node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new DropModelTask(node.getModelId());
   }
 
   @Override
   protected IConfigTask visitShowLoadedModels(ShowLoadedModels node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new ShowLoadedModelsTask(node.getDeviceIdList());
   }
 
@@ -1462,12 +1467,14 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitLoadModel(LoadModel node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new LoadModelTask(node.getModelId(), node.getDeviceIdList());
   }
 
   @Override
   protected IConfigTask visitUnloadModel(UnloadModel node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserGlobalSysPrivilege(context.getSession().getUserName());
     return new UnloadModelTask(node.getModelId(), node.getDeviceIdList());
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
index f5fc2e5f023..e6bb0d50f67 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
@@ -498,7 +498,8 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
       final TGetDatabaseReq req =
           new TGetDatabaseReq(
                   databasePathPattern, 
showDatabaseStatement.getAuthorityScope().serialize())
-              .setIsTableModel(false);
+              .setIsTableModel(false)
+              .setCanSeeAuditDB(showDatabaseStatement.isCanSeeAuditDB());
       final TShowDatabaseResp resp = client.showDatabase(req);
       // build TSBlock
       showDatabaseStatement.buildTSBlock(resp.getDatabaseInfoMap(), future);
@@ -519,7 +520,8 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
         
CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
       TGetDatabaseReq req =
           new TGetDatabaseReq(
-              databasePathPattern, 
countDatabaseStatement.getAuthorityScope().serialize());
+                  databasePathPattern, 
countDatabaseStatement.getAuthorityScope().serialize())
+              .setCanSeeAuditDB(countDatabaseStatement.isCanSeeAuditDB());
       TCountDatabaseResp resp = client.countMatchedDatabases(req);
       databaseNum = resp.getCount();
       // build TSBlock
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
index 3ddd2cd04be..1e15a3a7874 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
@@ -38,10 +38,14 @@ import org.apache.iotdb.rpc.TSStatusCode;
 import java.util.Collection;
 import java.util.Objects;
 
+import static 
org.apache.iotdb.commons.schema.table.Audit.TABLE_MODEL_AUDIT_DATABASE;
 import static org.apache.iotdb.db.auth.AuthorityChecker.ONLY_ADMIN_ALLOWED;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.security.ITableAuthCheckerImpl.checkCanSelectAuditTable;
 
 public class AccessControlImpl implements AccessControl {
 
+  public static final String READ_ONLY_DB_ERROR_MSG = "The database '%s' is 
read-only.";
+
   private final ITableAuthChecker authChecker;
 
   private final StatementVisitor<TSStatus, TreeAccessCheckContext> 
treeAccessCheckVisitor;
@@ -52,48 +56,40 @@ public class AccessControlImpl implements AccessControl {
     this.treeAccessCheckVisitor = visitor;
   }
 
+  private void checkAuditDatabase(String databaseName) {
+    if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
+      throw new AccessDeniedException(
+          String.format(READ_ONLY_DB_ERROR_MSG, TABLE_MODEL_AUDIT_DATABASE));
+    }
+  }
+
   @Override
   public void checkCanCreateDatabase(String userName, String databaseName) {
     InformationSchemaUtils.checkDBNameInWrite(databaseName);
-    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
-      return;
-    }
     authChecker.checkDatabasePrivilege(userName, databaseName, 
TableModelPrivilege.CREATE);
   }
 
   @Override
   public void checkCanDropDatabase(String userName, String databaseName) {
     InformationSchemaUtils.checkDBNameInWrite(databaseName);
-    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
-      return;
-    }
     authChecker.checkDatabasePrivilege(userName, databaseName, 
TableModelPrivilege.DROP);
   }
 
   @Override
   public void checkCanAlterDatabase(String userName, String databaseName) {
     InformationSchemaUtils.checkDBNameInWrite(databaseName);
-    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
-      return;
-    }
     authChecker.checkDatabasePrivilege(userName, databaseName, 
TableModelPrivilege.ALTER);
   }
 
   @Override
   public void checkCanShowOrUseDatabase(String userName, String databaseName) {
-    // Information_schema is visible to any user
-    if (databaseName.equals(InformationSchema.INFORMATION_DATABASE)) {
-      return;
-    }
-    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
-      return;
-    }
     authChecker.checkDatabaseVisibility(userName, databaseName);
   }
 
   @Override
   public void checkCanCreateTable(String userName, QualifiedObjectName 
tableName) {
     InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName());
+    checkAuditDatabase(tableName.getDatabaseName());
     if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
       return;
     }
@@ -103,6 +99,7 @@ public class AccessControlImpl implements AccessControl {
   @Override
   public void checkCanDropTable(String userName, QualifiedObjectName 
tableName) {
     InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName());
+    checkAuditDatabase(tableName.getDatabaseName());
     if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
       return;
     }
@@ -112,6 +109,7 @@ public class AccessControlImpl implements AccessControl {
   @Override
   public void checkCanAlterTable(String userName, QualifiedObjectName 
tableName) {
     InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName());
+    checkAuditDatabase(tableName.getDatabaseName());
     if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
       return;
     }
@@ -121,6 +119,7 @@ public class AccessControlImpl implements AccessControl {
   @Override
   public void checkCanInsertIntoTable(String userName, QualifiedObjectName 
tableName) {
     InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName());
+    checkAuditDatabase(tableName.getDatabaseName());
     authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.INSERT);
   }
 
@@ -129,6 +128,9 @@ public class AccessControlImpl implements AccessControl {
     if 
(tableName.getDatabaseName().equals(InformationSchema.INFORMATION_DATABASE)) {
       return;
     }
+    if 
(TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(tableName.getDatabaseName())) {
+      checkCanSelectAuditTable(userName);
+    }
     authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.SELECT);
   }
 
@@ -149,6 +151,7 @@ public class AccessControlImpl implements AccessControl {
   @Override
   public void checkCanDeleteFromTable(String userName, QualifiedObjectName 
tableName) {
     InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName());
+    checkAuditDatabase(tableName.getDatabaseName());
     authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.DELETE);
   }
 
@@ -158,9 +161,6 @@ public class AccessControlImpl implements AccessControl {
     if 
(tableName.getDatabaseName().equals(InformationSchema.INFORMATION_DATABASE)) {
       return;
     }
-    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
-      return;
-    }
     authChecker.checkTableVisibility(userName, tableName);
   }
 
@@ -169,9 +169,6 @@ public class AccessControlImpl implements AccessControl {
     if (AuthorityChecker.SUPER_USER.equals(userName)) {
       return;
     }
-    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
-      return;
-    }
     TSStatus status =
         AuthorityChecker.getTSStatus(
             AuthorityChecker.checkFullPathOrPatternPermission(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
index 97c4bb2ad99..7172f5b7b8b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
@@ -21,12 +21,15 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.security;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
+import org.apache.iotdb.commons.schema.table.InformationSchema;
 import org.apache.iotdb.db.auth.AuthorityChecker;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import java.util.Collection;
 
+import static 
org.apache.iotdb.commons.schema.table.Audit.TABLE_MODEL_AUDIT_DATABASE;
+
 public class ITableAuthCheckerImpl implements ITableAuthChecker {
 
   @Override
@@ -34,6 +37,22 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
     if (AuthorityChecker.SUPER_USER.equals(userName)) {
       return;
     }
+    // Information_schema is visible to any user
+    if (databaseName.equals(InformationSchema.INFORMATION_DATABASE)) {
+      return;
+    }
+
+    if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
+      if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT)) {
+        return;
+      } else {
+        throw new AccessDeniedException("DATABASE " + databaseName);
+      }
+    }
+
+    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
+      return;
+    }
     if (!AuthorityChecker.checkDBVisible(userName, databaseName)) {
       throw new AccessDeniedException("DATABASE " + databaseName);
     }
@@ -42,9 +61,16 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
   @Override
   public void checkDatabasePrivilege(
       String userName, String databaseName, TableModelPrivilege privilege) {
+    checkAuditDatabase(userName, privilege, databaseName);
+
     if (AuthorityChecker.SUPER_USER.equals(userName)) {
       return;
     }
+
+    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
+      return;
+    }
+
     TSStatus result =
         AuthorityChecker.getTSStatus(
             AuthorityChecker.checkDBPermission(
@@ -56,6 +82,27 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
     }
   }
 
+  private static void checkAuditDatabase(
+      String userName, TableModelPrivilege privilege, String databaseName) {
+    if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
+      if (privilege == TableModelPrivilege.SELECT) {
+        checkCanSelectAuditTable(userName);
+      } else {
+        throw new AccessDeniedException(
+            String.format("The database '%s' is read-only.", 
TABLE_MODEL_AUDIT_DATABASE));
+      }
+    }
+  }
+
+  public static void checkCanSelectAuditTable(String userName) {
+    if (!AuthorityChecker.SUPER_USER.equals(userName)
+        && !AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT)) {
+      throw new AccessDeniedException(
+          String.format(
+              "The database '%s' can only be queried by AUDIT admin.", 
TABLE_MODEL_AUDIT_DATABASE));
+    }
+  }
+
   @Override
   public void checkDatabasePrivilegeGrantOption(
       String userName, String databaseName, TableModelPrivilege privilege) {
@@ -137,6 +184,16 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
     if (AuthorityChecker.SUPER_USER.equals(userName)) {
       return;
     }
+
+    String databaseName = tableName.getDatabaseName();
+    if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)
+        && !AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT)) {
+      throw new AccessDeniedException("TABLE " + tableName);
+    }
+
+    if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
+      return;
+    }
     if (!AuthorityChecker.checkTableVisible(
         userName, tableName.getDatabaseName(), tableName.getObjectName())) {
       throw new AccessDeniedException("TABLE " + tableName);
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 6732d3cafd3..7f42900e9c2 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
@@ -146,7 +146,11 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+import static 
org.apache.iotdb.commons.schema.table.Audit.TABLE_MODEL_AUDIT_DATABASE;
+import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE;
+import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE_PATH;
 import static org.apache.iotdb.db.auth.AuthorityChecker.SUCCEED;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.security.AccessControlImpl.READ_ONLY_DB_ERROR_MSG;
 
 /** userName in TreeAccessCheckContext will never be SUPER_USER */
 public class TreeAccessCheckVisitor extends StatementVisitor<TSStatus, 
TreeAccessCheckContext> {
@@ -185,6 +189,11 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitSetSchemaTemplate(
       SetSchemaTemplateStatement setSchemaTemplateStatement, 
TreeAccessCheckContext context) {
+    // root.__audit can never be deleted
+    if 
(TREE_MODEL_AUDIT_DATABASE_PATH.equals(setSchemaTemplateStatement.getPath())) {
+      return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
+          .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TABLE_MODEL_AUDIT_DATABASE));
+    }
     return checkSystemAuth(context.userName);
   }
 
@@ -684,37 +693,74 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitSetDatabase(
       DatabaseSchemaStatement statement, TreeAccessCheckContext context) {
-    return checkCreateOrAlterDatabasePermission(context.userName);
+    return checkCreateOrAlterDatabasePermission(context.userName, 
statement.getDatabasePath());
   }
 
   @Override
   public TSStatus visitAlterDatabase(
       DatabaseSchemaStatement databaseSchemaStatement, TreeAccessCheckContext 
context) {
-    return checkCreateOrAlterDatabasePermission(context.userName);
+    return checkCreateOrAlterDatabasePermission(
+        context.userName, databaseSchemaStatement.getDatabasePath());
   }
 
   @Override
   public TSStatus visitShowStorageGroup(
       ShowDatabaseStatement showDatabaseStatement, TreeAccessCheckContext 
context) {
-    return visitAuthorityInformation(showDatabaseStatement, context);
+    if (!AuthorityChecker.checkSystemPermission(context.userName, 
PrivilegeType.AUDIT)) {
+      showDatabaseStatement.setCanSeeAuditDB(false);
+    }
+    return checkShowOrCountDatabasePermission(showDatabaseStatement, context);
   }
 
   @Override
   public TSStatus visitCountStorageGroup(
       CountDatabaseStatement countDatabaseStatement, TreeAccessCheckContext 
context) {
-    return visitAuthorityInformation(countDatabaseStatement, context);
+    if (!AuthorityChecker.checkSystemPermission(context.userName, 
PrivilegeType.AUDIT)) {
+      countDatabaseStatement.setCanSeeAuditDB(false);
+    }
+    return checkShowOrCountDatabasePermission(countDatabaseStatement, context);
   }
 
   @Override
   public TSStatus visitDeleteStorageGroup(
       DeleteDatabaseStatement statement, TreeAccessCheckContext context) {
-    return checkCreateOrAlterDatabasePermission(context.userName);
+    for (String prefixPath : statement.getPrefixPath()) {
+      // root.__audit can never be deleted
+      if (TREE_MODEL_AUDIT_DATABASE.equals(prefixPath)) {
+        return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
+            .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TABLE_MODEL_AUDIT_DATABASE));
+      }
+    }
+    return AuthorityChecker.getTSStatus(
+        AuthorityChecker.checkSystemPermission(context.userName, 
PrivilegeType.SYSTEM)
+            || AuthorityChecker.checkSystemPermission(
+                context.userName, PrivilegeType.MANAGE_DATABASE),
+        PrivilegeType.SYSTEM);
   }
 
-  private TSStatus checkCreateOrAlterDatabasePermission(String userName) {
+  private TSStatus checkCreateOrAlterDatabasePermission(String userName, 
PartialPath databaseName) {
+    // root.__audit can never be created or alter
+    if (TREE_MODEL_AUDIT_DATABASE_PATH.equals(databaseName)) {
+      return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
+          .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TABLE_MODEL_AUDIT_DATABASE));
+    }
     return AuthorityChecker.getTSStatus(
-        AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.MANAGE_DATABASE),
-        PrivilegeType.MANAGE_DATABASE);
+        AuthorityChecker.checkSystemPermission(userName, PrivilegeType.SYSTEM)
+            || AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.MANAGE_DATABASE),
+        PrivilegeType.SYSTEM);
+  }
+
+  private TSStatus checkShowOrCountDatabasePermission(
+      AuthorityInformationStatement statement, TreeAccessCheckContext context) 
{
+    // own SYSTEM/MAINTAIN can see all except for root.__audit, otherwise can 
only see PATHS that
+    // user has READ_SCHEMA auth
+    if (!AuthorityChecker.checkSystemPermission(context.userName, 
PrivilegeType.SYSTEM)
+        && !AuthorityChecker.checkSystemPermission(
+            context.userName, PrivilegeType.MANAGE_DATABASE)) {
+      return visitAuthorityInformation(statement, context);
+    } else {
+      return SUCCEED;
+    }
   }
 
   // ==================================== data related 
========================================
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
index 529a8660dfb..a10f05aa659 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
@@ -34,6 +34,7 @@ import java.util.List;
  */
 public class CountStatement extends ShowStatement {
   protected PartialPath pathPattern;
+  private boolean canSeeAuditDB = true;
 
   public CountStatement(PartialPath pathPattern) {
     this.pathPattern = pathPattern;
@@ -52,4 +53,12 @@ public class CountStatement extends ShowStatement {
   public List<PartialPath> getPaths() {
     return Collections.singletonList(pathPattern);
   }
+
+  public boolean isCanSeeAuditDB() {
+    return canSeeAuditDB;
+  }
+
+  public void setCanSeeAuditDB(boolean canSeeAuditDB) {
+    this.canSeeAuditDB = canSeeAuditDB;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
index d91e1f65f0d..a84758264d8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
@@ -53,6 +53,7 @@ public class ShowDatabaseStatement extends ShowStatement 
implements IConfigState
 
   private final PartialPath pathPattern;
   private boolean isDetailed;
+  private boolean canSeeAuditDB = true;
 
   public ShowDatabaseStatement(final PartialPath pathPattern) {
     super();
@@ -128,4 +129,12 @@ public class ShowDatabaseStatement extends ShowStatement 
implements IConfigState
   public List<PartialPath> getPaths() {
     return Collections.singletonList(pathPattern);
   }
+
+  public boolean isCanSeeAuditDB() {
+    return canSeeAuditDB;
+  }
+
+  public void setCanSeeAuditDB(boolean canSeeAuditDB) {
+    this.canSeeAuditDB = canSeeAuditDB;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/traverser/counter/DatabaseCounter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/traverser/counter/DatabaseCounter.java
index 2e16b188e21..bfdb7d866a3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/traverser/counter/DatabaseCounter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/traverser/counter/DatabaseCounter.java
@@ -25,25 +25,37 @@ import org.apache.iotdb.commons.schema.node.IMNode;
 import org.apache.iotdb.db.schemaengine.schemaregion.mtree.IMTreeStore;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.traverser.basic.DatabaseTraverser;
 
+import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE_PATH;
+
 // This class implement database counter.
 public class DatabaseCounter<N extends IMNode<N>> extends 
DatabaseTraverser<Void, N>
     implements Counter {
 
   private int count;
+  private final boolean needAuditDB;
 
   public DatabaseCounter(
       N startNode,
       PartialPath path,
       IMTreeStore<N> store,
       boolean isPrefixMatch,
-      PathPatternTree scope)
+      PathPatternTree scope,
+      boolean needAuditDB)
       throws MetadataException {
     super(startNode, path, store, isPrefixMatch, scope);
+    this.needAuditDB = needAuditDB;
   }
 
   @Override
   protected Void generateResult(N nextMatchedNode) {
-    count++;
+    if (needAuditDB) {
+      count++;
+    } else {
+      PartialPath dbName = 
nextMatchedNode.getAsDatabaseMNode().getPartialPath();
+      if (TREE_MODEL_AUDIT_DATABASE_PATH.equals(dbName)) {
+        count--;
+      }
+    }
     return null;
   }
 
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/utils/AuthUtils.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/utils/AuthUtils.java
new file mode 100644
index 00000000000..e842047a42a
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/utils/AuthUtils.java
@@ -0,0 +1,49 @@
+/*
+ * 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.commons.auth.utils;
+
+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.path.PathPatternTree;
+
+import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE_PATH_PATTERN;
+
+public class AuthUtils {
+
+  private AuthUtils() {}
+
+  public static void constructAuthorityScope(
+      PathPatternTree patternTree, Role role, PrivilegeType permission) {
+    for (PathPrivilege path : role.getPathPrivilegeList()) {
+      if (path.checkPrivilege(permission)) {
+        patternTree.appendPathPattern(path.getPath());
+      }
+    }
+    // for audit admin, we need to add authority scope root.__audit.**
+    if (permission == PrivilegeType.READ_DATA || permission == 
PrivilegeType.READ_SCHEMA) {
+      for (PrivilegeType globalPrivilege : role.getSysPrivilege()) {
+        if (globalPrivilege == PrivilegeType.AUDIT) {
+          
patternTree.appendPathPattern(TREE_MODEL_AUDIT_DATABASE_PATH_PATTERN);
+        }
+      }
+    }
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/Audit.java
similarity index 50%
copy from 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
copy to 
iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/Audit.java
index 529a8660dfb..257845e0f29 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/Audit.java
@@ -17,39 +17,21 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.queryengine.plan.statement.metadata;
+package org.apache.iotdb.commons.schema.table;
 
 import org.apache.iotdb.commons.path.PartialPath;
-import org.apache.iotdb.db.queryengine.plan.statement.StatementType;
 
-import java.util.Collections;
-import java.util.List;
+import static 
org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
+import static org.apache.iotdb.commons.schema.SchemaConstant.ROOT;
 
-/**
- * COUNT statement.
- *
- * <p>Here is the syntax definition:
- *
- * <p>COUNT {DATABASES | DEVICES | TIMESERIES | NODES} [prefixPath] [GROUP BY] 
LEVEL = level
- */
-public class CountStatement extends ShowStatement {
-  protected PartialPath pathPattern;
-
-  public CountStatement(PartialPath pathPattern) {
-    this.pathPattern = pathPattern;
-    setType(StatementType.COUNT);
-  }
-
-  public PartialPath getPathPattern() {
-    return pathPattern;
-  }
-
-  public void setPathPattern(PartialPath pathPattern) {
-    this.pathPattern = pathPattern;
-  }
+public class Audit {
+  public static final String TABLE_MODEL_AUDIT_DATABASE = "__audit";
+  public static final String TREE_MODEL_AUDIT_DATABASE =
+      String.format("%s.%s", ROOT, TABLE_MODEL_AUDIT_DATABASE);
+  public static final PartialPath TREE_MODEL_AUDIT_DATABASE_PATH =
+      new PartialPath(new String[] {"root", TABLE_MODEL_AUDIT_DATABASE});
+  public static final PartialPath TREE_MODEL_AUDIT_DATABASE_PATH_PATTERN =
+      new PartialPath(new String[] {"root", TABLE_MODEL_AUDIT_DATABASE, 
MULTI_LEVEL_PATH_WILDCARD});
 
-  @Override
-  public List<PartialPath> getPaths() {
-    return Collections.singletonList(pathPattern);
-  }
+  private Audit() {}
 }
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift 
b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index 2f1b4302c3e..455097357e8 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -695,6 +695,7 @@ struct TGetDatabaseReq {
   1: required list<string> databasePathPattern
   2: required binary scopePatternTree
   3: optional bool isTableModel
+  4: optional bool canSeeAuditDB
 }
 
 struct TShowDatabaseResp {

Reply via email to