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 ae033a6ff39244..32cfdc9fddbef3 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; @@ -25,6 +26,7 @@ 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; @@ -34,11 +36,13 @@ 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; @@ -57,11 +61,11 @@ public class GrantStmt extends DdlStmt { private ResourcePattern resourcePattern; private WorkloadGroupPattern workloadGroupPattern; private Set privileges = Sets.newHashSet(); - //Privilege,ctl,db,table -> cols + // Privilege,ctl,db,table -> cols private Map> colPrivileges = Maps.newHashMap(); // Indicates that these roles are granted to a user private List 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 accessPrivileges; @@ -87,7 +91,7 @@ public GrantStmt(List roles, UserIdentity userIdent) { private GrantStmt(UserIdentity userIdent, String role, TablePattern tblPattern, ResourcePattern resourcePattern, WorkloadGroupPattern workloadGroupPattern, List accessPrivileges, - ResourceTypeEnum type) { + ResourceTypeEnum type) { this.userIdent = userIdent; this.role = role; this.tblPattern = tblPattern; @@ -175,12 +179,12 @@ public void analyze(Analyzer analyzer) throws UserException { } if (tblPattern != null) { - checkTablePrivileges(privileges, role, tblPattern, colPrivileges); + checkTablePrivileges(privileges, tblPattern, colPrivileges); } else if (resourcePattern != null) { privileges = PrivBitSet.convertResourcePrivToCloudPriv(resourcePattern, privileges); - checkResourcePrivileges(privileges, role, resourcePattern); + checkResourcePrivileges(privileges, resourcePattern); } else if (workloadGroupPattern != null) { - checkWorkloadGroupPrivileges(privileges, role, workloadGroupPattern); + checkWorkloadGroupPrivileges(privileges, workloadGroupPattern); } else if (roles != null) { checkRolePrivileges(); } @@ -199,142 +203,132 @@ public static void checkAccessPrivileges( /** * 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 privileges, String role, TablePattern tblPattern, + public static void checkTablePrivileges(Collection privileges, TablePattern tblPattern, Map> 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) || privileges.contains(Privilege.CLUSTER_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 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 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])); } } + } + + private static PrivPredicate getPrivPredicate(Collection privileges) { + ArrayList 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); - 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 (resourcePattern.isGeneralResource()) { - if (!Env.getCurrentEnv().getAccessManager().checkResourcePriv(ConnectContext.get(), - resourcePattern.getResourceName(), PrivPredicate.GRANT)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT/ROVOKE"); - } - } else if (resourcePattern.isClusterResource()) { - if (!Env.getCurrentEnv().getAccessManager() - .checkCloudPriv(ConnectContext.get(), - resourcePattern.getResourceName(), PrivPredicate.GRANT, ResourceTypeEnum.CLUSTER)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT/ROVOKE"); - } - } - } } } - public static void checkWorkloadGroupPrivileges(Collection 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 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"); + } + + private static boolean checkResourcePriv(ConnectContext ctx, ResourcePattern resourcePattern, + PrivPredicate privPredicate) { + if (resourcePattern.getPrivLevel() == PrivLevel.GLOBAL) { + return Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx, privPredicate); + } else { + if (resourcePattern.isGeneralResource()) { + return Env.getCurrentEnv().getAccessManager() + .checkResourcePriv(ctx, resourcePattern.getResourceName(), privPredicate); + } else if (resourcePattern.isClusterResource()) { + return Env.getCurrentEnv().getAccessManager() + .checkCloudPriv(ctx, resourcePattern.getResourceName(), privPredicate, + ResourceTypeEnum.CLUSTER); } - } else if (!Env.getCurrentEnv().getAccessManager().checkWorkloadGroupPriv(ConnectContext.get(), - workloadGroupPattern.getworkloadGroupName(), PrivPredicate.GRANT)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT/ROVOKE"); + } + return true; + } + + public static void checkWorkloadGroupPrivileges(Collection 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 cbd5e0a83efe16..08aa9675065b17 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 @@ -157,12 +157,12 @@ public void analyze(Analyzer analyzer) throws AnalysisException { // 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) { privileges = PrivBitSet.convertResourcePrivToCloudPriv(resourcePattern, privileges); - 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 183c733097be0f..c5841f571b4752 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 @@ -74,6 +74,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 75309c4d953ea7..f9929a8d523a81 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 @@ -98,6 +98,12 @@ public enum Privilege { SHOW_VIEW_PRIV, }; + public static final Privilege[] notBelongToTablePrivileges = { + USAGE_PRIV, + CLUSTER_USAGE_PRIV, + STAGE_USAGE_PRIV, + }; + public static final Map privInDorisToMysql = ImmutableMap.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 2184e2ab37fda1..f5750d8a9fef4e 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 @@ -365,10 +365,6 @@ public void testSwitchCommand() throws Exception { 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 ffd5e21ca96228..93cd60ab778783 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 @@ -1957,13 +1957,15 @@ public void testResource() throws UserException { 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); @@ -2259,13 +2261,14 @@ public void testWorkloadGroupPriv() throws UserException { 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 00000000000000..abb95e9d1228aa --- /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 00000000000000..f679835e1ca96e --- /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 00000000000000..291cfe1fa4cd02 --- /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}""" +}