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 {