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

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

commit ac6dd6a3f3eafb4a905f4ce791a5a81867e7119a
Author: JackieTien97 <[email protected]>
AuthorDate: Mon Dec 2 20:19:06 2024 +0800

    Add AccessControl support for query and database related
---
 .../iotdb/db/queryengine/plan/Coordinator.java     |  13 ++-
 .../execution/config/TableConfigTaskVisitor.java   |  41 +++++++-
 .../config/executor/ClusterConfigTaskExecutor.java |   6 +-
 .../config/executor/IConfigTaskExecutor.java       |   4 +-
 .../config/metadata/relational/ShowDBTask.java     |  28 +++--
 .../plan/relational/analyzer/Analyzer.java         |  11 --
 .../relational/analyzer/StatementAnalyzer.java     |  33 ++----
 .../plan/relational/planner/TableModelPlanner.java |   9 +-
 .../plan/relational/security/AccessControl.java    | 113 ++++++++++++++++++++-
 .../relational/security/AccessControlImpl.java     |  91 +++++++++++++++++
 .../relational/security/AllowAllAccessControl.java |  64 +++++++++++-
 .../relational/security/ITableAuthChecker.java     |  75 ++++++++++++++
 ...AccessControl.java => TableModelPrivilege.java} |  15 ++-
 .../plan/relational/analyzer/AnalyzerTest.java     |   5 +-
 .../plan/relational/planner/PlanTester.java        |   6 +-
 .../exception/auth/AccessDeniedException.java}     |  14 ++-
 16 files changed, 456 insertions(+), 72 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
index 61be1471b15..22c9a7a282b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
@@ -52,6 +52,8 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.TableModelPlanner
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.DistributedOptimizeFactory;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.LogicalOptimizeFactory;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.PlanOptimizer;
+import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.security.AllowAllAccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ClearCache;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
@@ -139,6 +141,7 @@ public class Coordinator {
 
   private final List<PlanOptimizer> logicalPlanOptimizers;
   private final List<PlanOptimizer> distributionPlanOptimizers;
+  private final AccessControl accessControl;
 
   private Coordinator() {
     this.queryExecutionMap = new ConcurrentHashMap<>();
@@ -155,6 +158,7 @@ public class Coordinator {
                 new PlannerContext(
                     LocalExecutionPlanner.getInstance().metadata, new 
InternalTypeManager()))
             .getPlanOptimizers();
+    this.accessControl = new AllowAllAccessControl();
   }
 
   private ExecutionResult execution(
@@ -333,7 +337,8 @@ public class Coordinator {
             SYNC_INTERNAL_SERVICE_CLIENT_MANAGER,
             ASYNC_INTERNAL_SERVICE_CLIENT_MANAGER,
             logicalPlanOptimizers,
-            distributionPlanOptimizers);
+            distributionPlanOptimizers,
+            accessControl);
     return new QueryExecution(tableModelPlanner, queryContext, executor);
   }
 
@@ -380,7 +385,8 @@ public class Coordinator {
           queryContext,
           null,
           executor,
-          statement.accept(new TableConfigTaskVisitor(clientSession, 
metadata), queryContext));
+          statement.accept(
+              new TableConfigTaskVisitor(clientSession, metadata, 
accessControl), queryContext));
     }
     if (statement instanceof WrappedInsertStatement) {
       ((WrappedInsertStatement) statement).setContext(queryContext);
@@ -396,7 +402,8 @@ public class Coordinator {
             SYNC_INTERNAL_SERVICE_CLIENT_MANAGER,
             ASYNC_INTERNAL_SERVICE_CLIENT_MANAGER,
             logicalPlanOptimizers,
-            distributionPlanOptimizers);
+            distributionPlanOptimizers,
+            accessControl);
     return new QueryExecution(tableModelPlanner, queryContext, executor);
   }
 
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 ab93ad531cd..569e82bb2f4 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
@@ -74,7 +74,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analyzer;
 import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.StatementAnalyzerFactory;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableHeaderSchemaValidator;
