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

Reply via email to