This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.1 by this push:
new ff5a4cb5b9f [enhance](auth)when assigning permissions, the current
user must have corresponding permissions (#32825) (#33948)
ff5a4cb5b9f is described below
commit ff5a4cb5b9f7081d630890e0c4eab2ade49944cb
Author: Mingyu Chen <[email protected]>
AuthorDate: Mon Apr 22 12:08:46 2024 +0800
[enhance](auth)when assigning permissions, the current user must have
corresponding permissions (#32825) (#33948)
bp #32825
Co-authored-by: zhangdong <[email protected]>
---
.../java/org/apache/doris/analysis/GrantStmt.java | 183 ++++++++++-----------
.../java/org/apache/doris/analysis/RevokeStmt.java | 6 +-
.../java/org/apache/doris/common/ErrorCode.java | 2 +
.../apache/doris/mysql/privilege/Privilege.java | 4 +
.../apache/doris/datasource/CatalogMgrTest.java | 4 -
.../org/apache/doris/mysql/privilege/AuthTest.java | 11 +-
.../suites/account_p0/test_grant_priv.groovy | 86 ++++++++++
.../account_p0/test_grant_priv_resource.groovy | 57 +++++++
.../account_p0/test_grant_priv_workload.groovy | 57 +++++++
9 files changed, 305 insertions(+), 105 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
index 6712eec124a..f752ab7aae9 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
@@ -17,6 +17,7 @@
package org.apache.doris.analysis;
+import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.AccessPrivilegeWithCols;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
@@ -24,19 +25,23 @@ import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
+import org.apache.doris.mysql.privilege.AccessControllerManager;
import org.apache.doris.mysql.privilege.Auth.PrivLevel;
import org.apache.doris.mysql.privilege.ColPrivilegeKey;
+import org.apache.doris.mysql.privilege.PrivBitSet;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.Privilege;
import org.apache.doris.qe.ConnectContext;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -55,11 +60,11 @@ public class GrantStmt extends DdlStmt {
private ResourcePattern resourcePattern;
private WorkloadGroupPattern workloadGroupPattern;
private Set<Privilege> privileges = Sets.newHashSet();
- //Privilege,ctl,db,table -> cols
+ // Privilege,ctl,db,table -> cols
private Map<ColPrivilegeKey, Set<String>> colPrivileges =
Maps.newHashMap();
// Indicates that these roles are granted to a user
private List<String> roles;
- //AccessPrivileges will be parsed into two parts,
+ // AccessPrivileges will be parsed into two parts,
// with the column permissions section placed in "colPrivileges" and the
others in "privileges"
private List<AccessPrivilegeWithCols> accessPrivileges;
@@ -164,11 +169,11 @@ public class GrantStmt extends DdlStmt {
}
if (tblPattern != null) {
- checkTablePrivileges(privileges, role, tblPattern, colPrivileges);
+ checkTablePrivileges(privileges, tblPattern, colPrivileges);
} else if (resourcePattern != null) {
- checkResourcePrivileges(privileges, role, resourcePattern);
+ checkResourcePrivileges(privileges, resourcePattern);
} else if (workloadGroupPattern != null) {
- checkWorkloadGroupPrivileges(privileges, role,
workloadGroupPattern);
+ checkWorkloadGroupPrivileges(privileges, workloadGroupPattern);
} else if (roles != null) {
checkRolePrivileges();
}
@@ -187,134 +192,124 @@ public class GrantStmt extends DdlStmt {
/**
* Rules:
- * 1. ADMIN_PRIV and NODE_PRIV can only be granted/revoked on GLOBAL level
- * 2. Only the user with NODE_PRIV can grant NODE_PRIV to other user
- * 3. Privileges can not be granted/revoked to/from ADMIN and OPERATOR role
- * 4. Only user with GLOBAL level's GRANT_PRIV can grant/revoke privileges
to/from roles.
- * 5.1 User should has GLOBAL level GRANT_PRIV
- * 5.2 or user has DATABASE/TABLE level GRANT_PRIV if grant/revoke to/from
certain database or table.
- * 5.3 or user should has 'resource' GRANT_PRIV if grant/revoke to/from
certain 'resource'
- * 5.4 or user should has 'workload group' GRANT_PRIV if grant/revoke
to/from certain 'workload group'
- * 6. Can not grant USAGE_PRIV to database or table
+ * 1. some privs in Privilege.notBelongToTablePrivileges can not
granted/revoked on table
+ * 2. ADMIN_PRIV and NODE_PRIV can only be granted/revoked on GLOBAL level
+ * 3. Only the user with NODE_PRIV can grant NODE_PRIV to other user
+ * 4. Check that the current user has both grant_priv and the permissions
to be assigned to others
+ * 5. col priv must assign to specific table
*
* @param privileges
- * @param role
* @param tblPattern
* @throws AnalysisException
*/
- public static void checkTablePrivileges(Collection<Privilege> privileges,
String role, TablePattern tblPattern,
+ public static void checkTablePrivileges(Collection<Privilege> privileges,
TablePattern tblPattern,
Map<ColPrivilegeKey, Set<String>> colPrivileges)
throws AnalysisException {
// Rule 1
+ checkIncorrectPrivilege(Privilege.notBelongToTablePrivileges,
privileges);
+ // Rule 2
if (tblPattern.getPrivLevel() != PrivLevel.GLOBAL &&
(privileges.contains(Privilege.ADMIN_PRIV)
|| privileges.contains(Privilege.NODE_PRIV))) {
throw new AnalysisException("ADMIN_PRIV and NODE_PRIV can only be
granted/revoke on/from *.*.*");
}
- // Rule 2
+ // Rule 3
if (privileges.contains(Privilege.NODE_PRIV) &&
!Env.getCurrentEnv().getAccessManager()
.checkGlobalPriv(ConnectContext.get(),
PrivPredicate.OPERATOR)) {
throw new AnalysisException("Only user with NODE_PRIV can
grant/revoke NODE_PRIV to other user");
}
- if (role != null) {
- // Rule 3 and 4
- if
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else {
- // Rule 5.1 and 5.2
- if (tblPattern.getPrivLevel() == PrivLevel.GLOBAL) {
- if (!Env.getCurrentEnv().getAccessManager()
- .checkGlobalPriv(ConnectContext.get(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else if (tblPattern.getPrivLevel() == PrivLevel.CATALOG) {
- if
(!Env.getCurrentEnv().getAccessManager().checkCtlPriv(ConnectContext.get(),
- tblPattern.getQualifiedCtl(), PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else if (tblPattern.getPrivLevel() == PrivLevel.DATABASE) {
- if
(!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(),
- tblPattern.getQualifiedCtl(),
tblPattern.getQualifiedDb(), PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else {
- // table level
- if (!Env.getCurrentEnv().getAccessManager()
- .checkTblPriv(ConnectContext.get(),
tblPattern.getQualifiedCtl(), tblPattern.getQualifiedDb(),
- tblPattern.getTbl(), PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- }
- }
-
- // Rule 6
- if (privileges.contains(Privilege.USAGE_PRIV)) {
- throw new AnalysisException("Can not grant/revoke USAGE_PRIV
to/from database or table");
+ // Rule 4
+ PrivPredicate predicate = getPrivPredicate(privileges);
+ AccessControllerManager accessManager =
Env.getCurrentEnv().getAccessManager();
+ if (!accessManager.checkGlobalPriv(ConnectContext.get(),
PrivPredicate.ADMIN)
+ && !checkTablePriv(ConnectContext.get(), predicate,
tblPattern)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ALL_ACCESS_DENIED_ERROR,
+ predicate.getPrivs().toPrivilegeList());
}
- // Rule 7
+ // Rule 5
if (!MapUtils.isEmpty(colPrivileges) &&
"*".equals(tblPattern.getTbl())) {
throw new AnalysisException("Col auth must specify specific
table");
}
}
- public static void checkResourcePrivileges(Collection<Privilege>
privileges, String role,
- ResourcePattern resourcePattern) throws AnalysisException {
- for (int i = 0; i < Privilege.notBelongToResourcePrivileges.length;
i++) {
- if
(privileges.contains(Privilege.notBelongToResourcePrivileges[i])) {
+ private static void checkIncorrectPrivilege(Privilege[]
incorrectPrivileges,
+ Collection<Privilege> privileges) throws AnalysisException {
+ for (int i = 0; i < incorrectPrivileges.length; i++) {
+ if (privileges.contains(incorrectPrivileges[i])) {
throw new AnalysisException(
- String.format("Can not grant/revoke %s on resource
to/from any other users or roles",
- Privilege.notBelongToResourcePrivileges[i]));
+ String.format("Can not grant/revoke %s to/from any
other users or roles",
+ incorrectPrivileges[i]));
}
}
+ }
- if (role != null) {
- // Rule 3 and 4
- if
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else {
- // Rule 5.1 and 5.3
- if (resourcePattern.getPrivLevel() == PrivLevel.GLOBAL) {
- if (!Env.getCurrentEnv().getAccessManager()
- .checkGlobalPriv(ConnectContext.get(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else {
- if
(!Env.getCurrentEnv().getAccessManager().checkResourcePriv(ConnectContext.get(),
- resourcePattern.getResourceName(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- }
+ private static PrivPredicate getPrivPredicate(Collection<Privilege>
privileges) {
+ ArrayList<Privilege> privs = Lists.newArrayList(privileges);
+ privs.add(Privilege.GRANT_PRIV);
+ return PrivPredicate.of(PrivBitSet.of(privs), Operator.AND);
+ }
+
+ private static boolean checkTablePriv(ConnectContext ctx, PrivPredicate
wanted,
+ TablePattern tblPattern) {
+ AccessControllerManager accessManager =
Env.getCurrentEnv().getAccessManager();
+ switch (tblPattern.getPrivLevel()) {
+ case GLOBAL:
+ return accessManager.checkGlobalPriv(ctx, wanted);
+ case CATALOG:
+ return accessManager.checkCtlPriv(ConnectContext.get(),
+ tblPattern.getQualifiedCtl(), wanted);
+ case DATABASE:
+ return accessManager.checkDbPriv(ConnectContext.get(),
+ tblPattern.getQualifiedCtl(),
tblPattern.getQualifiedDb(), wanted);
+ default:
+ return accessManager.checkTblPriv(ConnectContext.get(),
tblPattern.getQualifiedCtl(),
+ tblPattern.getQualifiedDb(), tblPattern.getTbl(),
wanted);
}
}
- public static void checkWorkloadGroupPrivileges(Collection<Privilege>
privileges, String role,
- WorkloadGroupPattern workloadGroupPattern) throws
AnalysisException {
- for (int i = 0; i <
Privilege.notBelongToWorkloadGroupPrivileges.length; i++) {
- if
(privileges.contains(Privilege.notBelongToWorkloadGroupPrivileges[i])) {
- throw new AnalysisException(
- String.format("Can not grant/revoke %s on workload
group to/from any other users or roles",
-
Privilege.notBelongToWorkloadGroupPrivileges[i]));
- }
+ public static void checkResourcePrivileges(Collection<Privilege>
privileges,
+ ResourcePattern resourcePattern) throws AnalysisException {
+ checkIncorrectPrivilege(Privilege.notBelongToResourcePrivileges,
privileges);
+
+ PrivPredicate predicate = getPrivPredicate(privileges);
+ AccessControllerManager accessManager =
Env.getCurrentEnv().getAccessManager();
+ if (!accessManager.checkGlobalPriv(ConnectContext.get(),
PrivPredicate.ADMIN)
+ && !checkResourcePriv(ConnectContext.get(), resourcePattern,
predicate)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ALL_ACCESS_DENIED_ERROR,
+ predicate.getPrivs().toPrivilegeList());
}
- if (role != null) {
- // Rule 4
- if
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
- }
- } else if
(!Env.getCurrentEnv().getAccessManager().checkWorkloadGroupPriv(ConnectContext.get(),
- workloadGroupPattern.getworkloadGroupName(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
+ }
+
+ private static boolean checkResourcePriv(ConnectContext ctx,
ResourcePattern resourcePattern,
+ PrivPredicate privPredicate) {
+ if (resourcePattern.getPrivLevel() == PrivLevel.GLOBAL) {
+ return Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
privPredicate);
+ } else {
+ return Env.getCurrentEnv().getAccessManager()
+ .checkResourcePriv(ctx, resourcePattern.getResourceName(),
privPredicate);
+ }
+ }
+
+ public static void checkWorkloadGroupPrivileges(Collection<Privilege>
privileges,
+ WorkloadGroupPattern workloadGroupPattern) throws
AnalysisException {
+ checkIncorrectPrivilege(Privilege.notBelongToWorkloadGroupPrivileges,
privileges);
+
+ PrivPredicate predicate = getPrivPredicate(privileges);
+ AccessControllerManager accessManager =
Env.getCurrentEnv().getAccessManager();
+ if (!accessManager.checkGlobalPriv(ConnectContext.get(),
PrivPredicate.ADMIN)
+ && !accessManager.checkWorkloadGroupPriv(ConnectContext.get(),
+ workloadGroupPattern.getworkloadGroupName(), predicate)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ALL_ACCESS_DENIED_ERROR,
+ predicate.getPrivs().toPrivilegeList());
}
}
public static void checkRolePrivileges() throws AnalysisException {
if
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(),
PrivPredicate.GRANT)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/ROVOKE");
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT/REVOKE");
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
index 18066b925da..e586da88cc8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
@@ -147,11 +147,11 @@ public class RevokeStmt extends DdlStmt {
// Revoke operation obey the same rule as Grant operation. reuse the
same method
if (tblPattern != null) {
- GrantStmt.checkTablePrivileges(privileges, role, tblPattern,
colPrivileges);
+ GrantStmt.checkTablePrivileges(privileges, tblPattern,
colPrivileges);
} else if (resourcePattern != null) {
- GrantStmt.checkResourcePrivileges(privileges, role,
resourcePattern);
+ GrantStmt.checkResourcePrivileges(privileges, resourcePattern);
} else if (workloadGroupPattern != null) {
- GrantStmt.checkWorkloadGroupPrivileges(privileges, role,
workloadGroupPattern);
+ GrantStmt.checkWorkloadGroupPrivileges(privileges,
workloadGroupPattern);
} else if (roles != null) {
GrantStmt.checkRolePrivileges();
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
index 0ea4cdf0043..5a348278a15 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
@@ -76,6 +76,8 @@ public enum ErrorCode {
+ "(current value: %d)"),
ERR_SPECIFIC_ACCESS_DENIED_ERROR(1227, new byte[]{'4', '2', '0', '0',
'0'}, "Access denied; you need (at least "
+ "one of) the %s privilege(s) for this operation"),
+ ERR_SPECIFIC_ALL_ACCESS_DENIED_ERROR(1227, new byte[] {'4', '2', '0', '0',
'0'}, "Access denied; you need all "
+ + " %s privilege(s) for this operation"),
ERR_LOCAL_VARIABLE(1228, new byte[]{'H', 'Y', '0', '0', '0'}, "Variable
'%s' is a SESSION variable and can't be "
+ "used with SET GLOBAL"),
ERR_GLOBAL_VARIABLE(1229, new byte[]{'H', 'Y', '0', '0', '0'}, "Variable
'%s' is a GLOBAL variable and should be "
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
index 54130a5d450..1c4a16c0728 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
@@ -70,6 +70,10 @@ public enum Privilege {
SHOW_VIEW_PRIV
};
+ public static final Privilege[] notBelongToTablePrivileges = {
+ USAGE_PRIV
+ };
+
public static Map<Privilege, String> privInDorisToMysql =
ImmutableMap.<Privilege, String>builder() // No NODE_PRIV and
ADMIN_PRIV in the mysql
.put(SELECT_PRIV, "SELECT")
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/CatalogMgrTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/CatalogMgrTest.java
index 5faa9952b95..4f68c952145 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/datasource/CatalogMgrTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/CatalogMgrTest.java
@@ -366,10 +366,6 @@ public class CatalogMgrTest extends TestWithFeService {
SwitchStmt switchHive = (SwitchStmt) parseAndAnalyzeStmt("switch
hive;", user2Ctx);
env.changeCatalog(user2Ctx, switchHive.getCatalogName());
Assert.assertEquals(user2Ctx.getDefaultCatalog(), "hive");
- // user2 can grant select_priv to tpch.customer
- GrantStmt user2GrantHiveTable = (GrantStmt) parseAndAnalyzeStmt(
- "grant select_priv on tpch.customer to 'user2'@'%';",
user2Ctx);
- auth.grant(user2GrantHiveTable);
showCatalogSql = "SHOW CATALOGS";
showStmt = (ShowCatalogStmt) parseAndAnalyzeStmt(showCatalogSql);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
index a96586c1fa9..f5f136e434c 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
@@ -1953,13 +1953,15 @@ public class AuthTest {
TablePattern tablePattern = new TablePattern("db1", "*");
GrantStmt grantStmt2 = new GrantStmt(userIdentity, null, tablePattern,
usagePrivileges);
ExceptionChecker.expectThrowsWithMsg(AnalysisException.class,
- "Can not grant/revoke USAGE_PRIV to/from database or table",
() -> grantStmt2.analyze(analyzer));
+ "Can not grant/revoke Usage_priv to/from any other users or
roles",
+ () -> grantStmt2.analyze(analyzer));
// 3. grant resource prov to role on db.table
tablePattern = new TablePattern("db1", "*");
GrantStmt grantStmt3 = new GrantStmt(userIdentity, "test_role",
tablePattern, usagePrivileges);
ExceptionChecker.expectThrowsWithMsg(AnalysisException.class,
- "Can not grant/revoke USAGE_PRIV to/from database or table",
() -> grantStmt3.analyze(analyzer));
+ "Can not grant/revoke Usage_priv to/from any other users or
roles",
+ () -> grantStmt3.analyze(analyzer));
// 4.drop user
dropUser(userIdentity);
@@ -2255,13 +2257,14 @@ public class AuthTest {
TablePattern tablePattern = new TablePattern("db1", "*");
GrantStmt grantStmt2 = new GrantStmt(userIdentity, null, tablePattern,
usagePrivileges);
ExceptionChecker.expectThrowsWithMsg(AnalysisException.class,
- "Can not grant/revoke USAGE_PRIV to/from database or table",
() -> grantStmt2.analyze(analyzer));
+ "Can not grant/revoke Usage_priv to/from any other users or
roles", () -> grantStmt2.analyze(analyzer));
// 3. grant workload group prov to role on db.table
tablePattern = new TablePattern("db1", "*");
GrantStmt grantStmt3 = new GrantStmt(userIdentity, "test_role",
tablePattern, usagePrivileges);
ExceptionChecker.expectThrowsWithMsg(AnalysisException.class,
- "Can not grant/revoke USAGE_PRIV to/from database or table",
() -> grantStmt3.analyze(analyzer));
+ "Can not grant/revoke Usage_priv to/from any other users or
roles", () -> grantStmt3.analyze(analyzer));
+
// 4.drop user
dropUser(userIdentity);
diff --git a/regression-test/suites/account_p0/test_grant_priv.groovy
b/regression-test/suites/account_p0/test_grant_priv.groovy
new file mode 100644
index 00000000000..abb95e9d122
--- /dev/null
+++ b/regression-test/suites/account_p0/test_grant_priv.groovy
@@ -0,0 +1,86 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_grant_priv") {
+ def user1 = 'test_grant_priv_user1'
+ def user2 = 'test_grant_priv_user2'
+ def role1 = 'test_grant_priv_role1'
+ def pwd = '123456'
+ def dbName = 'test_grant_priv_db'
+ def tokens = context.config.jdbcUrl.split('/')
+ def url=tokens[0] + "//" + tokens[2] + "/" + dbName + "?"
+
+ sql """drop user if exists ${user1}"""
+ sql """drop user if exists ${user2}"""
+ sql """drop role if exists ${role1}"""
+ sql """DROP DATABASE IF EXISTS ${dbName}"""
+
+ sql """CREATE DATABASE ${dbName}"""
+ sql """CREATE ROLE ${role1}"""
+ sql """CREATE USER '${user1}' IDENTIFIED BY '${pwd}'"""
+ sql """CREATE USER '${user2}' IDENTIFIED BY '${pwd}'"""
+
+ // test only have select_priv, can not grant to other user
+ sql """grant select_priv on ${dbName}.* to ${user1}"""
+ connect(user=user1, password="${pwd}", url=url) {
+ try {
+ sql """grant select_priv on ${dbName}.* to ${user2}"""
+ Assert.fail("can not grant to other user");
+ } catch (Exception e) {
+ log.info(e.getMessage())
+ }
+ }
+
+ // test both have select_priv and grant_priv , can grant to other user
+ sql """grant grant_priv on ${dbName}.* to ${user1}"""
+ connect(user=user1, password="${pwd}", url=url) {
+ try {
+ sql """grant select_priv on ${dbName}.* to ${user2}"""
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ // test have grant_priv,but not have load_priv, can not grant
load_priv to other user
+ try {
+ sql """grant load_priv on ${dbName}.* to ${user2}"""
+ Assert.fail("can not grant to other user");
+ } catch (Exception e) {
+ log.info(e.getMessage())
+ }
+ // test have grant_priv, can not grant role to other user
+ try {
+ sql """grant '${role1}' to ${user2}"""
+ Assert.fail("can not grant to other user");
+ } catch (Exception e) {
+ log.info(e.getMessage())
+ }
+ }
+
+ // test have global grant_priv, can grant role to other user
+ sql """grant grant_priv on *.* to ${user1}"""
+ try {
+ sql """grant '${role1}' to ${user2}"""
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+
+ sql """drop user if exists ${user1}"""
+ sql """drop user if exists ${user2}"""
+ sql """drop role if exists ${role1}"""
+ sql """DROP DATABASE IF EXISTS ${dbName}"""
+}
diff --git a/regression-test/suites/account_p0/test_grant_priv_resource.groovy
b/regression-test/suites/account_p0/test_grant_priv_resource.groovy
new file mode 100644
index 00000000000..f679835e1ca
--- /dev/null
+++ b/regression-test/suites/account_p0/test_grant_priv_resource.groovy
@@ -0,0 +1,57 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_grant_priv_resource") {
+ def user1 = 'test_grant_priv_resource_user1'
+ def user2 = 'test_grant_priv_resource_user2'
+ def pwd = '123456'
+ def resource1 = 'test_grant_priv_resource_resource1'
+ def tokens = context.config.jdbcUrl.split('/')
+ def url=tokens[0] + "//" + tokens[2] + "/" + "information_schema" + "?"
+
+ sql """drop user if exists ${user1}"""
+ sql """drop user if exists ${user2}"""
+
+ sql """CREATE USER '${user1}' IDENTIFIED BY '${pwd}'"""
+ sql """CREATE USER '${user2}' IDENTIFIED BY '${pwd}'"""
+
+ // test only have USAGE_PRIV, can not grant to other user
+ sql """grant USAGE_PRIV on RESOURCE ${resource1} to ${user1}"""
+ connect(user=user1, password="${pwd}", url=url) {
+ try {
+ sql """grant USAGE_PRIV on RESOURCE ${resource1} to ${user2}"""
+ Assert.fail("can not grant to other user");
+ } catch (Exception e) {
+ log.info(e.getMessage())
+ }
+ }
+
+ // test both have USAGE_PRIV and grant_priv , can grant to other user
+ sql """grant grant_priv on RESOURCE * to ${user1}"""
+ connect(user=user1, password="${pwd}", url=url) {
+ try {
+ sql """grant USAGE_PRIV on RESOURCE ${resource1} to ${user2}"""
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ sql """drop user if exists ${user1}"""
+ sql """drop user if exists ${user2}"""
+}
diff --git a/regression-test/suites/account_p0/test_grant_priv_workload.groovy
b/regression-test/suites/account_p0/test_grant_priv_workload.groovy
new file mode 100644
index 00000000000..291cfe1fa4c
--- /dev/null
+++ b/regression-test/suites/account_p0/test_grant_priv_workload.groovy
@@ -0,0 +1,57 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_grant_priv_workload") {
+ def user1 = 'test_grant_priv_workload_user1'
+ def user2 = 'test_grant_priv_workload_user2'
+ def pwd = '123456'
+ def workload1 = 'test_grant_priv_workload_workload1'
+ def tokens = context.config.jdbcUrl.split('/')
+ def url=tokens[0] + "//" + tokens[2] + "/" + "information_schema" + "?"
+
+ sql """drop user if exists ${user1}"""
+ sql """drop user if exists ${user2}"""
+
+ sql """CREATE USER '${user1}' IDENTIFIED BY '${pwd}'"""
+ sql """CREATE USER '${user2}' IDENTIFIED BY '${pwd}'"""
+
+ // test only have USAGE_PRIV, can not grant to other user
+ sql """grant USAGE_PRIV on WORKLOAD GROUP ${workload1} to ${user1}"""
+ connect(user=user1, password="${pwd}", url=url) {
+ try {
+ sql """grant USAGE_PRIV on WORKLOAD GROUP ${workload1} to
${user2}"""
+ Assert.fail("can not grant to other user");
+ } catch (Exception e) {
+ log.info(e.getMessage())
+ }
+ }
+
+ // test both have USAGE_PRIV and grant_priv , can grant to other user
+ sql """grant grant_priv on WORKLOAD GROUP ${workload1} to ${user1}"""
+ connect(user=user1, password="${pwd}", url=url) {
+ try {
+ sql """grant USAGE_PRIV on WORKLOAD GROUP ${workload1} to
${user2}"""
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ sql """drop user if exists ${user1}"""
+ sql """drop user if exists ${user2}"""
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]