branch-2.1:[fix](auth)fix when authentication, the permissions of multiple roles should be merged #52349 (#52947)

pick #52349
This commit is contained in:
zhangdong
2025-07-24 17:06:32 +08:00
committed by GitHub
parent d316dbb3bd
commit 5873aa3083
4 changed files with 63 additions and 58 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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}"""
}