This is an automated email from the ASF dual-hosted git repository. yiguolei 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 5873aa3083e branch-2.1:[fix](auth)fix when authentication, the permissions of multiple roles should be merged #52349 (#52947) 5873aa3083e is described below commit 5873aa3083ec2df336a7e1e7f048838f873a2e6c Author: zhangdong <zhangd...@selectdb.com> AuthorDate: Thu Jul 24 17:06:32 2025 +0800 branch-2.1:[fix](auth)fix when authentication, the permissions of multiple roles should be merged #52349 (#52947) pick #52349 --- .../org/apache/doris/mysql/privilege/Auth.java | 41 ++++++++-------------- .../org/apache/doris/mysql/privilege/Role.java | 40 ++++++--------------- .../apache/doris/mysql/privilege/RoleManager.java | 2 +- .../suites/account_p0/test_grant_priv.groovy | 38 ++++++++++++++++++++ 4 files changed, 63 insertions(+), 58 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java index 3d528db72f5..1ab3657a29d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java @@ -266,8 +266,9 @@ public class Auth implements Writable { readLock(); try { Set<Role> roles = getRolesByUserWithLdap(currentUser); + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkGlobalPriv(wanted)) { + if (role.checkGlobalPriv(wanted, savedPrivs)) { return true; } } @@ -289,8 +290,9 @@ public class Auth implements Writable { readLock(); try { Set<Role> roles = getRolesByUserWithLdap(currentUser); + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkCtlPriv(ctl, wanted)) { + if (role.checkCtlPriv(ctl, wanted, savedPrivs)) { return true; } } @@ -312,8 +314,9 @@ public class Auth implements Writable { readLock(); try { Set<Role> roles = getRolesByUserWithLdap(currentUser); + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkDbPriv(ctl, db, wanted)) { + if (role.checkDbPriv(ctl, db, wanted, savedPrivs)) { return true; } } @@ -335,8 +338,9 @@ public class Auth implements Writable { readLock(); try { Set<Role> roles = getRolesByUserWithLdap(currentUser); + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkTblPriv(ctl, db, tbl, wanted)) { + if (role.checkTblPriv(ctl, db, tbl, wanted, savedPrivs)) { return true; } } @@ -363,8 +367,9 @@ public class Auth implements Writable { private boolean checkColPriv(String ctl, String db, String tbl, String col, PrivPredicate wanted, Set<Role> roles) { + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkColPriv(ctl, db, tbl, col, wanted)) { + if (role.checkColPriv(ctl, db, tbl, col, wanted, savedPrivs)) { return true; } } @@ -376,8 +381,9 @@ public class Auth implements Writable { readLock(); try { Set<Role> roles = getRolesByUserWithLdap(currentUser); + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkResourcePriv(resourceName, wanted)) { + if (role.checkResourcePriv(resourceName, wanted, savedPrivs)) { return true; } } @@ -398,28 +404,9 @@ public class Auth implements Writable { } Set<Role> roles = getRolesByUserWithLdap(currentUser); + PrivBitSet savedPrivs = PrivBitSet.of(); for (Role role : roles) { - if (role.checkWorkloadGroupPriv(workloadGroupName, wanted)) { - return true; - } - } - return false; - } finally { - readUnlock(); - } - } - - // ==== Other ==== - /* - * Check if current user has certain privilege. - * This method will check the given privilege levels - */ - public boolean checkHasPriv(ConnectContext ctx, PrivPredicate priv, PrivLevel... levels) { - readLock(); - try { - Set<Role> roles = getRolesByUserWithLdap(ctx.getCurrentUserIdentity()); - for (Role role : roles) { - if (role.checkHasPriv(priv, levels)) { + if (role.checkWorkloadGroupPriv(workloadGroupName, wanted, savedPrivs)) { return true; } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Role.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Role.java index e4a68be4492..2bcf190556f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Role.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Role.java @@ -235,13 +235,11 @@ public class Role implements Writable, GsonPostProcessable { mergeNotCheck(other); } - public boolean checkGlobalPriv(PrivPredicate wanted) { - PrivBitSet savedPrivs = PrivBitSet.of(); + public boolean checkGlobalPriv(PrivPredicate wanted, PrivBitSet savedPrivs) { return checkGlobalInternal(wanted, savedPrivs); } - public boolean checkCtlPriv(String ctl, PrivPredicate wanted) { - PrivBitSet savedPrivs = PrivBitSet.of(); + public boolean checkCtlPriv(String ctl, PrivPredicate wanted, PrivBitSet savedPrivs) { if (checkGlobalInternal(wanted, savedPrivs) || checkCatalogInternal(ctl, wanted, savedPrivs)) { return true; @@ -285,8 +283,7 @@ public class Role implements Writable, GsonPostProcessable { return false; } - public boolean checkDbPriv(String ctl, String db, PrivPredicate wanted) { - PrivBitSet savedPrivs = PrivBitSet.of(); + public boolean checkDbPriv(String ctl, String db, PrivPredicate wanted, PrivBitSet savedPrivs) { if (checkGlobalInternal(wanted, savedPrivs) || checkCatalogInternal(ctl, wanted, savedPrivs) || checkDbInternal(ctl, db, wanted, savedPrivs)) { @@ -357,8 +354,7 @@ public class Role implements Writable, GsonPostProcessable { return false; } - public boolean checkTblPriv(String ctl, String db, String tbl, PrivPredicate wanted) { - PrivBitSet savedPrivs = PrivBitSet.of(); + public boolean checkTblPriv(String ctl, String db, String tbl, PrivPredicate wanted, PrivBitSet savedPrivs) { if (checkGlobalInternal(wanted, savedPrivs) || checkCatalogInternal(ctl, wanted, savedPrivs) || checkDbInternal(ctl, db, wanted, savedPrivs) @@ -378,12 +374,14 @@ public class Role implements Writable, GsonPostProcessable { return false; } - public boolean checkColPriv(String ctl, String db, String tbl, String col, PrivPredicate wanted) { + public boolean checkColPriv(String ctl, String db, String tbl, String col, PrivPredicate wanted, + PrivBitSet savedPrivs) { Optional<Privilege> colPrivilege = wanted.getColPrivilege(); if (!colPrivilege.isPresent()) { throw new IllegalStateException("this privPredicate should not use checkColPriv:" + wanted); } - return checkTblPriv(ctl, db, tbl, wanted) || onlyCheckColPriv(ctl, db, tbl, col, colPrivilege.get()); + return checkTblPriv(ctl, db, tbl, wanted, savedPrivs) || onlyCheckColPriv(ctl, db, tbl, col, + colPrivilege.get()); } private boolean onlyCheckColPriv(String ctl, String db, String tbl, String col, @@ -400,8 +398,7 @@ public class Role implements Writable, GsonPostProcessable { return Privilege.satisfy(savedPrivs, wanted); } - public boolean checkResourcePriv(String resourceName, PrivPredicate wanted) { - PrivBitSet savedPrivs = PrivBitSet.of(); + public boolean checkResourcePriv(String resourceName, PrivPredicate wanted, PrivBitSet savedPrivs) { if (checkGlobalInternal(wanted, savedPrivs) || checkResourceInternal(resourceName, wanted, savedPrivs)) { return true; @@ -418,12 +415,11 @@ public class Role implements Writable, GsonPostProcessable { return Privilege.satisfy(savedPrivs, wanted); } - public boolean checkWorkloadGroupPriv(String workloadGroupName, PrivPredicate wanted) { + public boolean checkWorkloadGroupPriv(String workloadGroupName, PrivPredicate wanted, PrivBitSet savedPrivs) { // For compatibility with older versions, it is not needed to check the privileges of the default group. if (WorkloadGroupMgr.DEFAULT_GROUP_NAME.equals(workloadGroupName)) { return true; } - PrivBitSet savedPrivs = PrivBitSet.of(); // usage priv not in global, but grant_priv may in global if (checkGlobalInternal(wanted, savedPrivs) || checkWorkloadGroupInternal(workloadGroupName, wanted, savedPrivs)) { @@ -502,22 +498,6 @@ public class Role implements Writable, GsonPostProcessable { this.comment = comment; } - public boolean checkCanEnterCluster(String clusterName) { - if (checkGlobalPriv(PrivPredicate.ALL)) { - return true; - } - - if (dbPrivTable.hasClusterPriv(clusterName)) { - return true; - } - - if (tablePrivTable.hasClusterPriv(clusterName)) { - return true; - } - return false; - } - - private void grantPrivs(ResourcePattern resourcePattern, PrivBitSet privs) throws DdlException { if (privs.isEmpty()) { return; diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java index 5ce213e2957..d647a7d3d99 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java @@ -198,7 +198,7 @@ public class RoleManager implements Writable, GsonPostProcessable { if (limitedRole != null && !limitedRole.contains(role.getRoleName())) { continue; } - String isGrantable = role.checkGlobalPriv(PrivPredicate.ADMIN) ? "YES" : "NO"; + String isGrantable = role.checkGlobalPriv(PrivPredicate.ADMIN, PrivBitSet.of()) ? "YES" : "NO"; for (Map.Entry<WorkloadGroupPattern, PrivBitSet> entry : role.getWorkloadGroupPatternToPrivs().entrySet()) { List<String> row = Lists.newArrayList(); diff --git a/regression-test/suites/account_p0/test_grant_priv.groovy b/regression-test/suites/account_p0/test_grant_priv.groovy index d2e04945905..ef0dda3a07a 100644 --- a/regression-test/suites/account_p0/test_grant_priv.groovy +++ b/regression-test/suites/account_p0/test_grant_priv.groovy @@ -21,6 +21,7 @@ suite("test_grant_priv") { def user1 = 'test_grant_priv_user1' def user2 = 'test_grant_priv_user2' def role1 = 'test_grant_priv_role1' + def role2 = 'test_grant_priv_role2' def pwd = '123456' def dbName = 'test_grant_priv_db' def tokens = context.config.jdbcUrl.split('/') @@ -29,6 +30,7 @@ suite("test_grant_priv") { sql """drop user if exists ${user1}""" sql """drop user if exists ${user2}""" sql """drop role if exists ${role1}""" + sql """drop role if exists ${role2}""" sql """DROP DATABASE IF EXISTS ${dbName}""" sql """CREATE DATABASE ${dbName}""" @@ -82,5 +84,41 @@ suite("test_grant_priv") { sql """drop user if exists ${user1}""" sql """drop user if exists ${user2}""" sql """drop role if exists ${role1}""" + sql """drop role if exists ${role2}""" + + sql """CREATE ROLE ${role1}""" + sql """CREATE ROLE ${role2}""" + sql """CREATE USER '${user1}' IDENTIFIED BY '${pwd}'""" + // for login + sql """grant select_priv on ${dbName}.* to ${user1}""" + sql """CREATE USER '${user2}' IDENTIFIED BY '${pwd}'""" + sql """grant grant_priv on *.*.* to role '${role1}'""" + sql """grant select_priv on *.*.* to role '${role2}'""" + sql """grant '${role1}' to ${user1}""" + // test only have role1 can not grant + connect(user1, "${pwd}", url) { + test { + sql """grant select_priv on *.*.* to ${user2}""" + exception "denied" + } + } + sql """revoke '${role1}' from ${user1}""" + sql """grant '${role2}' to ${user1}""" + // test only have role2 can not grant + connect(user1, "${pwd}", url) { + test { + sql """grant select_priv on *.*.* to ${user2}""" + exception "denied" + } + } + // test both have role1 and role2 can grant to other + sql """grant '${role1}' to ${user1}""" + connect(user1, "${pwd}", url) { + sql """grant select_priv on *.*.* to ${user2}""" + } + sql """drop user if exists ${user1}""" + sql """drop user if exists ${user2}""" + sql """drop role if exists ${role1}""" + sql """drop role if exists ${role2}""" sql """DROP DATABASE IF EXISTS ${dbName}""" } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org