This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch auth
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/auth by this push:
new c0c3ccea547 fix auth parser. (#11027)
c0c3ccea547 is described below
commit c0c3ccea54755835df48595155df0ecd75257bbe
Author: Colin Li <[email protected]>
AuthorDate: Mon Sep 4 13:59:34 2023 +0800
fix auth parser. (#11027)
---
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 12 +-
.../db/queryengine/plan/parser/ASTVisitor.java | 67 +++--
.../plan/parser/StatementGeneratorTest.java | 318 +++++++++++++++++++++
.../org/apache/iotdb/commons/utils/AuthUtils.java | 14 +-
.../apache/iotdb/commons/utils/AuthUtilsTest.java | 38 +--
5 files changed, 383 insertions(+), 66 deletions(-)
diff --git
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 381c1b48fbd..3d7118ff3f2 100644
---
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -861,7 +861,7 @@ grantOpt
// Grant User Role
grantRoleToUser
- : GRANT roleName=identifier TO userName=identifier
+ : GRANT ROLE roleName=identifier TO userName=identifier
;
// Revoke User Privileges
@@ -876,7 +876,7 @@ revokeRole
// Revoke Role From User
revokeRoleFromUser
- : REVOKE roleName=identifier FROM userName=identifier
+ : REVOKE ROLE roleName=identifier FROM userName=identifier
;
// Drop User
@@ -899,14 +899,14 @@ listRole
: LIST ROLE (OF USER userName=usernameWithRoot)?
;
-// List Privileges of Users On Specific Path
+// List Privileges of Users
listPrivilegesUser
- : LIST PRIVILEGES USER userName=usernameWithRoot (ON prefixPath (COMMA
prefixPath)*)?
+ : LIST PRIVILEGES OF USER userName=usernameWithRoot
;
-// List Privileges of Roles On Specific Path
+// List Privileges of Roles
listPrivilegesRole
- : LIST PRIVILEGES ROLE roleName=identifier (ON prefixPath (COMMA
prefixPath)*)?
+ : LIST PRIVILEGES OF ROLE roleName=identifier
;
privileges
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index 5909d4f51e4..a96413da6f0 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -2195,10 +2195,11 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
.distinct()
.collect(Collectors.toList());
checkGrantRevokePrivileges(privileges, nodeNameList);
+ String[] priviParsed = parsePrivilege(privileges);
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.GRANT_USER);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
- authorStatement.setPrivilegeList(privileges);
+ authorStatement.setPrivilegeList(priviParsed);
authorStatement.setNodeNameList(nodeNameList);
authorStatement.setGrantOpt(ctx.grantOpt() != null);
return authorStatement;
@@ -2215,10 +2216,11 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
.distinct()
.collect(Collectors.toList());
checkGrantRevokePrivileges(privileges, nodeNameList);
+ String[] priviParsed = parsePrivilege(privileges);
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.GRANT_ROLE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
- authorStatement.setPrivilegeList(privileges);
+ authorStatement.setPrivilegeList(priviParsed);
authorStatement.setNodeNameList(nodeNameList);
authorStatement.setGrantOpt(ctx.grantOpt() != null);
return authorStatement;
@@ -2245,10 +2247,11 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
.distinct()
.collect(Collectors.toList());
checkGrantRevokePrivileges(privileges, nodeNameList);
+ String[] priviParsed = parsePrivilege(privileges);
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.REVOKE_USER);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
- authorStatement.setPrivilegeList(privileges);
+ authorStatement.setPrivilegeList(priviParsed);
authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
@@ -2264,40 +2267,66 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
.distinct()
.collect(Collectors.toList());
checkGrantRevokePrivileges(privileges, nodeNameList);
+ String[] priviParsed = parsePrivilege(privileges);
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.REVOKE_ROLE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
- authorStatement.setPrivilegeList(privileges);
+ authorStatement.setPrivilegeList(priviParsed);
authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
private void checkGrantRevokePrivileges(String[] privileges,
List<PartialPath> nodeNameList) {
+ // 1. all grant or revoke statements need target path.
if (nodeNameList.isEmpty()) {
- nodeNameList.add(new PartialPath(ALL_RESULT_NODES));
- return;
+ throw new SemanticException("Statement needs target paths");
}
- boolean pathRelevant = true;
+
+ // 2. if privilege list has system privilege or "ALL", nodeNameList must
only contain "root.**".
+ boolean hasSystemPri = false;
String errorPrivilegeName = "";
+
for (String privilege : privileges) {
- if (!PrivilegeType.valueOf(privilege.toUpperCase()).isPathRelevant()) {
- pathRelevant = false;
+ if ("ALL".equalsIgnoreCase(privilege)
+ || (!"READ".equalsIgnoreCase(privilege)
+ && !"WRITE".equalsIgnoreCase(privilege)
+ &&
!PrivilegeType.valueOf(privilege.toUpperCase()).isPathRelevant())) {
+ hasSystemPri = true;
errorPrivilegeName = privilege.toUpperCase();
break;
}
}
- if (!(pathRelevant
- || (nodeNameList.size() == 1
- && nodeNameList.contains(new PartialPath(ALL_RESULT_NODES))))) {
+ if (hasSystemPri
+ && !(nodeNameList.size() == 1
+ && nodeNameList.contains(new PartialPath(ALL_RESULT_NODES)))) {
throw new SemanticException(
- String.format(
- "path independent privilege: [%s] can only be set on path:
root.**",
- errorPrivilegeName));
+ String.format("[%s] can only be set on path: root.**",
errorPrivilegeName));
}
}
- // Revoke Role From User
+ private String[] parsePrivilege(String[] privileges) {
+ Set<String> privSet = new HashSet<>();
+ for (String priv : privileges) {
+ if (priv.equalsIgnoreCase("READ")) {
+ privSet.add("READ_SCHEMA");
+ privSet.add("READ_DATA");
+ continue;
+ } else if (priv.equalsIgnoreCase("WRITE")) {
+ privSet.add("WRITE_DATA");
+ privSet.add("WRITE_SCHEMA");
+ continue;
+ } else if (priv.equalsIgnoreCase("ALL")) {
+ for (PrivilegeType type : PrivilegeType.values()) {
+ privSet.add(type.toString());
+ }
+ continue;
+ }
+ privSet.add(priv);
+ }
+ return privSet.toArray(new String[0]);
+ }
+ // Revoke Role From User
@Override
public Statement
visitRevokeRoleFromUser(IoTDBSqlParser.RevokeRoleFromUserContext ctx) {
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.REVOKE_USER_ROLE);
@@ -2352,9 +2381,6 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
public Statement
visitListPrivilegesUser(IoTDBSqlParser.ListPrivilegesUserContext ctx) {
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.LIST_USER_PRIVILEGE);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
- List<PartialPath> nodeNameList =
-
ctx.prefixPath().stream().map(this::parsePrefixPath).collect(Collectors.toList());
- authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
@@ -2364,9 +2390,6 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
public Statement
visitListPrivilegesRole(IoTDBSqlParser.ListPrivilegesRoleContext ctx) {
AuthorStatement authorStatement = new
AuthorStatement(AuthorType.LIST_ROLE_PRIVILEGE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
- List<PartialPath> nodeNameList =
-
ctx.prefixPath().stream().map(this::parsePrefixPath).collect(Collectors.toList());
- authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGeneratorTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGeneratorTest.java
index ff0ec603365..b8f8645aae6 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGeneratorTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGeneratorTest.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.db.queryengine.plan.parser;
import org.apache.iotdb.common.rpc.thrift.TAggregationType;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.exception.MetadataException;
import org.apache.iotdb.commons.path.PartialPath;
@@ -33,6 +34,7 @@ import
org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimestampOperand;
import
org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
+import org.apache.iotdb.db.queryengine.plan.statement.StatementType;
import org.apache.iotdb.db.queryengine.plan.statement.component.ResultColumn;
import org.apache.iotdb.db.queryengine.plan.statement.crud.DeleteDataStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertMultiTabletsStatement;
@@ -52,6 +54,7 @@ import
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.CreateSc
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.DropSchemaTemplateStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowNodesInSchemaTemplateStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.UnsetSchemaTemplateStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement;
import org.apache.iotdb.isession.template.TemplateNode;
import org.apache.iotdb.mpp.rpc.thrift.TDeleteModelMetricsReq;
import org.apache.iotdb.mpp.rpc.thrift.TFetchTimeseriesReq;
@@ -89,12 +92,16 @@ import java.nio.ByteBuffer;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Set;
import static
org.apache.iotdb.db.schemaengine.template.TemplateQueryType.SHOW_MEASUREMENTS;
import static
org.apache.iotdb.tsfile.file.metadata.enums.CompressionType.SNAPPY;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
public class StatementGeneratorTest {
@@ -463,6 +470,317 @@ public class StatementGeneratorTest {
}
}
+ private AuthorStatement createAuthDclStmt(String sql) {
+ Statement stmt = StatementGenerator.createStatement(sql,
ZonedDateTime.now().getOffset());
+ AuthorStatement roleDcl = (AuthorStatement) stmt;
+ return roleDcl;
+ }
+
+ @Test
+ public void testDCLUserOperation() {
+ // 1. create user and drop user
+ AuthorStatement userDcl = createAuthDclStmt("create user `user1`
'password1';");
+ assertEquals("user1", userDcl.getUserName());
+ assertEquals(Collections.emptyList(), userDcl.getPaths());
+ assertEquals("password1", userDcl.getPassWord());
+ assertEquals(StatementType.CREATE_USER, userDcl.getType());
+
+ userDcl = createAuthDclStmt("drop user `user1`;");
+ assertEquals("user1", userDcl.getUserName());
+ assertEquals(Collections.emptyList(), userDcl.getPaths());
+ assertEquals(StatementType.DELETE_USER, userDcl.getType());
+
+ // 2.update user's password
+ userDcl = createAuthDclStmt("alter user `user1` set password
'password2';");
+ assertEquals("user1", userDcl.getUserName());
+ /**
+ * [ BUG ] We didn't save the old password in the statement. If userA has
logged in with
+ * session_A. Session_B's alter password operation cannot block session
A's alter password
+ * operation because we only check the user's password before they log in.
+ */
+ // assertEquals("password1", userDcl.getPassWord());
+ assertEquals("password2", userDcl.getNewPassword());
+ assertEquals(StatementType.MODIFY_PASSWORD, userDcl.getType());
+ }
+
+ @Test
+ public void testDCLROLEOperation() {
+ // 1. create role and drop role.
+ AuthorStatement roleDcl = createAuthDclStmt("create role role1;");
+ assertEquals("role1", roleDcl.getRoleName());
+ assertEquals(StatementType.CREATE_ROLE, roleDcl.getType());
+
+ roleDcl = createAuthDclStmt("drop role role1;");
+ assertEquals(StatementType.DELETE_ROLE, roleDcl.getType());
+ assertEquals("role1", roleDcl.getRoleName());
+
+ // 2. grant and revoke role.
+ roleDcl = createAuthDclStmt("grant role `role1` to `user1`;");
+ assertEquals(StatementType.GRANT_USER_ROLE, roleDcl.getType());
+ assertEquals("role1", roleDcl.getRoleName());
+ assertEquals("user1", roleDcl.getUserName());
+
+ roleDcl = createAuthDclStmt("revoke role `role1` from `user1`;");
+ assertEquals(StatementType.GRANT_USER_ROLE, roleDcl.getType());
+ assertEquals("role1", roleDcl.getRoleName());
+ assertEquals("user1", roleDcl.getUserName());
+ }
+
+ @FunctionalInterface
+ interface grantRevokeCheck {
+ void checkParser(String privilege, String name, boolean isuser, String
path, boolean grantOpt);
+ }
+
+ /** This test will check grant/revoke simple privilege on/from paths. */
+ @Test
+ public void testNormalGrantRevoke() {
+ grantRevokeCheck testGrant =
+ (privilege, name, isuser, path, grantOpt) -> {
+ String sql = "grant %s on %s to %s %s %s ;";
+ sql =
+ String.format(
+ sql,
+ privilege,
+ path,
+ isuser ? "USER" : "ROLE",
+ name,
+ grantOpt ? "with grant option" : "");
+ AuthorStatement aclStmt = createAuthDclStmt(sql);
+ assertEquals(
+ isuser ? StatementType.GRANT_USER_PRIVILEGE :
StatementType.GRANT_ROLE_PRIVILEGE,
+ aclStmt.getType());
+ assertEquals(path, aclStmt.getPaths().get(0).toString());
+ assertEquals(name, isuser ? aclStmt.getUserName() :
aclStmt.getRoleName());
+ assertEquals(grantOpt, aclStmt.getGrantOpt());
+ assertEquals(privilege, aclStmt.getPrivilegeList()[0]);
+ };
+
+ String name = "test1";
+ String path = "root.**";
+ String pathErr = "root.t1.**";
+ String pathsErr = "root.**, root.t1.**";
+
+ // 1. check simple privilege grant to user/role with/without grant option.
+ for (PrivilegeType privilege : PrivilegeType.values()) {
+ testGrant.checkParser(privilege.toString(), name, true, path, true);
+ testGrant.checkParser(privilege.toString(), name, true, path, false);
+ testGrant.checkParser(privilege.toString(), name, false, path, true);
+ testGrant.checkParser(privilege.toString(), name, false, path, false);
+ // 2. if grant stmt has system privilege, path should be root.**
+ if (!privilege.isPathRelevant()) {
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ String.format("GRANT %s on %s to USER `user1`;",
privilege, pathErr)));
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ String.format("GRANT %s on %s to USER `user1`;",
privilege, pathsErr)));
+ }
+ }
+
+ grantRevokeCheck testRevoke =
+ (privilege, username, isuser, targtePath, grantOpt) -> {
+ String sql = "revoke %s on %s from %s %s";
+ sql = String.format(sql, privilege, targtePath, isuser ? "USER" :
"ROLE", username);
+ AuthorStatement aclStmt = createAuthDclStmt(sql);
+ assertEquals(
+ isuser ? StatementType.REVOKE_USER_PRIVILEGE :
StatementType.REVOKE_ROLE_PRIVILEGE,
+ aclStmt.getType());
+ assertEquals(path, aclStmt.getPaths().get(0).toString());
+ assertEquals(username, isuser ? aclStmt.getUserName() :
aclStmt.getRoleName());
+ assertFalse(aclStmt.getGrantOpt());
+ assertEquals(privilege, aclStmt.getPrivilegeList()[0]);
+ };
+
+ // 3. check simple privilege revoke from user/role on simple path
+ for (PrivilegeType type : PrivilegeType.values()) {
+ testRevoke.checkParser(type.toString(), name, true, path, false);
+ testRevoke.checkParser(type.toString(), name, false, path, false);
+
+ // 4. check system privilege revoke from user on wrong paths.
+ if (!type.isPathRelevant()) {
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ String.format("revoke %s on %s FROM USER `user1`;", type,
pathErr)));
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ String.format("revoke %s on %s FROM USER `user1`;", type,
pathsErr)));
+ }
+ }
+ }
+
+ @Test
+ public void testComplexGrantRevoke() {
+ // 1. test complex privilege on single path :"root.**"
+ Set<String> allPriv = new HashSet<>();
+ for (PrivilegeType type : PrivilegeType.values()) {
+ allPriv.add(type.toString());
+ }
+
+ for (PrivilegeType type : PrivilegeType.values()) {
+ {
+ AuthorStatement stmt =
+ createAuthDclStmt(
+ String.format("GRANT ALL,%s on root.** to USER `user1` with
grant option", type));
+ assertEquals(allPriv, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+ Assert.assertTrue(stmt.getGrantOpt());
+ assertEquals(StatementType.GRANT_USER_PRIVILEGE, stmt.getType());
+ }
+ {
+ AuthorStatement stmt =
+ createAuthDclStmt(String.format("REVOKE ALL,%s on root.** from
USER `user1`;", type));
+ assertEquals(allPriv, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+ assertEquals(StatementType.REVOKE_USER_PRIVILEGE, stmt.getType());
+ }
+ {
+ AuthorStatement stmt =
+ createAuthDclStmt(String.format("GRANT ALL,%s on root.** to ROLE
`role1`;", type));
+ assertEquals(allPriv, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+ assertFalse(stmt.getGrantOpt());
+ assertEquals(StatementType.GRANT_ROLE_PRIVILEGE, stmt.getType());
+ }
+ }
+
+ AuthorStatement stmt =
+ createAuthDclStmt("GRANT ALL ON root.** to user `user1` with grant
option;");
+ assertEquals(allPriv, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+ Assert.assertTrue(stmt.getGrantOpt());
+ assertEquals(allPriv, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+
+ // 2. complex privilege on a single wrong path
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("grant all on root.t1.** to USER `user1` with
grant option;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("grant all on root.t1.** to ROLE `user1` with
grant option;"));
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ "grant all,READ_DATA on root.t1.** to USER `user1` with grant
option"));
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ "grant all,READ_DATA on root.t1.** to ROLE `user1` with grant
option"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("grant all on root.t1.** to USER `user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("grant all on root.t1.** to ROLE `user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("grant all,READ_DATA on root.t1.** to USER
`user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("grant all,READ_DATA on root.t1.** to ROLE
`user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("revoke all on root.t1.** from USER
`user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("revoke all on root.t1.** from ROLE
`user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("revoke all,READ_DATA on root.t1.** from USER
`user1`;"));
+ assertThrows(
+ SemanticException.class,
+ () -> createAuthDclStmt("revoke all,READ_DATA on root.t1.** from ROLE
`user1`;"));
+ try {
+ createAuthDclStmt("grant all on root.t1.**, root.** to USER `user1` with
grant option;");
+ } catch (SemanticException e) {
+ assertEquals("[ALL] can only be set on path: root.**", e.getMessage());
+ }
+
+ try {
+ createAuthDclStmt("grant MANAGE_ROLE on root.t1.** to USER `user1` with
grant option;");
+ } catch (SemanticException e) {
+ assertEquals("[MANAGE_ROLE] can only be set on path: root.**",
e.getMessage());
+ }
+
+ // 3. complex privilege on complex paths.
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ "grant all on root.t1.**, root.** to USER `user1` with grant
option;"));
+ assertThrows(
+ SemanticException.class,
+ () ->
+ createAuthDclStmt(
+ "grant MANAGE_ROLE on root.t1.**, root.** to USER `user1` with
grant option;"));
+
+ // 4. READ privilege can be parsed successfully.
+ stmt = createAuthDclStmt("GRANT READ ON root.** TO USER `user1`;");
+ Set<String> readSet = new HashSet<>();
+ readSet.add("READ_DATA");
+ readSet.add("READ_SCHEMA");
+ assertEquals(readSet, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+
+ stmt = createAuthDclStmt("GRANT READ,READ_DATA ON root.** TO USER
`user1`;");
+ assertEquals(readSet, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+
+ stmt = createAuthDclStmt("GRANT READ,READ_DATA ON root.**,root.t1.t2 TO
USER `user1`;");
+ assertEquals(readSet, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+ assertEquals(2, stmt.getPaths().size());
+
+ // 5. WRITE privilege can be parsed successfully.
+ stmt = createAuthDclStmt("GRANT WRITE ON root.** TO USER `user1`;");
+ Set<String> writeSet = new HashSet<>();
+ writeSet.add("WRITE_DATA");
+ writeSet.add("WRITE_SCHEMA");
+ assertEquals(writeSet, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+
+ stmt = createAuthDclStmt("GRANT WRITE,WRITE_DATA ON root.** TO USER
`user1`;");
+ assertEquals(writeSet, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+
+ stmt = createAuthDclStmt("GRANT WRITE,WRITE ON root.**,root.t1.t2 TO USER
`user1`;");
+ assertEquals(writeSet, new
HashSet<>(Arrays.asList(stmt.getPrivilegeList())));
+ assertEquals(2, stmt.getPaths().size());
+ }
+
+ @Test
+ public void testListThings() {
+ // 1. list user
+ AuthorStatement stmt = createAuthDclStmt("LIST USER;");
+ assertEquals(StatementType.LIST_USER, stmt.getType());
+ assertEquals(null, stmt.getRoleName());
+
+ // 2. list user of role
+ stmt = createAuthDclStmt("LIST USER OF ROLE `role1`;");
+ assertEquals(StatementType.LIST_USER, stmt.getType());
+ assertEquals("role1", stmt.getRoleName());
+
+ // 3. list role
+ stmt = createAuthDclStmt("LIST ROLE;");
+ assertEquals(StatementType.LIST_ROLE, stmt.getType());
+ assertEquals(null, stmt.getUserName());
+
+ // 4. list role of user
+ stmt = createAuthDclStmt("LIST ROLE OF USER `user1`;");
+ assertEquals(StatementType.LIST_ROLE, stmt.getType());
+ assertEquals("user1", stmt.getUserName());
+
+ // 5. list privileges of user
+ stmt = createAuthDclStmt("LIST PRIVILEGES OF USER `user1`;");
+ assertEquals(StatementType.LIST_USER_PRIVILEGE, stmt.getType());
+ assertEquals("user1", stmt.getUserName());
+
+ // 6. list privileges of role
+ stmt = createAuthDclStmt("LIST PRIVILEGES OF ROLE `role1`;");
+ assertEquals(StatementType.LIST_ROLE_PRIVILEGE, stmt.getType());
+ assertEquals("role1", stmt.getRoleName());
+ }
+
// TODO: add more tests
private void checkQueryStatement(
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
index 96266071713..6a576ae5f40 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
@@ -244,9 +244,17 @@ public class AuthUtils {
return false;
}
for (PathPrivilege pathPrivilege : privilegeList) {
- if (pathPrivilege.getPath().matchFullPath(path)
- && pathPrivilege.getPrivileges().contains(privilegeId)) {
- return true;
+ if (pathPrivilege.getPath().matchFullPath(path)) {
+ if (pathPrivilege.getPrivileges().contains(privilegeId)) {
+ return true;
+ }
+ if (privilegeId == PrivilegeType.READ_SCHEMA.ordinal()
+ &&
pathPrivilege.getPrivileges().contains(PrivilegeType.WRITE_SCHEMA.ordinal()))
+ return true;
+ if (privilegeId == PrivilegeType.READ_DATA.ordinal()
+ &&
pathPrivilege.getPrivileges().contains(PrivilegeType.WRITE_DATA.ordinal())) {
+ return true;
+ }
}
}
return false;
diff --git
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/AuthUtilsTest.java
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/AuthUtilsTest.java
index b0048e09bd0..97a88ace8d1 100644
---
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/AuthUtilsTest.java
+++
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/AuthUtilsTest.java
@@ -30,40 +30,8 @@ import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
-import java.util.Vector;
public class AuthUtilsTest {
- @Test
- public void authUtilsTest_ParameterCheck() throws AuthException,
IllegalPathException {
- AuthUtils auth;
- Vector<String> nameOrPassword = new Vector<>();
- nameOrPassword.add(new String("he"));
- nameOrPassword.add(
- new String(
- "qwertyuiopasdfghjklzxcvbnm123456789999999asdfgh"
- + "jkzxcvbnmqwertyuioasdfghjklzxcvbnm"));
- nameOrPassword.add(new String("he llo"));
- nameOrPassword.add(new String("hel^d"));
- nameOrPassword.add(new String("he\\llo"));
- nameOrPassword.add(new String("he*llo"));
- nameOrPassword.add(new String("he*$llo"));
- for (String item : nameOrPassword) {
- Assert.assertThrows(AuthException.class, () ->
AuthUtils.validateNameOrPassword(item));
- }
- PartialPath path1 = new PartialPath(new String("data.t1"));
- PartialPath path2 = new PartialPath(new String("root.t1"));
- Assert.assertThrows(AuthException.class, () ->
AuthUtils.validatePath(path1));
- Assert.assertThrows(AuthException.class, () ->
AuthUtils.validatePrivilege(-1));
- // give a wrong path
- Assert.assertThrows(AuthException.class, () ->
AuthUtils.validatePrivilege(path1, -1));
- // give a path but a wrong privilege id
- Assert.assertThrows(AuthException.class, () ->
AuthUtils.validatePrivilege(path2, 5));
-
- Assert.assertThrows(AuthException.class, () ->
AuthUtils.validatePrivilege(null, 3));
- AuthUtils.validatePrivilege(path2, PrivilegeType.WRITE_SCHEMA.ordinal());
- AuthUtils.validatePrivilege(null, PrivilegeType.MANAGE_ROLE.ordinal());
- }
-
@Test
public void authUtilsTest_PrivilegeGrantRevokeCheck() throws
IllegalPathException {
PartialPath path = new PartialPath(new String("root.t1"));
@@ -79,7 +47,7 @@ public class AuthUtilsTest {
PathPrivilege pathWithPri3 = new PathPrivilege(path3);
pathWithPri3.grantPrivilege(PrivilegeType.READ_DATA.ordinal(), false);
- /** root.t1 : read schema, read data root.t2 : write schema root.** : read
data */
+ /** root.t1 : read schema, read data; root.t2 : write schema; root.** :
read data */
// Privilege list is empty.
Assert.assertFalse(
AuthUtils.checkPathPrivilege(path2,
PrivilegeType.READ_SCHEMA.ordinal(), null));
@@ -88,13 +56,13 @@ public class AuthUtilsTest {
privilegeList.add(pathWithPri);
privilegeList.add(pathWithPri2);
privilegeList.add(pathWithPri3);
- Assert.assertFalse(
+ Assert.assertTrue(
AuthUtils.checkPathPrivilege(path2,
PrivilegeType.READ_SCHEMA.ordinal(), privilegeList));
Assert.assertTrue(
AuthUtils.checkPathPrivilege(path,
PrivilegeType.READ_SCHEMA.ordinal(), privilegeList));
pathWithPri.revokePrivilege(PrivilegeType.READ_SCHEMA.ordinal());
- /** root.t1 : read data root.t2 : write schema root.** : read data */
+ /** root.t1 : read data; root.t2 : write schema ; root.** : read data */
Assert.assertFalse(
AuthUtils.checkPathPrivilege(path,
PrivilegeType.READ_SCHEMA.ordinal(), privilegeList));
Assert.assertTrue(