-import 
org.apache.iotdb.db.queryengine.plan.relational.planner.TableModelPlanner;
+import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
@@ -133,6 +133,7 @@ import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.Pair;
 
+import java.security.AccessControlException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -163,9 +164,15 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
 
   private final Metadata metadata;
 
-  public TableConfigTaskVisitor(final IClientSession clientSession, final 
Metadata metadata) {
+  private final AccessControl accessControl;
+
+  public TableConfigTaskVisitor(
+      final IClientSession clientSession,
+      final Metadata metadata,
+      final AccessControl accessControl) {
     this.clientSession = clientSession;
     this.metadata = metadata;
+    this.accessControl = accessControl;
   }
 
   @Override
@@ -184,6 +191,8 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
     final String dbName = node.getDbName();
     validateDatabaseName(dbName);
 
+    accessControl.checkCanCreateDatabase(context.getSession().getUserName(), 
dbName);
+
     schema.setName(ROOT + PATH_SEPARATOR_CHAR + dbName);
 
     for (final Property property : node.getProperties()) {
@@ -235,25 +244,40 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitUse(final Use node, final MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
+    accessControl.checkCanShowOrUseDatabase(
+        context.getSession().getUserName(), node.getDatabaseId().getValue());
     return new UseDBTask(node, clientSession);
   }
 
   @Override
   protected IConfigTask visitDropDB(final DropDB node, final MPPQueryContext 
context) {
     context.setQueryType(QueryType.WRITE);
+    accessControl.checkCanDropDatabase(
+        context.getSession().getUserName(), node.getDbName().getValue());
     return new DropDBTask(node);
   }
 
   @Override
   protected IConfigTask visitShowDB(final ShowDB node, final MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
-    return new ShowDBTask(node);
+    return new ShowDBTask(
+        node,
+        databaseName -> {
+          try {
+            accessControl.checkCanShowOrUseDatabase(
+                context.getSession().getUserName(), databaseName);
+            return true;
+          } catch (AccessControlException e) {
+            return false;
+          }
+        });
   }
 
   @Override
   protected IConfigTask visitShowCluster(
       final ShowCluster showCluster, final MPPQueryContext context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     // As the implementation is identical, we'll simply translate to the
     // corresponding tree-model variant and execute that.
     ShowClusterStatement treeStatement = new ShowClusterStatement();
@@ -265,6 +289,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   protected IConfigTask visitShowRegions(
       final ShowRegions showRegions, final MPPQueryContext context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     // As the implementation is identical, we'll simply translate to the
     // corresponding tree-model variant and execute that.
     final ShowRegionStatement treeStatement = new ShowRegionStatement();
@@ -278,6 +303,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   protected IConfigTask visitShowDataNodes(
       final ShowDataNodes showDataNodesStatement, final MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new ShowDataNodesTask();
   }
 
@@ -285,6 +311,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   protected IConfigTask visitShowConfigNodes(
       final ShowConfigNodes showConfigNodesStatement, final MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new ShowConfigNodesTask();
   }
 
@@ -292,6 +319,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   protected IConfigTask visitShowAINodes(
       final ShowAINodes showAINodesStatement, final MPPQueryContext context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new ShowAINodesTask();
   }
 
@@ -299,6 +327,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   protected IConfigTask visitClearCache(
       final ClearCache clearCacheStatement, final MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new ClearCacheTask(clearCacheStatement);
   }
 
@@ -515,7 +544,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
     new Analyzer(
             context,
             context.getSession(),
-            new StatementAnalyzerFactory(metadata, null, new 
TableModelPlanner.NopAccessControl()),
+            new StatementAnalyzerFactory(metadata, null, accessControl),
             Collections.emptyList(),
             Collections.emptyMap(),
             WarningCollector.NOOP)
@@ -556,12 +585,14 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitFlush(Flush node, MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new FlushTask(((FlushStatement) node.getInnerTreeStatement()));
   }
 
   @Override
   protected IConfigTask visitSetConfiguration(SetConfiguration node, 
MPPQueryContext context) {
     context.setQueryType(QueryType.WRITE);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new SetConfigurationTask(((SetConfigurationStatement) 
node.getInnerTreeStatement()));
   }
 
@@ -697,12 +728,14 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
   @Override
   protected IConfigTask visitShowVariables(ShowVariables node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new ShowVariablesTask();
   }
 
   @Override
   protected IConfigTask visitShowClusterId(ShowClusterId node, MPPQueryContext 
context) {
     context.setQueryType(QueryType.READ);
+    
accessControl.checkUserHasMaintainPrivilege(context.getSession().getUserName());
     return new ShowClusterIdTask();
   }
 
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 bf7bc065d49..6bbb0a2238c 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
@@ -306,6 +306,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static 
org.apache.iotdb.commons.conf.IoTDBConstant.MAX_DATABASE_NAME_LENGTH;
@@ -3088,7 +3089,8 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
   }
 
   @Override
-  public SettableFuture<ConfigTaskResult> showDatabases(final ShowDB showDB) {
+  public SettableFuture<ConfigTaskResult> showDatabases(
+      final ShowDB showDB, final Function<String, Boolean> canSeenDB) {
     final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
     // Construct request using statement
     final List<String> databasePathPattern = Arrays.asList(ALL_RESULT_NODES);
@@ -3099,7 +3101,7 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
           new TGetDatabaseReq(databasePathPattern, 
ALL_MATCH_SCOPE.serialize());
       final TShowDatabaseResp resp = client.showDatabase(req);
       // build TSBlock
-      ShowDBTask.buildTSBlock(resp.getDatabaseInfoMap(), future, 
showDB.isDetails());
+      ShowDBTask.buildTSBlock(resp.getDatabaseInfoMap(), future, 
showDB.isDetails(), canSeenDB);
     } catch (final IOException | ClientManagerException | TException e) {
       future.setException(e);
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
index 1773ad94d7d..4180abd3b09 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
@@ -98,6 +98,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.Function;
 
 public interface IConfigTaskExecutor {
 
@@ -282,7 +283,8 @@ public interface IConfigTaskExecutor {
 
   // =============================== table syntax 
=========================================
 
-  SettableFuture<ConfigTaskResult> showDatabases(ShowDB showDB);
+  SettableFuture<ConfigTaskResult> showDatabases(
+      ShowDB showDB, Function<String, Boolean> canSeenDB);
 
   SettableFuture<ConfigTaskResult> showCluster(ShowCluster showCluster);
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
index d0516a14dac..976291dbdbc 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
@@ -40,36 +40,43 @@ import org.apache.tsfile.utils.Binary;
 
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 public class ShowDBTask implements IConfigTask {
 
   private final ShowDB node;
 
-  public ShowDBTask(final ShowDB node) {
+  // judge whether the specific database can be seen, dbName should be without 
`root.` prefix
+  private final Function<String, Boolean> canSeenDB;
+
+  public ShowDBTask(final ShowDB node, final Function<String, Boolean> 
canSeenDB) {
     this.node = node;
+    this.canSeenDB = canSeenDB;
   }
 
   @Override
   public ListenableFuture<ConfigTaskResult> execute(final IConfigTaskExecutor 
configTaskExecutor)
       throws InterruptedException {
-    return configTaskExecutor.showDatabases(node);
+    return configTaskExecutor.showDatabases(node, canSeenDB);
   }
 
   public static void buildTSBlock(
       final Map<String, TDatabaseInfo> storageGroupInfoMap,
       final SettableFuture<ConfigTaskResult> future,
-      final boolean isDetails) {
+      final boolean isDetails,
+      final Function<String, Boolean> canSeenDB) {
     if (isDetails) {
-      buildTSBlockForDetails(storageGroupInfoMap, future);
+      buildTSBlockForDetails(storageGroupInfoMap, future, canSeenDB);
     } else {
-      buildTSBlockForNonDetails(storageGroupInfoMap, future);
+      buildTSBlockForNonDetails(storageGroupInfoMap, future, canSeenDB);
     }
   }
 
   private static void buildTSBlockForNonDetails(
       final Map<String, TDatabaseInfo> storageGroupInfoMap,
-      final SettableFuture<ConfigTaskResult> future) {
+      final SettableFuture<ConfigTaskResult> future,
+      final Function<String, Boolean> canSeenDB) {
     final List<TSDataType> outputDataTypes =
         ColumnHeaderConstant.showDBColumnHeaders.stream()
             .map(ColumnHeader::getColumnType)
@@ -78,6 +85,9 @@ public class ShowDBTask implements IConfigTask {
     final TsBlockBuilder builder = new TsBlockBuilder(outputDataTypes);
     for (final Map.Entry<String, TDatabaseInfo> entry : 
storageGroupInfoMap.entrySet()) {
       final String dbName = entry.getKey().substring(5);
+      if (!canSeenDB.apply(dbName)) {
+        continue;
+      }
       final TDatabaseInfo storageGroupInfo = entry.getValue();
       builder.getTimeColumnBuilder().writeLong(0L);
       builder.getColumnBuilder(0).writeBinary(new Binary(dbName, 
TSFileConfig.STRING_CHARSET));
@@ -104,7 +114,8 @@ public class ShowDBTask implements IConfigTask {
 
   private static void buildTSBlockForDetails(
       final Map<String, TDatabaseInfo> storageGroupInfoMap,
-      final SettableFuture<ConfigTaskResult> future) {
+      final SettableFuture<ConfigTaskResult> future,
+      final Function<String, Boolean> canSeenDB) {
     final List<TSDataType> outputDataTypes =
         ColumnHeaderConstant.showDBDetailsColumnHeaders.stream()
             .map(ColumnHeader::getColumnType)
@@ -113,6 +124,9 @@ public class ShowDBTask implements IConfigTask {
     final TsBlockBuilder builder = new TsBlockBuilder(outputDataTypes);
     for (final Map.Entry<String, TDatabaseInfo> entry : 
storageGroupInfoMap.entrySet()) {
       final String dbName = entry.getKey().substring(5);
+      if (!canSeenDB.apply(dbName)) {
+        continue;
+      }
       final TDatabaseInfo storageGroupInfo = entry.getValue();
       builder.getTimeColumnBuilder().writeLong(0L);
       builder.getColumnBuilder(0).writeBinary(new Binary(dbName, 
TSFileConfig.STRING_CHARSET));
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analyzer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analyzer.java
index 75071daaa38..5ea7c492149 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analyzer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analyzer.java
@@ -96,17 +96,6 @@ public class Analyzer {
       context.setAnalyzeCost(analyzeCost);
     }
 
-    // TODO access control
-    // check column access permissions for each table
-    //    analysis.getTableColumnReferences().forEach((accessControlInfo, 
tableColumnReferences) ->
-    //        tableColumnReferences.forEach((tableName, columns) ->
-    //            
accessControlInfo.getAccessControl().checkCanSelectFromColumns(
-    //                
accessControlInfo.getSecurityContext(session.getRequiredTransactionId(),
-    // session.getQueryId(),
-    //                    session.getStart()),
-    //                tableName,
-    //                columns)));
-
     return analysis;
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
index 928354dee10..2090d58bdd4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
@@ -206,7 +206,7 @@ public class StatementAnalyzer {
 
   private final StatementAnalyzerFactory statementAnalyzerFactory;
 
-  private Analysis analysis;
+  private final Analysis analysis;
 
   private boolean hasFillInParentScope = false;
   private final MPPQueryContext queryContext;
@@ -1739,6 +1739,10 @@ public class StatementAnalyzer {
       }
 
       QualifiedObjectName name = createQualifiedObjectName(sessionContext, 
table.getName());
+
+      // access control
+      accessControl.checkCanSelectFromTable(sessionContext.getUserName(), 
name);
+
       analysis.setRelationName(
           table, QualifiedName.of(name.getDatabaseName(), 
name.getObjectName()));
 
@@ -1752,37 +1756,12 @@ public class StatementAnalyzer {
       ImmutableList.Builder<Field> fields = ImmutableList.builder();
       fields.addAll(analyzeTableOutputFields(table, name, tableSchema.get()));
 
-      //      boolean addRowIdColumn = updateKind.isPresent();
-      //
-      //      if (addRowIdColumn) {
-      //        // Add the row id field
-      //        ColumnHandle rowIdColumnHandle = 
metadata.getMergeRowIdColumnHandle(session,
-      // tableHandle.get());
-      //        Type type = metadata.getColumnMetadata(session, 
tableHandle.get(),
-      // rowIdColumnHandle).getType();
-      //        Field field = Field.newUnqualified(Optional.empty(), type);
-      //        fields.add(field);
-      //        analysis.setColumn(field, rowIdColumnHandle);
-      //      }
-
       List<Field> outputFields = fields.build();
 
       RelationType relationType = new RelationType(outputFields);
-      Scope accessControlScope =
-          Scope.builder().withRelationType(RelationId.anonymous(), 
relationType).build();
-      //      analyzeFiltersAndMasks(table, name, new 
RelationType(outputFields),
-      // accessControlScope);
       analysis.registerTable(table, tableSchema, name);
 
-      Scope tableScope = createAndAssignScope(table, scope, relationType);
-
-      //      if (addRowIdColumn) {
-      //        FieldReference reference = new 
FieldReference(outputFields.size() - 1);
-      //        analyzeExpression(reference, tableScope);
-      //        analysis.setRowIdField(table, reference);
-      //      }
-
-      return tableScope;
+      return createAndAssignScope(table, scope, relationType);
     }
 
     private Scope createScopeForCommonTableExpression(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableModelPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableModelPlanner.java
index b209096732f..c8e0c948bc0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableModelPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableModelPlanner.java
@@ -68,8 +68,7 @@ public class TableModelPlanner implements IPlanner {
   private final List<PlanOptimizer> distributionPlanOptimizers;
   private final SymbolAllocator symbolAllocator = new SymbolAllocator();
 
-  // TODO access control
-  private final AccessControl accessControl = new NopAccessControl();
+  private final AccessControl accessControl;
 
   private final WarningCollector warningCollector = WarningCollector.NOOP;
 
@@ -95,7 +94,8 @@ public class TableModelPlanner implements IPlanner {
       final IClientManager<TEndPoint, AsyncDataNodeInternalServiceClient>
           asyncInternalServiceClientManager,
       final List<PlanOptimizer> logicalPlanOptimizers,
-      final List<PlanOptimizer> distributionPlanOptimizers) {
+      final List<PlanOptimizer> distributionPlanOptimizers,
+      final AccessControl accessControl) {
     this.statement = statement;
     this.sqlParser = sqlParser;
     this.metadata = metadata;
@@ -106,6 +106,7 @@ public class TableModelPlanner implements IPlanner {
     this.asyncInternalServiceClientManager = asyncInternalServiceClientManager;
     this.logicalPlanOptimizers = logicalPlanOptimizers;
     this.distributionPlanOptimizers = distributionPlanOptimizers;
+    this.accessControl = accessControl;
   }
 
   @Override
@@ -227,6 +228,4 @@ public class TableModelPlanner implements IPlanner {
       }
     }
   }
-
-  public static class NopAccessControl implements AccessControl {}
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
index f61b67652d5..fe439a19a8c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
@@ -19,4 +19,115 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.security;
 
-public interface AccessControl {}
+import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
+
+public interface AccessControl {
+
+  /**
+   * Check if user is allowed to create the specified database.
+   *
+   * @param userName name of user
+   * @param databaseName without `root.` prefix, like db
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanCreateDatabase(String userName, String databaseName);
+
+  /**
+   * Check if user is allowed to drop the specified database.
+   *
+   * @param userName name of user
+   * @param databaseName without `root.` prefix, like db
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanDropDatabase(String userName, String databaseName);
+
+  /**
+   * Check if user is allowed to alter the specified database.
+   *
+   * @param userName name of user
+   * @param databaseName without `root.` prefix, like db
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanAlterDatabase(String userName, String databaseName);
+
+  /**
+   * Check if user is allowed to show or use the specified database.
+   *
+   * @param userName name of user
+   * @param databaseName without `root.` prefix, like db
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanShowOrUseDatabase(String userName, String databaseName);
+
+  /**
+   * Check if user is allowed to create the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanCreateTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user is allowed to create the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanDropTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user is allowed to alter the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanAlterTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user is allowed to insert into the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanInsertIntoTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user is allowed to select from the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanSelectFromTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user is allowed to delete from the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanDeleteFromTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user is allowed to show or describe the specified table.
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkCanShowOrDescTable(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user has global maintain privilege
+   *
+   * @param userName name of user
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkUserHasMaintainPrivilege(String userName);
+}
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
new file mode 100644
index 00000000000..e7426896699
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.relational.security;
+
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
+
+public class AccessControlImpl implements AccessControl {
+
+  private final ITableAuthChecker authChecker;
+
+  public AccessControlImpl(ITableAuthChecker authChecker) {
+    this.authChecker = authChecker;
+  }
+
+  @Override
+  public void checkCanCreateDatabase(String userName, String databaseName) {
+    authChecker.checkDatabasePrivilege(userName, databaseName, 
TableModelPrivilege.CREATE);
+  }
+
+  @Override
+  public void checkCanDropDatabase(String userName, String databaseName) {
+    authChecker.checkDatabasePrivilege(userName, databaseName, 
TableModelPrivilege.DROP);
+  }
+
+  @Override
+  public void checkCanAlterDatabase(String userName, String databaseName) {
+    authChecker.checkDatabasePrivilege(userName, databaseName, 
TableModelPrivilege.ALTER);
+  }
+
+  @Override
+  public void checkCanShowOrUseDatabase(String userName, String databaseName) {
+    authChecker.checkDatabaseVisibility(userName, databaseName);
+  }
+
+  @Override
+  public void checkCanCreateTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.CREATE);
+  }
+
+  @Override
+  public void checkCanDropTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.DROP);
+  }
+
+  @Override
+  public void checkCanAlterTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.ALTER);
+  }
+
+  @Override
+  public void checkCanInsertIntoTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.INSERT);
+  }
+
+  @Override
+  public void checkCanSelectFromTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.SELECT);
+  }
+
+  @Override
+  public void checkCanDeleteFromTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTablePrivilege(userName, tableName, 
TableModelPrivilege.DELETE);
+  }
+
+  @Override
+  public void checkCanShowOrDescTable(String userName, QualifiedObjectName 
tableName) {
+    authChecker.checkTableVisibility(userName, tableName);
+  }
+
+  @Override
+  public void checkUserHasMaintainPrivilege(String userName) {
+    authChecker.checkMaintainPrivilege(userName);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
index a6368023e18..99cb78b7a92 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
@@ -19,4 +19,66 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.security;
 
-public class AllowAllAccessControl implements AccessControl {}
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
+
+public class AllowAllAccessControl implements AccessControl {
+  @Override
+  public void checkCanCreateDatabase(String userName, String databaseName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanDropDatabase(String userName, String databaseName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanAlterDatabase(String userName, String databaseName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanShowOrUseDatabase(String userName, String databaseName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanCreateTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanDropTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanAlterTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanInsertIntoTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanSelectFromTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanDeleteFromTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkCanShowOrDescTable(String userName, QualifiedObjectName 
tableName) {
+    // allow anything
+  }
+
+  @Override
+  public void checkUserHasMaintainPrivilege(String userName) {
+    // allow anything
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
new file mode 100644
index 00000000000..e234827bdd5
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.relational.security;
+
+import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
+
+public interface ITableAuthChecker {
+
+  /**
+   * Check if user has any privilege on ANY, @param{databaseName} or any tables
+   * in @param{databaseName}
+   *
+   * @param userName name of user
+   * @param databaseName without `root.` prefix, like db
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkDatabaseVisibility(String userName, String databaseName);
+
+  /**
+   * Check if user has specified privilege on the specified database or bigger 
scope (like ANY).
+   *
+   * @param userName name of user
+   * @param databaseName without `root.` prefix, like db
+   * @param privilege specified privilege to be checked
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkDatabasePrivilege(String userName, String databaseName, 
TableModelPrivilege privilege);
+
+  /**
+   * Check if user has specified privilege on the specified table or bigger 
scope (like database or
+   * ANY).
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @param privilege specified privilege to be checked
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkTablePrivilege(
+      String userName, QualifiedObjectName tableName, TableModelPrivilege 
privilege);
+
+  /**
+   * Check if user has any privilege on the specified table or bigger scope 
(like database or ANY).
+   *
+   * @param userName name of user
+   * @param tableName qualified name of table without `root.` prefix, like 
db.table1
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkTableVisibility(String userName, QualifiedObjectName tableName);
+
+  /**
+   * Check if user has global maintain privilege
+   *
+   * @param userName name of user
+   * @throws AccessDeniedException if not allowed
+   */
+  void checkMaintainPrivilege(String userName);
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java
similarity index 83%
copy from 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
copy to 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java
index f61b67652d5..1c9991aa234 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java
@@ -19,4 +19,17 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.security;
 
-public interface AccessControl {}
+public enum TableModelPrivilege {
+  // global privilege
+  MANAGE_USER,
+  MANAGE_ROLE,
+  MAINTAIN,
+
+  // scope privilege
+  CREATE,
+  DROP,
+  ALTER,
+  SELECT,
+  INSERT,
+  DELETE,
+}
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index b8e1ad9ae46..2463e552c9b 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -63,6 +63,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.security.AllowAllAccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement;
@@ -112,7 +113,7 @@ import static org.mockito.ArgumentMatchers.eq;
 
 public class AnalyzerTest {
 
-  private static final NopAccessControl nopAccessControl = new 
NopAccessControl();
+  private static final AccessControl nopAccessControl = new 
AllowAllAccessControl();
 
   QueryId queryId = new QueryId("test_query");
   SessionInfo sessionInfo =
@@ -1264,6 +1265,4 @@ public class AnalyzerTest {
             NOOP);
     return analyzer.analyze(statement);
   }
-
-  private static class NopAccessControl implements AccessControl {}
 }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
index 5db55304a1f..199942012d2 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
@@ -37,7 +37,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.execution.querystats.Plan
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.distribute.TableDistributedPlanner;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.PlanOptimizer;
-import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.security.AllowAllAccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
 
@@ -149,7 +149,7 @@ public class PlanTester {
       SessionInfo session) {
     try {
       StatementAnalyzerFactory statementAnalyzerFactory =
-          new StatementAnalyzerFactory(metadata, sqlParser, new 
NopAccessControl());
+          new StatementAnalyzerFactory(metadata, sqlParser, new 
AllowAllAccessControl());
 
       Analyzer analyzer =
           new Analyzer(
@@ -175,6 +175,4 @@ public class PlanTester {
     }
     return 
distributedQueryPlan.getFragments().get(index).getPlanNodeTree().getChildren().get(0);
   }
-
-  private static class NopAccessControl implements AccessControl {}
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/auth/AccessDeniedException.java
similarity index 66%
copy from 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
copy to 
iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/auth/AccessDeniedException.java
index f61b67652d5..9aca837f825 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/auth/AccessDeniedException.java
@@ -17,6 +17,16 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.queryengine.plan.relational.security;
+package org.apache.iotdb.commons.exception.auth;
 
-public interface AccessControl {}
+import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class AccessDeniedException extends IoTDBRuntimeException {
+
+  public static final String PREFIX = "Access Denied: ";
+
+  public AccessDeniedException(String message) {
+    super(PREFIX + message, TSStatusCode.NO_PERMISSION.getStatusCode());
+  }
+}


Reply via email to