This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 2b4ab69dff6 Add AccessControl support for query and database related
2b4ab69dff6 is described below
commit 2b4ab69dff635b17a0a4268eb4b822326d4539f6
Author: Jackie Tien <[email protected]>
AuthorDate: Tue Dec 3 19:37:38 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 eefed656e01..fa2f15fc74b 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;
@@ -140,6 +142,7 @@ public class Coordinator {
private final List<PlanOptimizer> logicalPlanOptimizers;
private final List<PlanOptimizer> distributionPlanOptimizers;
+ private final AccessControl accessControl;
private Coordinator() {
this.queryExecutionMap = new ConcurrentHashMap<>();
@@ -156,6 +159,7 @@ public class Coordinator {
new PlannerContext(
LocalExecutionPlanner.getInstance().metadata, new
InternalTypeManager()))
.getPlanOptimizers();
+ this.accessControl = new AllowAllAccessControl();
}
private ExecutionResult execution(
@@ -334,7 +338,8 @@ public class Coordinator {
SYNC_INTERNAL_SERVICE_CLIENT_MANAGER,
ASYNC_INTERNAL_SERVICE_CLIENT_MANAGER,
logicalPlanOptimizers,
- distributionPlanOptimizers);
+ distributionPlanOptimizers,
+ accessControl);
return new QueryExecution(tableModelPlanner, queryContext, executor);
}
@@ -382,7 +387,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);
@@ -398,7 +404,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 9173cd74187..86e8c691dd1 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
@@ -78,7 +78,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;
@@ -141,6 +141,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;
@@ -171,9 +172,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
@@ -192,6 +199,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()) {
@@ -243,25 +252,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();
@@ -273,6 +297,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();
@@ -286,6 +311,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();
}
@@ -293,6 +319,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();
}
@@ -300,6 +327,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();
}
@@ -307,6 +335,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);
}
@@ -523,7 +552,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)
@@ -564,12 +593,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()));
}
@@ -759,12 +790,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 7e04626ef7c..bf841a0c3ae 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 ade7aacbb1e..fdf9c032742 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
@@ -210,7 +210,7 @@ public class StatementAnalyzer {
private final StatementAnalyzerFactory statementAnalyzerFactory;
- private Analysis analysis;
+ private final Analysis analysis;
private boolean hasFillInParentScope = false;
private final MPPQueryContext queryContext;
@@ -1743,6 +1743,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()));
@@ -1756,37 +1760,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());
+ }
+}