diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java index 74769b5efc2a..645ff1acae67 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java @@ -19,6 +19,8 @@ package org.apache.iotdb.db.it.auth; +import org.apache.iotdb.commons.auth.entity.PrivilegeType; +import org.apache.iotdb.db.it.utils.TestUtils; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.TableClusterIT; @@ -34,14 +36,12 @@ import java.sql.Connection; import java.sql.ResultSet; -import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; @RunWith(IoTDBTestRunner.class) @Category({TableLocalStandaloneIT.class, TableClusterIT.class}) @@ -56,30 +56,6 @@ public void tearDown() throws Exception { EnvFactory.getEnv().cleanClusterEnvironment(); } - private void validateResultSet(ResultSet set, String ans) throws SQLException { - try { - StringBuilder builder = new StringBuilder(); - ResultSetMetaData metaData = set.getMetaData(); - int colNum = metaData.getColumnCount(); - while (set.next()) { - for (int i = 1; i <= colNum; i++) { - builder.append(set.getString(i)).append(","); - } - builder.append("\n"); - } - String result = builder.toString(); - assertEquals(ans.length(), result.length()); - List ansLines = Arrays.asList(ans.split("\n")); - List resultLines = Arrays.asList(result.split("\n")); - assertEquals(ansLines.size(), resultLines.size()); - for (String resultLine : resultLines) { - assertTrue(ansLines.contains(resultLine)); - } - } finally { - set.close(); - } - } - @Test public void listUserPrivileges() throws SQLException { try (Connection adminCon = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); @@ -117,17 +93,19 @@ public void listUserPrivileges() throws SQLException { adminStmt.execute("GRANT DROP ON testdb.tb to user testuser with grant option"); ResultSet rs = adminStmt.executeQuery("LIST PRIVILEGES OF USER testuser"); - String ans = - ",,MANAGE_USER,false,\n" - + ",,MANAGE_ROLE,false,\n" - + ",*.*,SELECT,false,\n" - + ",*.*,INSERT,false,\n" - + ",*.*,DELETE,false,\n" - + ",testdb.*,SELECT,true,\n" - + ",testdb.tb,SELECT,false,\n" - + ",testdb.tb,INSERT,true,\n" - + ",testdb.tb,DROP,true,\n"; - validateResultSet(rs, ans); + Set ans = + new HashSet<>( + Arrays.asList( + ",,MANAGE_USER,false,", + ",,MANAGE_ROLE,false,", + ",*.*,SELECT,false,", + ",*.*,INSERT,false,", + ",*.*,DELETE,false,", + ",testdb.*,SELECT,true,", + ",testdb.tb,SELECT,false,", + ",testdb.tb,INSERT,true,", + ",testdb.tb,DROP,true,")); + TestUtils.assertResultSetEqual(rs, "Role,Scope,Privileges,GrantOption,", ans); } } @@ -230,21 +208,23 @@ public void checkAuthorStatementPrivilegeCheck() throws SQLException { // can list itself privileges and the all roles privileges ResultSet rs = userStmt.executeQuery("List privileges of user testuser"); - String ans = - ",,MANAGE_ROLE,false,\n" - + ",*.*,ALTER,false,\n" - + ",testdb.*,INSERT,false,\n" - + ",testdb.tb,SELECT,false,\n" - + ",testdb.tb,INSERT,false,\n" - + "testrole2,,MAINTAIN,false,\n" - + "testrole,,MAINTAIN,true,\n"; - validateResultSet(rs, ans); + Set ans = + new HashSet<>( + Arrays.asList( + ",,MANAGE_ROLE,false,", + ",*.*,ALTER,false,", + ",testdb.*,INSERT,false,", + ",testdb.tb,SELECT,false,", + ",testdb.tb,INSERT,false,", + "testrole2,,MAINTAIN,false,", + "testrole,,MAINTAIN,true,")); + TestUtils.assertResultSetEqual(rs, "Role,Scope,Privileges,GrantOption,", ans); rs = userStmt.executeQuery("List privileges of role testrole"); - ans = "testrole,,MAINTAIN,true,\n"; - validateResultSet(rs, ans); + ans = new HashSet<>(Collections.singletonList("testrole,,MAINTAIN,true,")); + TestUtils.assertResultSetEqual(rs, "Role,Scope,Privileges,GrantOption,", ans); rs = userStmt.executeQuery("List privileges of role testrole2"); - ans = "testrole2,,MAINTAIN,false,\n"; - validateResultSet(rs, ans); + ans = new HashSet<>(Collections.singletonList("testrole2,,MAINTAIN,false,")); + TestUtils.assertResultSetEqual(rs, "Role,Scope,Privileges,GrantOption,", ans); // testdb.TB's privilege is not grant option. Assert.assertThrows( SQLException.class, @@ -289,8 +269,9 @@ public void checkAuthorStatementPrivilegeCheck() throws SQLException { userStmt.execute("GRANT drop on database testdb to user testuser3"); userStmt.execute("GRANT SELECT ON database testdb to user testuser3"); ResultSet rs = userStmt.executeQuery("List privileges of user testuser3"); - String ans = ",testdb.*,SELECT,false,\n" + ",testdb.*,DROP,false,\n"; - validateResultSet(rs, ans); + Set ans = + new HashSet<>(Arrays.asList(",testdb.*,SELECT,false,", ",testdb.*,DROP,false,")); + TestUtils.assertResultSetEqual(rs, "Role,Scope,Privileges,GrantOption,", ans); userStmt.execute("REVOKE SELECT ON DATABASE testdb from user testuser3"); Assert.assertThrows( SQLException.class, @@ -299,8 +280,71 @@ public void checkAuthorStatementPrivilegeCheck() throws SQLException { }); rs = userStmt.executeQuery("List privileges of user testuser3"); - ans = ",testdb.*,DROP,false,\n"; - validateResultSet(rs, ans); + TestUtils.assertResultSetEqual( + rs, "Role,Scope,Privileges,GrantOption,", Collections.singleton(",testdb.*,DROP,false,")); + } + } + + @Test + public void checkGrantRevokeAllPrivileges() throws SQLException { + try (Connection adminCon = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + Statement adminStmt = adminCon.createStatement()) { + adminStmt.execute("create user test 'password'"); + adminStmt.execute("grant all to user test"); + adminStmt.execute("revoke SELECT ON ANY from user test"); + adminStmt.execute("create role role1"); + adminStmt.execute("grant all to role role1 with grant option"); + } + + Set listUserPrivilegeResult = new HashSet<>(); + for (PrivilegeType privilegeType : PrivilegeType.values()) { + if (privilegeType == PrivilegeType.SELECT) { + continue; + } + if (privilegeType.isRelationalPrivilege()) { + listUserPrivilegeResult.add(",*.*," + privilegeType + ",false,"); + } + if (privilegeType.forRelationalSys()) { + listUserPrivilegeResult.add(",," + privilegeType + ",false,"); + } + } + + Set listRolePrivilegeResult = new HashSet<>(); + for (PrivilegeType privilegeType : PrivilegeType.values()) { + if (privilegeType.isRelationalPrivilege()) { + listRolePrivilegeResult.add("role1,*.*," + privilegeType + ",true,"); + } + if (privilegeType.forRelationalSys()) { + listRolePrivilegeResult.add("role1,," + privilegeType + ",true,"); + } + } + + try (Connection userCon = + EnvFactory.getEnv().getConnection("test", "password", BaseEnv.TABLE_SQL_DIALECT); + Statement userConStatement = userCon.createStatement()) { + ResultSet resultSet = userConStatement.executeQuery("List privileges of user test"); + TestUtils.assertResultSetEqual( + resultSet, "Role,Scope,Privileges,GrantOption,", listUserPrivilegeResult); + + // Have manage_role privilege + resultSet = userConStatement.executeQuery("List privileges of role role1"); + TestUtils.assertResultSetEqual( + resultSet, "Role,Scope,Privileges,GrantOption,", listRolePrivilegeResult); + + // Do not have grant option + Assert.assertThrows( + SQLException.class, + () -> { + userConStatement.execute("GRANT SELECT ON DATABASE TEST to role role1"); + }); + } + + try (Connection adminCon = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + Statement adminStmt = adminCon.createStatement()) { + adminStmt.execute("REVOKE ALL FROM USER test"); + ResultSet resultSet = adminStmt.executeQuery("List privileges of user test"); + TestUtils.assertResultSetEqual( + resultSet, "Role,Scope,Privileges,GrantOption,", Collections.emptySet()); } } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java index 983c4a3f1a1f..603f8639bcd9 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java @@ -480,6 +480,8 @@ public TSStatus executeNonQueryPlan(ConfigPhysicalPlan physicalPlan) case RGrantUserRole: case RGrantRoleAny: case RGrantUserAny: + case RGrantUserAll: + case RGrantRoleAll: case RGrantUserDBPriv: case RGrantUserSysPri: case RGrantUserTBPriv: @@ -488,6 +490,8 @@ public TSStatus executeNonQueryPlan(ConfigPhysicalPlan physicalPlan) case RGrantRoleTBPriv: case RRevokeRoleAny: case RRevokeUserAny: + case RRevokeUserAll: + case RRevokeRoleAll: case RRevokeUserDBPriv: case RRevokeUserSysPri: case RRevokeUserTBPriv: diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/AuthorInfoTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/AuthorInfoTest.java index 2971e49f7f0d..8766109ac8c3 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/AuthorInfoTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/AuthorInfoTest.java @@ -256,11 +256,11 @@ public void permissionTest() throws AuthException, IllegalPathException { status = authorInfo.authorNonQuery(authorPlan); assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), status.getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user0", new PrivilegeUnion(nodeNameList, PrivilegeType.READ_DATA)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); // grant user system privilege authorPlan = @@ -269,11 +269,11 @@ public void permissionTest() throws AuthException, IllegalPathException { status = authorInfo.authorNonQuery(authorPlan); assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), status.getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user0", new PrivilegeUnion(PrivilegeType.MANAGE_ROLE)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); // check user privileges status = authorInfo @@ -868,94 +868,94 @@ public void relationalPermissionTest() throws AuthException { // TB: database.table ALTER assertEquals( - authorInfo.checkRoleOfUser("user", "role").getStatus().getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + TSStatusCode.SUCCESS_STATUS.getStatusCode(), + authorInfo.checkRoleOfUser("user", "role").getStatus().getCode()); assertEquals( - authorInfo.checkRoleOfUser("user", "role2").getStatus().getCode(), - TSStatusCode.USER_NOT_HAS_ROLE.getStatusCode()); + TSStatusCode.USER_NOT_HAS_ROLE.getStatusCode(), + authorInfo.checkRoleOfUser("user", "role2").getStatus().getCode()); // check visible assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion("testdb", null)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion("database", null)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion("database", "table", null)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion("database", "table2", null)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion("database2", "table2", null)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion("testdb", PrivilegeType.SELECT)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorInfo .checkUserPrivileges( "user", new PrivilegeUnion("testdb", "testtb", PrivilegeType.INSERT)) .getStatus() - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges( "user", new PrivilegeUnion("testdb", "table", PrivilegeType.CREATE)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges("user", new PrivilegeUnion(PrivilegeType.MANAGE_ROLE)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges( "user", new PrivilegeUnion("database", "table", PrivilegeType.ALTER)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorInfo .checkUserPrivileges( "user", new PrivilegeUnion("testdb", "table2", PrivilegeType.DELETE, true)) .getStatus() - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorInfo .checkUserPrivileges( "user", new PrivilegeUnion("database", "table", PrivilegeType.ALTER, true)) .getStatus() - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); + .getCode()); } } 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 e0fecd3b6ef0..fb225f3c487a 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 @@ -663,7 +663,7 @@ private TAuthorizerRelationalReq statementToAuthorizerReq( authorStatement.getPassword() == null ? "" : authorStatement.getPassword(), authorStatement.getDatabase() == null ? "" : authorStatement.getDatabase(), authorStatement.getTableName() == null ? "" : authorStatement.getTableName(), - authorStatement.getPrivilegeType() == null + authorStatement.getPrivilegeTypes() == null ? Collections.emptySet() : authorStatement.getPrivilegeIds(), authorStatement.isGrantOption()); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java index ccb75ebb22f9..a798a1879c15 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.queryengine.execution.operator.source.relational; import org.apache.iotdb.commons.conf.IoTDBConstant; +import org.apache.iotdb.commons.exception.IoTDBException; import org.apache.iotdb.commons.schema.table.InformationSchema; import org.apache.iotdb.commons.schema.table.TableNodeStatus; import org.apache.iotdb.commons.schema.table.TsTable; @@ -48,7 +49,6 @@ import org.apache.tsfile.utils.BytesUtils; import org.apache.tsfile.utils.Pair; -import java.security.AccessControlException; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; @@ -341,8 +341,11 @@ public boolean hasNext() { private static boolean canShowDB(final String userName, final String dbName) { try { Coordinator.getInstance().getAccessControl().checkCanShowOrUseDatabase(userName, dbName); - } catch (final AccessControlException e) { - return false; + } catch (final RuntimeException e) { + if (e.getCause() instanceof IoTDBException) { + return false; + } + throw e; } return true; } 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 1e9f6d0c44d5..e3bb6bfc0acb 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 @@ -21,6 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.Model; import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.commons.exception.IoTDBException; import org.apache.iotdb.commons.executable.ExecutableManager; import org.apache.iotdb.commons.pipe.config.constant.SystemConstant; import org.apache.iotdb.commons.schema.table.TsTable; @@ -165,7 +166,6 @@ 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; @@ -319,8 +319,11 @@ protected IConfigTask visitShowDB(final ShowDB node, final MPPQueryContext conte accessControl.checkCanShowOrUseDatabase( context.getSession().getUserName(), databaseName); return true; - } catch (final AccessControlException e) { - return false; + } catch (final RuntimeException e) { + if (e.getCause() instanceof IoTDBException) { + return false; + } + throw e; } }); } 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 e9497b6e3a35..9fd0948ccc4f 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 @@ -216,7 +216,7 @@ public void checkUserCanRunRelationalAuthorStatement( if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - for (PrivilegeType privilegeType : statement.getPrivilegeType()) { + for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { authChecker.checkAnyScopePrivilegeGrantOption( userName, TableModelPrivilege.getTableModelType(privilegeType)); } @@ -234,7 +234,7 @@ public void checkUserCanRunRelationalAuthorStatement( if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - for (PrivilegeType privilegeType : statement.getPrivilegeType()) { + for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { if (privilegeType.isRelationalPrivilege()) { AuthorityChecker.checkAnyScopePermissionGrantOption(userName, privilegeType); } @@ -256,7 +256,7 @@ public void checkUserCanRunRelationalAuthorStatement( if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - for (PrivilegeType privilegeType : statement.getPrivilegeType()) { + for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { authChecker.checkDatabasePrivilegeGrantOption( userName, statement.getDatabase(), @@ -276,7 +276,7 @@ public void checkUserCanRunRelationalAuthorStatement( if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - for (PrivilegeType privilegeType : statement.getPrivilegeType()) { + for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { authChecker.checkTablePrivilegeGrantOption( userName, new QualifiedObjectName(statement.getDatabase(), statement.getTableName()), @@ -297,7 +297,7 @@ public void checkUserCanRunRelationalAuthorStatement( if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - for (PrivilegeType privilegeType : statement.getPrivilegeType()) { + for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { authChecker.checkGlobalPrivilegeGrantOption( userName, TableModelPrivilege.getTableModelType(privilegeType)); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java index 2e6565c76d4a..71c1962f2eaa 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; public class RelationalAuthorStatement extends Statement { @@ -123,10 +124,14 @@ public boolean isGrantOption() { return grantOption; } - public Set getPrivilegeType() { + public Set getPrivilegeTypes() { return privilegeType; } + public String getPrivilegesString() { + return privilegeType.stream().map(Enum::name).collect(Collectors.joining(",")); + } + public Set getPrivilegeIds() { Set privilegeIds = new HashSet<>(); for (PrivilegeType privilegeType : privilegeType) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/SqlFormatter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/SqlFormatter.java index 3114a220424b..7eb19c5b7da5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/SqlFormatter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/SqlFormatter.java @@ -1174,58 +1174,219 @@ protected Void visitShowTopics(ShowTopics node, Integer context) { protected Void visitRelationalAuthorPlan(RelationalAuthorStatement node, Integer context) { switch (node.getAuthorType()) { case GRANT_USER_ANY: + builder.append( + "GRANT " + + node.getPrivilegesString() + + " ON ANY" + + " TO USER " + + node.getUserName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; + case GRANT_USER_ALL: + builder.append( + "GRANT ALL TO USER " + + node.getUserName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; case GRANT_USER_DB: + builder.append( + "GRANT " + + node.getPrivilegesString() + + " ON DATABASE " + + node.getDatabase() + + " TO USER " + + node.getUserName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; case GRANT_USER_SYS: + builder.append( + "GRANT " + + node.getPrivilegesString() + + " TO USER " + + node.getUserName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; case GRANT_USER_TB: - builder.append("GRANT USER PRIVILEGES"); + builder.append( + "GRANT " + + node.getPrivilegesString() + + " ON TABLE " + + node.getDatabase() + + "." + + node.getTableName() + + " TO USER " + + node.getUserName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); break; case GRANT_ROLE_ANY: + builder.append( + "GRANT " + + node.getPrivilegesString() + + " ON ANY" + + " TO ROLE " + + node.getRoleName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; + case GRANT_ROLE_ALL: + builder.append( + "GRANT ALL TO ROLE " + + node.getRoleName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; case GRANT_ROLE_DB: + builder.append( + "GRANT " + + node.getPrivilegesString() + + " ON DATABASE " + + node.getDatabase() + + " TO ROLE " + + node.getRoleName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; case GRANT_ROLE_SYS: + builder.append( + "GRANT " + + node.getPrivilegesString() + + " TO ROLE " + + node.getRoleName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; case GRANT_ROLE_TB: - builder.append("GRANT ROLE PRIVILEGES"); + builder.append( + "GRANT " + + node.getPrivilegesString() + + " ON TABLE " + + node.getDatabase() + + "." + + node.getTableName() + + " TO ROLE " + + node.getRoleName() + + (node.isGrantOption() ? " WITH GRANT OPTION" : "")); + break; + case REVOKE_USER_ANY: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " ON ANY FROM USER " + + node.getUserName()); + break; + case REVOKE_USER_ALL: + builder.append( + "REVOKE" + + (node.isGrantOption() ? "GRANT OPTION FOR ALL" : "ALL") + + " FROM USER " + + node.getUserName()); + break; + case REVOKE_USER_DB: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " ON DATABASE " + + node.getDatabase() + + " FROM USER " + + node.getUserName()); + break; + case REVOKE_USER_SYS: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + "FROM USER " + + node.getUserName()); + break; + case REVOKE_USER_TB: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " ON TABLE " + + node.getDatabase() + + "." + + node.getTableName() + + " FROM USER " + + node.getUserName()); break; case REVOKE_ROLE_ANY: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " ON ANY FROM ROLE " + + node.getRoleName()); + break; + case REVOKE_ROLE_ALL: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR ALL" : "ALL") + + " FROM ROLE " + + node.getRoleName()); + break; case REVOKE_ROLE_DB: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " ON DATABASE " + + node.getDatabase() + + " FROM ROLE " + + node.getRoleName()); + break; case REVOKE_ROLE_SYS: + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " FROM ROLE " + + node.getRoleName()); + break; case REVOKE_ROLE_TB: - builder.append("REVOKE ROLE PRIVILEGES"); + builder.append( + "REVOKE " + + (node.isGrantOption() ? "GRANT OPTION FOR " : "") + + node.getPrivilegesString() + + " ON TABLE " + + node.getDatabase() + + "." + + node.getTableName() + + " FROM ROLE " + + node.getRoleName()); break; - case REVOKE_USER_ANY: - case REVOKE_USER_DB: - case REVOKE_USER_SYS: - case REVOKE_USER_TB: - builder.append("REVOKE USER PRIVILEGES"); + case GRANT_USER_ROLE: + builder.append("GRANT ROLE " + node.getRoleName() + " TO " + node.getUserName()); break; case REVOKE_USER_ROLE: - builder.append("REVOKE USER ROLE"); - break; - case UPDATE_USER: - builder.append("UPDATE USER"); + builder.append("REVOKE ROLE " + node.getRoleName() + " FROM " + node.getUserName()); break; case CREATE_USER: - builder.append("CREATE USER"); + builder.append("CREATE USER " + node.getUserName()); break; - case GRANT_USER_ROLE: - builder.append("GRANT USER ROLE"); + case CREATE_ROLE: + builder.append("CREATE ROLE " + node.getRoleName()); break; - case LIST_ROLE: - builder.append("LIST ROLE"); + case UPDATE_USER: + builder.append("ALTER USER " + node.getUserName() + " SET PASSWORD"); break; case LIST_USER: - builder.append("LIST USER"); + builder.append("LIST USER "); break; - case LIST_ROLE_PRIV: - builder.append("LIST ROLE PRIVILEGES"); + case LIST_ROLE: + builder.append("LIST ROLE "); break; case LIST_USER_PRIV: - builder.append("LIST USER PRIVILEGES"); + builder.append("LIST PRIVILEGES OF USER " + node.getUserName()); + break; + case LIST_ROLE_PRIV: + builder.append("LIST PRIVILEGES OF ROLE " + node.getRoleName()); break; case DROP_ROLE: - builder.append("DROP ROLE"); + builder.append("DROP ROLE " + node.getRoleName()); break; case DROP_USER: - builder.append("DROP USER"); + builder.append("DROP USER " + node.getUserName()); + break; + default: break; } return null; diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java index 8ea9da39db9a..73cba529a66e 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorizerManagerTest.java @@ -140,12 +140,12 @@ public void grantOptTest() throws IllegalPathException { // 3. READ_DATA root.d1.** // 4. WRITE_SCHEMA root.d1.** with grant option // 5. SELECT on database, ALTER on database with grant option - // 6. UPDATE on database.table, DELETE on database.table with grant option + // 6. DELETE on database.table with grant option // role's priv: // 1. USE_UDF // 2. USE_CQ with grant option - // 3. READ_DATA root.t9.** with grant option + // 3. READ_DATA root.t.** with grant option user.addRole("role1"); authorityFetcher.getAuthorCache().putUserCache("user1", user); @@ -153,88 +153,88 @@ public void grantOptTest() throws IllegalPathException { // for system priv. we have USE_PIPE grant option. Assert.assertEquals( - authorityFetcher.checkUserSysPrivilegesGrantOpt("user1", PrivilegeType.USE_PIPE).getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + TSStatusCode.SUCCESS_STATUS.getStatusCode(), + authorityFetcher.checkUserSysPrivilegesGrantOpt("user1", PrivilegeType.USE_PIPE).getCode()); Assert.assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorityFetcher .checkUserSysPrivilegesGrantOpt("user1", PrivilegeType.MANAGE_USER) - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); + .getCode()); // for path priv. we have write_schema on root.d1.** with grant option. // require root.d1.** with write_schema, return true Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorityFetcher .checkUserPathPrivilegesGrantOpt( "user1", Collections.singletonList(new PartialPath("root.d1.**")), PrivilegeType.WRITE_SCHEMA) - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); // require root.** with write_schema, return false Assert.assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorityFetcher .checkUserPathPrivilegesGrantOpt( "user1", Collections.singletonList(new PartialPath("root.**")), PrivilegeType.WRITE_SCHEMA) - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); - // reuqire root.d1.d2 with write_schema, return true + .getCode()); + // require root.d1.d2 with write_schema, return true Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorityFetcher .checkUserPathPrivilegesGrantOpt( "user1", - Collections.singletonList(new PartialPath("root.d1.d1.**")), + Collections.singletonList(new PartialPath("root.d1.d2")), PrivilegeType.WRITE_SCHEMA) - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); // require root.d1.d2 with read_schema, return false Assert.assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorityFetcher .checkUserPathPrivilegesGrantOpt( "user1", Collections.singletonList(new PartialPath("root.d1.d2")), PrivilegeType.READ_SCHEMA) - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); + .getCode()); Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorityFetcher .checkUserDBPrivilegesGrantOpt("user1", "database", PrivilegeType.ALTER) - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); Assert.assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorityFetcher .checkUserTBPrivilegesGrantOpt("user1", "database", "table", PrivilegeType.SELECT) - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); + .getCode()); // role test Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorityFetcher .checkUserPathPrivilegesGrantOpt( "user1", Collections.singletonList(new PartialPath("root.t.**")), PrivilegeType.READ_DATA) - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), authorityFetcher .checkUserPathPrivilegesGrantOpt( "user1", Collections.singletonList(new PartialPath("root.t.t1")), PrivilegeType.READ_DATA) - .getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + .getCode()); Assert.assertEquals( + TSStatusCode.NO_PERMISSION.getStatusCode(), authorityFetcher .checkUserSysPrivilegesGrantOpt("user1", PrivilegeType.USE_TRIGGER) - .getCode(), - TSStatusCode.NO_PERMISSION.getStatusCode()); + .getCode()); Assert.assertEquals( - authorityFetcher.checkUserSysPrivilegesGrantOpt("user1", PrivilegeType.USE_CQ).getCode(), - TSStatusCode.SUCCESS_STATUS.getStatusCode()); + TSStatusCode.SUCCESS_STATUS.getStatusCode(), + authorityFetcher.checkUserSysPrivilegesGrantOpt("user1", PrivilegeType.USE_CQ).getCode()); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java index a3bfa09cc414..4e2b75bfca86 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java @@ -40,6 +40,9 @@ import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class LocalFileUserAccessorTest { @@ -79,6 +82,23 @@ public void test() throws IOException, IllegalPathException { accessor.reset(); User loadUser = accessor.loadEntry("test"); assertEquals(user, loadUser); + user.setName("test1"); + accessor.saveEntry(user); + + // list + List usernames = accessor.listAllEntries(); + usernames.sort(null); + assertTrue(usernames.contains("test")); + assertTrue(usernames.contains("test1")); + + // delete + assertFalse(accessor.deleteEntry("not a user")); + assertTrue(accessor.deleteEntry(user.getName())); + usernames = accessor.listAllEntries(); + assertEquals(1, usernames.size()); + assertTrue(usernames.contains("test")); + User nullUser = accessor.loadEntry(user.getName()); + assertNull(nullUser); } @Test diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AuthorStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AuthorStatementTest.java index e2ddd1487f02..e9bd9e393e51 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AuthorStatementTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AuthorStatementTest.java @@ -60,7 +60,7 @@ private RelationalAuthorStatement createAuthorStatement(String sql) { private void checkUserManagerFiled(RelationalAuthorStatement authorStatement) { assertNull(authorStatement.getDatabase()); assertNull(authorStatement.getTableName()); - assertNull(authorStatement.getPrivilegeType()); + assertNull(authorStatement.getPrivilegeTypes()); assertFalse(authorStatement.isGrantOption()); } @@ -127,7 +127,7 @@ private void checkRevokePrivileges( RelationalAuthorStatement stmt = createAuthorStatement(sql); PrivilegeModelType modelType = PrivilegeModelType.INVALID; int ind = 0; - for (PrivilegeType privilegeType : stmt.getPrivilegeType()) { + for (PrivilegeType privilegeType : stmt.getPrivilegeTypes()) { if (ind == 0) { modelType = privilegeType.getModelType(); } @@ -158,7 +158,7 @@ private void checkRevokePrivileges( assertEquals(authorRType, stmt.getAuthorType()); assertEquals(isUser ? idName : "", stmt.getUserName()); assertEquals(isUser ? "" : idName, stmt.getRoleName()); - Set privilegeTypes = stmt.getPrivilegeType(); + Set privilegeTypes = stmt.getPrivilegeTypes(); Set privilegeTypeSet = new HashSet<>(privilegeTypeList); assertEquals(privilegeTypes, privilegeTypeSet); assertNull(stmt.getPassword()); @@ -194,7 +194,7 @@ private void checkGrantPrivileges( PrivilegeModelType modelType = PrivilegeModelType.INVALID; // 1. All privileges are same model. int ind = 0; - for (PrivilegeType privilegeType : stmt.getPrivilegeType()) { + for (PrivilegeType privilegeType : stmt.getPrivilegeTypes()) { if (ind == 0) { modelType = privilegeType.getModelType(); } @@ -223,7 +223,7 @@ private void checkGrantPrivileges( assertEquals(authType, stmt.getAuthorType()); assertEquals(isUser ? idName : "", stmt.getUserName()); assertEquals(isUser ? "" : idName, stmt.getRoleName()); - Set privilegeTypes = stmt.getPrivilegeType(); + Set privilegeTypes = stmt.getPrivilegeTypes(); Set privilegeTypeSet = new HashSet<>(privilegeTypeList); assertEquals(privilegeTypeSet, privilegeTypes); assertNull(stmt.getPassword()); diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java index e54673d56dae..1e0a818e8260 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java @@ -130,6 +130,7 @@ protected void savePrivileges(BufferedOutputStream outputStream, Role role) thro protected void loadPrivileges(DataInputStream dataInputStream, Role role) throws IOException, IllegalPathException { + role.setSysPrivilegesWithMask(dataInputStream.readInt()); int num = ReadWriteIOUtils.readInt(dataInputStream); List pathPrivilegeList = new ArrayList<>(); for (int i = 0; i < num; i++) { @@ -193,7 +194,6 @@ public Role loadEntry(String entryName) throws IOException { assert version == VERSION; entryName = IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal); Role role = new Role(entryName); - role.setSysPrivilegesWithMask(dataInputStream.readInt()); loadPrivileges(dataInputStream, role); return role; } catch (Exception e) { diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java index 0d836c72979a..3b9264b4c4f6 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java @@ -168,37 +168,37 @@ public User loadEntry(String entryName) throws IOException { File roleOfUser = checkFileAvailable(entryName, "_role"); - Set roleList = new HashSet<>(); + Set roleSet = new HashSet<>(); if (roleOfUser != null && roleOfUser.exists()) { inputStream = new FileInputStream(roleOfUser); - try (DataInputStream roleInpuStream = + try (DataInputStream roleInputStream = new DataInputStream(new BufferedInputStream(inputStream))) { - for (int i = 0; roleInpuStream.available() != 0; i++) { - String rolename = IOUtils.readString(roleInpuStream, STRING_ENCODING, strBufferLocal); - roleList.add(rolename); + for (int i = 0; roleInputStream.available() != 0; i++) { + String roleName = + IOUtils.readString(roleInputStream, STRING_ENCODING, strBufferLocal); + roleSet.add(roleName); } } } - user.setRoleSet(roleList); + user.setRoleSet(roleSet); return user; } assert (tag == VERSION); user.setName(IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal)); user.setPassword(IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal)); - user.setSysPrivilegesWithMask(dataInputStream.readInt()); loadPrivileges(dataInputStream, user); File roleOfUser = checkFileAvailable(entryName, "_role"); Set roleSet = new HashSet<>(); if (roleOfUser.exists()) { inputStream = new FileInputStream(roleOfUser); - try (DataInputStream roleInpuStream = + try (DataInputStream userInputStream = new DataInputStream(new BufferedInputStream(inputStream))) { - int num = roleInpuStream.readInt(); + int num = userInputStream.readInt(); for (int i = 0; i < num; i++) { - String rolename = IOUtils.readString(roleInpuStream, STRING_ENCODING, strBufferLocal); - roleSet.add(rolename); + String roleName = IOUtils.readString(userInputStream, STRING_ENCODING, strBufferLocal); + roleSet.add(roleName); } } } @@ -254,7 +254,9 @@ public List listAllEntries() { (dir, name) -> (name.endsWith(IoTDBConstant.PROFILE_SUFFIX) && !name.endsWith(ROLE_SUFFIX + IoTDBConstant.PROFILE_SUFFIX)) - || (name.endsWith(TEMP_SUFFIX) && !name.endsWith(ROLE_SUFFIX + TEMP_SUFFIX))); + || (name.endsWith(TEMP_SUFFIX) + && !name.endsWith( + ROLE_SUFFIX + IoTDBConstant.PROFILE_SUFFIX + TEMP_SUFFIX))); return getEntryStrings(names); }