[Enhancement] Implement grant and revoke role functionality for external groups (#63258)

What I'm doing:
This pull request adds support for granting and revoking roles to user groups in the authorization system. It introduces new methods and data structures to manage the mapping between groups and roles, ensures persistence and replay of these operations, and updates the privilege loading logic to include group-based roles. The changes also update relevant SQL analyzers and statement visitors to handle group-related role grants and revokes.

Group-to-Role Grant/Revoke Functionality:

Added a new groupToRoleList map in AuthorizationMgr to track which roles are assigned to each group, along with methods to grant and revoke roles for groups (grantRoleToGroup, revokeRoleFromGroup, and their replay counterparts). These actions are now handled in the main grantRole and revokeRole methods. [1] [2] [3] [4] [5]
Introduced the UpdateGroupToRoleLog class to persist group-to-role assignments and removals, and added new operation types (OP_GRANT_ROLE_TO_GROUP, OP_REVOKE_ROLE_FROM_GROUP) for edit log handling. [1] [2]
Updated the edit log and deserialization logic to support the new group-to-role operations, ensuring they are correctly replayed during recovery. [1] [2] [3]
Privilege Resolution and Query Enhancements:

Modified privilege collection loading to include roles assigned via group membership, so users gain the union of their direct and group-based roles. [1] [2]
Added methods to query roles assigned to a group, both by role ID and by role name, for use in privilege checks and metadata queries. [1] [2]
SQL Analyzer and Visitor Updates:

Updated the SQL analyzer and statement visitor logic to support group-based role grants and revokes, ensuring correct validation and privilege checks for group operations. [1] [2] [3] [4]
Persistence and Initialization:

Ensured that the groupToRoleList map is persisted and restored during authorization manager state load, maintaining group-role relationships across restarts.
These changes collectively enable group-based role management, improving flexibility and scalability of privilege assignment in the system.
This commit is contained in:
Harbor Liu 2025-09-22 14:56:37 +08:00 committed by GitHub
parent ce6b0525c6
commit 0bbbae8cef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 873 additions and 28 deletions

View File

@ -29,7 +29,9 @@ import com.starrocks.common.Config;
import com.starrocks.common.DdlException;
import com.starrocks.common.FeConstants;
import com.starrocks.persist.ImageWriter;
import com.starrocks.persist.OperationType;
import com.starrocks.persist.RolePrivilegeCollectionInfo;
import com.starrocks.persist.UpdateGroupToRoleLog;
import com.starrocks.persist.metablock.MapEntryConsumer;
import com.starrocks.persist.metablock.SRMetaBlockEOFException;
import com.starrocks.persist.metablock.SRMetaBlockException;
@ -84,6 +86,9 @@ public class AuthorizationMgr {
protected Map<UserIdentity, UserPrivilegeCollectionV2> userToPrivilegeCollection;
protected Map<Long, RolePrivilegeCollectionV2> roleIdToPrivilegeCollection;
@SerializedName(value = "gr")
private Map<String, Set<Long>> groupToRoleList;
private static final int MAX_NUM_CACHED_MERGED_PRIVILEGE_COLLECTION = 1000;
private static final int CACHED_MERGED_PRIVILEGE_COLLECTION_EXPIRE_MIN = 60;
protected LoadingCache<UserPrivKey, PrivilegeCollectionV2> ctxToMergedPrivilegeCollections =
@ -137,6 +142,7 @@ public class AuthorizationMgr {
roleNameToId = new HashMap<>();
userToPrivilegeCollection = new HashMap<>();
roleIdToPrivilegeCollection = new HashMap<>();
groupToRoleList = new HashMap<>();
userLock = new ReentrantReadWriteLock();
roleLock = new ReentrantReadWriteLock();
}
@ -150,6 +156,7 @@ public class AuthorizationMgr {
roleLock = new ReentrantReadWriteLock();
userToPrivilegeCollection = new HashMap<>();
roleIdToPrivilegeCollection = new HashMap<>();
groupToRoleList = new HashMap<>();
initBuiltinRolesAndUsers();
}
@ -525,6 +532,7 @@ public class AuthorizationMgr {
try {
switch (stmt.getGrantType()) {
case USER -> grantRoleToUser(stmt.getGranteeRole(), stmt.getUser());
case GROUP -> grantRoleToGroup(stmt.getGranteeRole(), stmt.getRoleOrGroup());
case ROLE -> grantRoleToRole(stmt.getGranteeRole(), stmt.getRoleOrGroup());
}
} catch (PrivilegeException e) {
@ -581,6 +589,43 @@ public class AuthorizationMgr {
}
}
protected void grantRoleToGroup(List<String> parentRoleName, String groupName) throws PrivilegeException {
lockForRoleUpdate();
List<Long> roleIdList = Lists.newArrayList();
try {
for (String role : parentRoleName) {
Long roleId = getRoleIdByNameAllowNull(role);
if (roleId == null) {
throw new PrivilegeException("role name '" + role + "' not found");
}
groupToRoleList.putIfAbsent(groupName, new HashSet<>());
Set<Long> roleSet = groupToRoleList.get(groupName);
roleSet.add(roleId);
roleIdList.add(roleId);
}
} finally {
unlockForRoleUpdate();
}
UpdateGroupToRoleLog log = new UpdateGroupToRoleLog(groupName, roleIdList);
GlobalStateMgr.getCurrentState().getEditLog().logJsonObject(OperationType.OP_GRANT_ROLE_TO_GROUP, log);
}
public void replayGrantRoleToGroup(List<Long> roleIdList, String groupName) {
lockForRoleUpdate();
try {
for (Long roleId : roleIdList) {
groupToRoleList.putIfAbsent(groupName, new HashSet<>());
Set<Long> roleSet = groupToRoleList.get(groupName);
roleSet.add(roleId);
}
} finally {
unlockForRoleUpdate();
}
}
protected void grantRoleToRole(List<String> parentRoleName, String roleName) throws PrivilegeException {
try {
lockForRoleUpdate();
@ -659,6 +704,7 @@ public class AuthorizationMgr {
try {
switch (stmt.getGrantType()) {
case USER -> revokeRoleFromUser(stmt.getGranteeRole(), stmt.getUser());
case GROUP -> revokeRoleFromGroup(stmt.getGranteeRole(), stmt.getRoleOrGroup());
case ROLE -> revokeRoleFromRole(stmt.getGranteeRole(), stmt.getRoleOrGroup());
}
} catch (PrivilegeException e) {
@ -695,6 +741,45 @@ public class AuthorizationMgr {
}
}
protected void revokeRoleFromGroup(List<String> parentRoleNameList, String groupName) throws PrivilegeException {
lockForRoleUpdate();
List<Long> roleIdList = Lists.newArrayList();
try {
for (String role : parentRoleNameList) {
Long roleId = getRoleIdByNameAllowNull(role);
if (roleId == null) {
throw new PrivilegeException("role name '" + role + "' not found");
}
Set<Long> roleSet = groupToRoleList.get(groupName);
if (roleSet != null) {
roleSet.remove(roleId);
}
roleIdList.add(roleId);
}
} finally {
unlockForRoleUpdate();
}
UpdateGroupToRoleLog log = new UpdateGroupToRoleLog(groupName, roleIdList);
GlobalStateMgr.getCurrentState().getEditLog().logJsonObject(OperationType.OP_REVOKE_ROLE_FROM_GROUP, log);
}
public void replayRevokeRoleFromGroup(List<Long> roleIdList, String groupName) {
lockForRoleUpdate();
try {
for (Long roleId : roleIdList) {
Set<Long> roleSet = groupToRoleList.get(groupName);
if (roleSet != null) {
roleSet.remove(roleId);
}
}
} finally {
unlockForRoleUpdate();
}
}
protected void revokeRoleFromRole(List<String> parentRoleNameList, String roleName) throws PrivilegeException {
try {
lockForRoleUpdate();
@ -761,8 +846,13 @@ public class AuthorizationMgr {
}
}
public List<String> getGranteeRoleForGroup(String groupName) {
return List.of();
public Set<Long> getRoleIdListByGroup(String groupName) {
roleReadLock();
try {
return groupToRoleList.getOrDefault(groupName, Set.of());
} finally {
roleReadUnlock();
}
}
protected boolean checkAction(PrivilegeCollectionV2 collection, ObjectType objectType,
@ -892,6 +982,7 @@ public class AuthorizationMgr {
try {
userReadLock();
Set<Long> validRoleIds;
if (userIdentity.isEphemeral()) {
Preconditions.checkState(roleIdsSpecified != null,
"ephemeral use should always have current role ids specified");
@ -909,6 +1000,10 @@ public class AuthorizationMgr {
}
}
for (String group : groups) {
validRoleIds.addAll(getRoleIdListByGroup(group));
}
try {
roleReadLock();
// 2. Get all predecessors base on step 1
@ -1114,6 +1209,30 @@ public class AuthorizationMgr {
}
}
public List<String> getGranteeRoleForGroup(String groupName) {
roleReadLock();
try {
Set<Long> roleIds = getRoleIdListByGroup(groupName);
List<String> parentRoleNameList = new ArrayList<>();
for (Long parentRoleId : roleIds) {
// Because the drop role is an asynchronous behavior, the parentRole may not exist.
// Here, for the role that does not exist, choose to ignore it directly
RolePrivilegeCollectionV2 parentRolePriv =
getRolePrivilegeCollectionUnlocked(parentRoleId, false);
if (parentRolePriv != null) {
parentRoleNameList.add(parentRolePriv.getName());
}
}
return parentRoleNameList;
} catch (PrivilegeException e) {
throw new SemanticException(e.getMessage());
} finally {
roleReadUnlock();
}
}
public Map<ObjectType, List<PrivilegeEntry>> getTypeToPrivilegeEntryListByRole(String roleName) {
roleReadLock();
try {
@ -1777,6 +1896,7 @@ public class AuthorizationMgr {
pluginVersion = ret.pluginVersion;
userToPrivilegeCollection = ret.userToPrivilegeCollection;
roleIdToPrivilegeCollection = ret.roleIdToPrivilegeCollection;
groupToRoleList = ret.groupToRoleList;
// Initialize the Authorizer class in advance during the loading phase
// to prevent loading errors and lack of permissions.

View File

@ -1071,6 +1071,17 @@ public class EditLog {
globalStateMgr.getAuthorizationMgr().replayUpdateRolePrivilegeCollection(info);
break;
}
case OperationType.OP_GRANT_ROLE_TO_GROUP: {
UpdateGroupToRoleLog log = (UpdateGroupToRoleLog) journal.data();
globalStateMgr.getAuthorizationMgr().replayGrantRoleToGroup(log.getRoleIdList(), log.getGroup());
break;
}
case OperationType.OP_REVOKE_ROLE_FROM_GROUP: {
UpdateGroupToRoleLog log = (UpdateGroupToRoleLog) journal.data();
globalStateMgr.getAuthorizationMgr().replayRevokeRoleFromGroup(log.getRoleIdList(), log.getGroup());
break;
}
case OperationType.OP_DROP_ROLE_V2: {
RolePrivilegeCollectionInfo info = (RolePrivilegeCollectionInfo) journal.data();
globalStateMgr.getAuthorizationMgr().replayDropRole(info);

View File

@ -230,6 +230,8 @@ public class EditLogDeserializer {
.put(OperationType.OP_UPDATE_USER_PRIVILEGE_V2, UserPrivilegeCollectionInfo.class)
.put(OperationType.OP_DROP_ROLE_V2, RolePrivilegeCollectionInfo.class)
.put(OperationType.OP_UPDATE_ROLE_PRIVILEGE_V2, RolePrivilegeCollectionInfo.class)
.put(OperationType.OP_GRANT_ROLE_TO_GROUP, UpdateGroupToRoleLog.class)
.put(OperationType.OP_REVOKE_ROLE_FROM_GROUP, UpdateGroupToRoleLog.class)
.put(OperationType.OP_MV_JOB_STATE, MVMaintenanceJob.class)
.put(OperationType.OP_MV_EPOCH_UPDATE, MVEpoch.class)
.put(OperationType.OP_MODIFY_TABLE_ADD_OR_DROP_COLUMNS, TableAddOrDropColumnsInfo.class)

View File

@ -669,6 +669,10 @@ public class OperationType {
public static final short OP_DROP_SECURITY_INTEGRATION = 20271;
public static final short OP_ALTER_SECURITY_INTEGRATION = 20272;
// Grant Role to Group
public static final short OP_GRANT_ROLE_TO_GROUP = 20501;
public static final short OP_REVOKE_ROLE_FROM_GROUP = 20502;
public static final ImmutableSet<Short> IGNORABLE_OPERATIONS = buildIgnorableOperations();
private static ImmutableSet<Short> buildIgnorableOperations() {
@ -694,7 +698,9 @@ public class OperationType {
opType != OP_WAREHOUSE_INTERNAL_OP &&
opType != OP_CREATE_SECURITY_INTEGRATION &&
opType != OP_DROP_SECURITY_INTEGRATION &&
opType != OP_ALTER_SECURITY_INTEGRATION) {
opType != OP_ALTER_SECURITY_INTEGRATION &&
opType != OP_GRANT_ROLE_TO_GROUP &&
opType != OP_REVOKE_ROLE_FROM_GROUP) {
LOG.fatal("OperationType cannot use a value exceeding 20000, " +
"and an error will be reported if it exceeds : {} = {}", field.getName(), opType);
System.exit(-1);

View File

@ -0,0 +1,41 @@
// Copyright 2021-present StarRocks, Inc. All rights reserved.
//
// Licensed 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
//
// https://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.
package com.starrocks.persist;
import com.google.gson.annotations.SerializedName;
import com.starrocks.common.io.Writable;
import java.util.List;
public class UpdateGroupToRoleLog implements Writable {
@SerializedName(value = "g")
private String group;
@SerializedName(value = "r")
private List<Long> roleIdList;
public UpdateGroupToRoleLog(String group, List<Long> roleIdList) {
this.group = group;
this.roleIdList = roleIdList;
}
public String getGroup() {
return group;
}
public List<Long> getRoleIdList() {
return roleIdList;
}
}

View File

@ -469,9 +469,26 @@ public class ConnectContext {
return accessControlContext.getCurrentRoleIds();
}
public void setCurrentRoleIds(Set<Long> roleIds) {
accessControlContext.setCurrentRoleIds(roleIds);
}
public void setCurrentRoleIds(UserIdentity user) {
Set<Long> roleIds = getRoleIdsByUser(user);
accessControlContext.setCurrentRoleIds(roleIds);
}
public void setCurrentRoleIds(UserIdentity userIdentity, Set<String> groups) {
Set<Long> roleIds = getRoleIdsByUser(userIdentity);
for (String group : groups) {
roleIds.addAll(globalStateMgr.getAuthorizationMgr().getRoleIdListByGroup(group));
}
setCurrentRoleIds(roleIds);
}
private Set<Long> getRoleIdsByUser(UserIdentity user) {
if (user.isEphemeral()) {
accessControlContext.setCurrentRoleIds(new HashSet<>());
return new HashSet<>();
} else {
try {
Set<Long> defaultRoleIds;
@ -480,21 +497,14 @@ public class ConnectContext {
} else {
defaultRoleIds = globalStateMgr.getAuthorizationMgr().getDefaultRoleIdsByUser(user);
}
accessControlContext.setCurrentRoleIds(defaultRoleIds);
return defaultRoleIds;
} catch (PrivilegeException e) {
LOG.warn("Set current role fail : {}", e.getMessage());
return new HashSet<>();
}
}
}
public void setCurrentRoleIds(UserIdentity userIdentity, Set<String> groups) {
setCurrentRoleIds(userIdentity);
}
public void setCurrentRoleIds(Set<Long> roleIds) {
accessControlContext.setCurrentRoleIds(roleIds);
}
public Set<String> getGroups() {
return accessControlContext.getGroups();
}

View File

@ -90,7 +90,7 @@ public class ExecuteAsExecutor {
ctx.setGroups(groups);
// Refresh current role IDs based on user + groups
ctx.setCurrentRoleIds(userIdentity);
ctx.setCurrentRoleIds(userIdentity, groups);
LOG.info("Refreshed groups {} and roles for user {}", groups, userIdentity);
} catch (Exception e) {

View File

@ -468,7 +468,7 @@ public class AuthorizationAnalyzer {
*/
@Override
public Void visitGrantRevokeRoleStatement(BaseGrantRevokeRoleStmt stmt, ConnectContext session) {
if (stmt.getUser() != null) {
if (stmt.getGrantType() == GrantType.USER) {
AuthenticationAnalyzer.analyzeUser(stmt.getUser());
AuthenticationAnalyzer.checkUserExist(stmt.getUser(), true);
if (AuthenticationAnalyzer.needProtectAdminUser(stmt.getUser(), session)) {
@ -477,10 +477,13 @@ public class AuthorizationAnalyzer {
}
stmt.getGranteeRole().forEach(role ->
validRoleName(role, "Can not granted/revoke role to/from user", true));
} else {
} else if (stmt.getGrantType() == GrantType.ROLE) {
validRoleName(stmt.getRoleOrGroup(), "Can not granted/revoke role to/from role", true);
stmt.getGranteeRole().forEach(role ->
validRoleName(role, "Can not granted/revoke role to/from user", true));
} else if (stmt.getGrantType() == GrantType.GROUP) {
stmt.getGranteeRole().forEach(role ->
validRoleName(role, "Can not granted/revoke role to/from user", true));
}
return null;
}

View File

@ -130,6 +130,7 @@ import com.starrocks.sql.ast.ExecuteScriptStmt;
import com.starrocks.sql.ast.ExportStmt;
import com.starrocks.sql.ast.FunctionRef;
import com.starrocks.sql.ast.GrantRoleStmt;
import com.starrocks.sql.ast.GrantType;
import com.starrocks.sql.ast.HintNode;
import com.starrocks.sql.ast.InsertStmt;
import com.starrocks.sql.ast.InstallPluginStmt;
@ -1427,19 +1428,22 @@ public class AuthorizerStmtVisitor implements AstVisitorExtendInterface<Void, Co
public Void visitShowGrantsStatement(ShowGrantsStmt statement, ConnectContext context) {
UserRef user = statement.getUser();
try {
// if user == null mean show current user grants
if (user != null) {
UserIdentity userIdentity = new UserIdentity(user.getUser(), user.getHost(), user.isDomain());
if (!userIdentity.equals(context.getCurrentUserIdentity())) {
Authorizer.checkSystemAction(context, PrivilegeType.GRANT);
}
} else if (statement.getGroupOrRole() != null) {
} else if (statement.getGrantType() == GrantType.ROLE) {
AuthorizationMgr authorizationManager = context.getGlobalStateMgr().getAuthorizationMgr();
Set<String> roleNames =
authorizationManager.getAllPredecessorRoleNamesByUser(context.getCurrentUserIdentity());
if (!roleNames.contains(statement.getGroupOrRole())) {
Authorizer.checkSystemAction(context,
PrivilegeType.GRANT);
Authorizer.checkSystemAction(context, PrivilegeType.GRANT);
}
} else if (statement.getGrantType() == GrantType.GROUP) {
Set<String> groups = context.getGroups();
if (groups == null || !groups.contains(statement.getGroupOrRole())) {
Authorizer.checkSystemAction(context, PrivilegeType.GRANT);
}
}
} catch (AccessDeniedException | PrivilegeException e) {

View File

@ -273,6 +273,8 @@ public class AST2StringVisitor implements AstVisitorExtendInterface<String, Void
if (statement.getGrantType().equals(GrantType.ROLE)) {
sqlBuilder.append("ROLE ").append(statement.getRoleOrGroup());
} else if (statement.getGrantType().equals(GrantType.GROUP)) {
sqlBuilder.append("EXTERNAL GROUP ").append(statement.getRoleOrGroup());
} else {
sqlBuilder.append(statement.getUser());
}

View File

@ -6754,6 +6754,18 @@ public class AstBuilder extends com.starrocks.sql.parser.StarRocksBaseVisitor<Pa
return new GrantRoleStmt(roleNameList, (UserRef) visit(context.user()), createPos(context));
}
@Override
public ParseNode visitGrantRoleToGroup(StarRocksParser.GrantRoleToGroupContext context) {
List<String> roleNameList = new ArrayList<>();
for (StarRocksParser.IdentifierOrStringContext oneContext : context.identifierOrStringList()
.identifierOrString()) {
roleNameList.add(((Identifier) visit(oneContext)).getValue());
}
return new GrantRoleStmt(roleNameList, ((Identifier) visit(context.identifierOrString())).getValue(),
GrantType.GROUP, createPos(context));
}
@Override
public ParseNode visitGrantRoleToRole(com.starrocks.sql.parser.StarRocksParser.GrantRoleToRoleContext context) {
List<String> roleNameList = new ArrayList<>();

View File

@ -26,6 +26,8 @@ import com.starrocks.server.GlobalStateMgr;
import com.starrocks.sql.ast.CreateRoleStmt;
import com.starrocks.sql.ast.CreateUserStmt;
import com.starrocks.sql.ast.ExecuteAsStmt;
import com.starrocks.sql.ast.GrantRoleStmt;
import com.starrocks.sql.ast.GrantType;
import com.starrocks.sql.ast.UserRef;
import com.starrocks.sql.parser.NodePosition;
import mockit.Mock;
@ -78,19 +80,20 @@ public class ExecuteAsExecutorTest {
LDAPGroupProvider ldapGroupProvider = (LDAPGroupProvider) authenticationMgr.getGroupProvider(groupName);
Map<String, Set<String>> groups = new HashMap<>();
groups.put("impersonate_user", Set.of("group1", "group2"));
groups.put("u1", Set.of("group3"));
groups.put("u2", Set.of("group4"));
groups.put("u1", Set.of("group1"));
groups.put("u2", Set.of("group2"));
groups.put("u3", Set.of("group1", "group2"));
ldapGroupProvider.setUserToGroupCache(groups);
}
@Test
public void testExecuteAs() throws Exception {
public void testExecuteAsGetGroups() throws Exception {
authorizationMgr.createRole(new CreateRoleStmt(List.of("r1"), true, ""));
authorizationMgr.createRole(new CreateRoleStmt(List.of("r2"), true, ""));
authenticationMgr.createUser(
new CreateUserStmt(new UserRef("impersonate_user", "%"), true, null, List.of(), Map.of(), NodePosition.ZERO));
new CreateUserStmt(new UserRef("impersonate_user", "%"), true, null, List.of(), Map.of(),
NodePosition.ZERO));
authenticationMgr.createUser(
new CreateUserStmt(new UserRef("u1", "%"), true, null, List.of("r1"), Map.of(), NodePosition.ZERO));
authenticationMgr.createUser(
@ -105,16 +108,68 @@ public class ExecuteAsExecutorTest {
AuthenticationHandler.authenticate(context, "impersonate_user", "%", MysqlPassword.EMPTY_PASSWORD);
Assertions.assertEquals("impersonate_user", context.getAccessControlContext().getQualifiedUser());
Assertions.assertEquals(Set.of("group1", "group2"), context.getGroups());
Assertions.assertEquals(Set.of(), context.getGroups());
ExecuteAsStmt executeAsStmt = new ExecuteAsStmt(new UserRef("u1", "%"), false);
ExecuteAsExecutor.execute(executeAsStmt, context);
Assertions.assertEquals(Set.of("group3"), context.getGroups());
Assertions.assertEquals(Set.of("group1"), context.getGroups());
Assertions.assertEquals(Set.of(roleId1), context.getCurrentRoleIds());
ExecuteAsStmt executeAsStmt2 = new ExecuteAsStmt(new UserRef("u2", "%"), false);
ExecuteAsExecutor.execute(executeAsStmt2, context);
Assertions.assertEquals(Set.of("group4"), context.getGroups());
Assertions.assertEquals(Set.of("group2"), context.getGroups());
Assertions.assertEquals(Set.of(roleId2), context.getCurrentRoleIds());
}
@Test
public void testExecuteAsGroupWithRoles() throws Exception {
authorizationMgr.createRole(new CreateRoleStmt(List.of("r1"), true, ""));
authorizationMgr.createRole(new CreateRoleStmt(List.of("r2"), true, ""));
authorizationMgr.createRole(new CreateRoleStmt(List.of("r3"), true, ""));
authenticationMgr.createUser(
new CreateUserStmt(new UserRef("impersonate_user", "%"), true, null, List.of(), Map.of(), NodePosition.ZERO));
authenticationMgr.createUser(
new CreateUserStmt(new UserRef("u1", "%"), true, null, List.of("r1"), Map.of(), NodePosition.ZERO));
authenticationMgr.createUser(
new CreateUserStmt(new UserRef("u2", "%"), true, null, List.of("r2"), Map.of(), NodePosition.ZERO));
authenticationMgr.createUser(
new CreateUserStmt(new UserRef("u3", "%"), true, null, List.of("r3"), Map.of(), NodePosition.ZERO));
long roleId1 = authorizationMgr.getRoleIdByNameAllowNull("r1");
long roleId2 = authorizationMgr.getRoleIdByNameAllowNull("r2");
long roleId3 = authorizationMgr.getRoleIdByNameAllowNull("r3");
authorizationMgr.grantRole(new GrantRoleStmt(List.of("r1"), "group1", GrantType.GROUP, NodePosition.ZERO));
authorizationMgr.grantRole(new GrantRoleStmt(List.of("r2"), "group2", GrantType.GROUP, NodePosition.ZERO));
// login as impersonate_user
ConnectContext context = new ConnectContext();
AuthenticationHandler.authenticate(context, "impersonate_user", "%", MysqlPassword.EMPTY_PASSWORD);
Assertions.assertEquals("impersonate_user", context.getAccessControlContext().getQualifiedUser());
Assertions.assertEquals(Set.of(), context.getGroups());
ExecuteAsStmt executeAsStmt = new ExecuteAsStmt(new UserRef("u1", "%"), false);
ExecuteAsExecutor.execute(executeAsStmt, context);
Assertions.assertEquals(Set.of("group1"), context.getGroups());
Assertions.assertEquals(Set.of(roleId1), context.getCurrentRoleIds());
ExecuteAsStmt executeAsStmt2 = new ExecuteAsStmt(new UserRef("u2", "%"), false);
ExecuteAsExecutor.execute(executeAsStmt2, context);
Assertions.assertEquals(Set.of("group2"), context.getGroups());
Assertions.assertEquals(Set.of(roleId2), context.getCurrentRoleIds());
ExecuteAsStmt executeAsStmt3 = new ExecuteAsStmt(new UserRef("u3", "%"), false);
ExecuteAsExecutor.execute(executeAsStmt3, context);
Assertions.assertEquals(Set.of("group1", "group2"), context.getGroups());
Assertions.assertEquals(Set.of(roleId1, roleId2, roleId3), context.getCurrentRoleIds());
ExecuteAsStmt executeAsStmt4 =
new ExecuteAsStmt(new UserRef("impersonate_user", "%", false, true, NodePosition.ZERO), false);
ExecuteAsExecutor.execute(executeAsStmt4, context);
Assertions.assertEquals(Set.of(), context.getGroups());
Assertions.assertEquals(Set.of(), context.getCurrentRoleIds());
}
}

View File

@ -0,0 +1,353 @@
// Copyright 2021-present StarRocks, Inc. All rights reserved.
//
// Licensed 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
//
// https://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.
package com.starrocks.authorization;
import com.starrocks.authentication.AuthenticationMgr;
import com.starrocks.catalog.UserIdentity;
import com.starrocks.common.ErrorReportException;
import com.starrocks.persist.EditLog;
import com.starrocks.persist.OperationType;
import com.starrocks.persist.UpdateGroupToRoleLog;
import com.starrocks.persist.gson.GsonUtils;
import com.starrocks.qe.ConnectContext;
import com.starrocks.qe.DDLStmtExecutor;
import com.starrocks.qe.ShowExecutor;
import com.starrocks.qe.ShowResultSet;
import com.starrocks.server.GlobalStateMgr;
import com.starrocks.sql.analyzer.Analyzer;
import com.starrocks.sql.analyzer.Authorizer;
import com.starrocks.sql.ast.CreateTableStmt;
import com.starrocks.sql.ast.CreateUserStmt;
import com.starrocks.sql.ast.GrantPrivilegeStmt;
import com.starrocks.sql.ast.GrantRoleStmt;
import com.starrocks.sql.ast.GrantType;
import com.starrocks.sql.ast.RevokeRoleStmt;
import com.starrocks.sql.ast.ShowGrantsStmt;
import com.starrocks.sql.ast.StatementBase;
import com.starrocks.sql.parser.NodePosition;
import com.starrocks.sql.parser.SqlParser;
import com.starrocks.transaction.MockedLocalMetaStore;
import com.starrocks.transaction.MockedMetadataMgr;
import com.starrocks.utframe.UtFrameUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyShort;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
public class GrantRoleToGroupTest {
@Test
public void testAlterAndDrop() throws Exception {
EditLog editLog = spy(new EditLog(null));
doNothing().when(editLog).logEdit(anyShort(), any());
GlobalStateMgr.getCurrentState().setEditLog(editLog);
ConnectContext ctx = new ConnectContext();
ctx.setGlobalStateMgr(GlobalStateMgr.getCurrentState());
AuthorizationMgr authorizationMgr = new AuthorizationMgr(new DefaultAuthorizationProvider());
GlobalStateMgr.getCurrentState().setAuthorizationMgr(authorizationMgr);
GlobalStateMgr.getCurrentState().setAuthenticationMgr(new AuthenticationMgr());
for (int i = 1; i <= 2; i++) {
String sql = "create role r" + i;
StatementBase stmt = UtFrameUtils.parseStmtWithNewParser(sql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
}
GrantRoleStmt grantRoleStmt;
grantRoleStmt = new GrantRoleStmt(List.of("r1", "r2"), "g1", GrantType.GROUP, NodePosition.ZERO);
Analyzer.analyze(grantRoleStmt, ctx);
authorizationMgr.grantRole(grantRoleStmt);
grantRoleStmt = new GrantRoleStmt(List.of("r1"), "g2", GrantType.GROUP, NodePosition.ZERO);
Analyzer.analyze(grantRoleStmt, ctx);
authorizationMgr.grantRole(grantRoleStmt);
Long r1Id = authorizationMgr.getRoleIdByNameAllowNull("r1");
Long r2Id = authorizationMgr.getRoleIdByNameAllowNull("r2");
Set<Long> roleIds = authorizationMgr.getRoleIdListByGroup("g1");
Assertions.assertEquals(2, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
Assertions.assertTrue(roleIds.contains(r2Id));
roleIds = authorizationMgr.getRoleIdListByGroup("g2");
Assertions.assertEquals(1, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
roleIds = authorizationMgr.getRoleIdListByGroup("g3");
Assertions.assertEquals(0, roleIds.size());
RevokeRoleStmt revokeRoleStmt;
revokeRoleStmt = new RevokeRoleStmt(List.of("r2"), "g1", GrantType.GROUP, NodePosition.ZERO);
Analyzer.analyze(grantRoleStmt, ctx);
authorizationMgr.revokeRole(revokeRoleStmt);
grantRoleStmt = new GrantRoleStmt(List.of("r1"), "g3", GrantType.GROUP, NodePosition.ZERO);
Analyzer.analyze(grantRoleStmt, ctx);
authorizationMgr.grantRole(grantRoleStmt);
roleIds = authorizationMgr.getRoleIdListByGroup("g1");
Assertions.assertEquals(1, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
roleIds = authorizationMgr.getRoleIdListByGroup("g2");
Assertions.assertEquals(1, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
roleIds = authorizationMgr.getRoleIdListByGroup("g3");
Assertions.assertTrue(roleIds.contains(r1Id));
Assertions.assertEquals(1, roleIds.size());
roleIds = authorizationMgr.getRoleIdListByGroup("g4");
Assertions.assertEquals(0, roleIds.size());
}
@Test
public void testSerDer() throws Exception {
EditLog editLog = spy(new EditLog(null));
doNothing().when(editLog).logEdit(anyShort(), any());
GlobalStateMgr.getCurrentState().setEditLog(editLog);
ConnectContext ctx = new ConnectContext();
ctx.setGlobalStateMgr(GlobalStateMgr.getCurrentState());
AuthorizationMgr authorizationMgr = new AuthorizationMgr(new DefaultAuthorizationProvider());
GlobalStateMgr.getCurrentState().setAuthorizationMgr(authorizationMgr);
GlobalStateMgr.getCurrentState().setAuthenticationMgr(new AuthenticationMgr());
for (int i = 1; i <= 3; i++) {
String sql = "create role r" + i;
StatementBase stmt = UtFrameUtils.parseStmtWithNewParser(sql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
}
GrantRoleStmt grantRoleStmt;
grantRoleStmt =
new GrantRoleStmt(List.of("r1", "r2", "r3"), "g1", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.grantRole(grantRoleStmt);
grantRoleStmt = new GrantRoleStmt(List.of("r1"), "g2", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.grantRole(grantRoleStmt);
RevokeRoleStmt revokeRoleStmt;
revokeRoleStmt = new RevokeRoleStmt(List.of("r3"), "g1", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.revokeRole(revokeRoleStmt);
String serialized = GsonUtils.GSON.toJson(authorizationMgr);
AuthorizationMgr newObject = GsonUtils.GSON.fromJson(serialized, AuthorizationMgr.class);
Long r1Id = authorizationMgr.getRoleIdByNameAllowNull("r1");
Long r2Id = authorizationMgr.getRoleIdByNameAllowNull("r2");
Set<Long> roleIds = newObject.getRoleIdListByGroup("g1");
Assertions.assertEquals(2, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
Assertions.assertTrue(roleIds.contains(r2Id));
roleIds = newObject.getRoleIdListByGroup("g2");
Assertions.assertEquals(1, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
roleIds = newObject.getRoleIdListByGroup("g3");
Assertions.assertEquals(0, roleIds.size());
}
@Test
public void testPersist() throws Exception {
UtFrameUtils.setUpForPersistTest();
ConnectContext ctx = new ConnectContext();
ctx.setGlobalStateMgr(GlobalStateMgr.getCurrentState());
AuthorizationMgr authorizationMgr = new AuthorizationMgr(new DefaultAuthorizationProvider());
GlobalStateMgr.getCurrentState().setAuthorizationMgr(authorizationMgr);
GlobalStateMgr.getCurrentState().setAuthenticationMgr(new AuthenticationMgr());
for (int i = 1; i <= 3; i++) {
String sql = "create role r" + i;
StatementBase stmt = UtFrameUtils.parseStmtWithNewParser(sql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
}
Long r1Id = authorizationMgr.getRoleIdByNameAllowNull("r1");
Long r2Id = authorizationMgr.getRoleIdByNameAllowNull("r2");
String serialized = GsonUtils.GSON.toJson(authorizationMgr);
GrantRoleStmt grantRoleStmt;
grantRoleStmt =
new GrantRoleStmt(List.of("r1", "r2", "r3"), "g1", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.grantRole(grantRoleStmt);
grantRoleStmt = new GrantRoleStmt(List.of("r1"), "g2", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.grantRole(grantRoleStmt);
RevokeRoleStmt revokeRoleStmt;
revokeRoleStmt = new RevokeRoleStmt(List.of("r3"), "g1", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.revokeRole(revokeRoleStmt);
AuthorizationMgr newObject = GsonUtils.GSON.fromJson(serialized, AuthorizationMgr.class);
Set<Long> roleIds = newObject.getRoleIdListByGroup("g1");
Assertions.assertEquals(0, roleIds.size());
roleIds = newObject.getRoleIdListByGroup("g2");
Assertions.assertEquals(0, roleIds.size());
roleIds = newObject.getRoleIdListByGroup("g3");
Assertions.assertEquals(0, roleIds.size());
UpdateGroupToRoleLog log1 = (UpdateGroupToRoleLog)
UtFrameUtils.PseudoJournalReplayer.replayNextJournal(OperationType.OP_GRANT_ROLE_TO_GROUP);
newObject.replayGrantRoleToGroup(log1.getRoleIdList(), log1.getGroup());
UpdateGroupToRoleLog log2 = (UpdateGroupToRoleLog)
UtFrameUtils.PseudoJournalReplayer.replayNextJournal(OperationType.OP_GRANT_ROLE_TO_GROUP);
newObject.replayGrantRoleToGroup(log2.getRoleIdList(), log2.getGroup());
UpdateGroupToRoleLog log3 = (UpdateGroupToRoleLog)
UtFrameUtils.PseudoJournalReplayer.replayNextJournal(OperationType.OP_REVOKE_ROLE_FROM_GROUP);
newObject.replayRevokeRoleFromGroup(log3.getRoleIdList(), log3.getGroup());
roleIds = newObject.getRoleIdListByGroup("g1");
Assertions.assertEquals(2, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
Assertions.assertTrue(roleIds.contains(r2Id));
roleIds = newObject.getRoleIdListByGroup("g2");
Assertions.assertEquals(1, roleIds.size());
Assertions.assertTrue(roleIds.contains(r1Id));
roleIds = newObject.getRoleIdListByGroup("g3");
Assertions.assertEquals(0, roleIds.size());
UtFrameUtils.tearDownForPersisTest();
}
@Test
public void testShowGrants() throws Exception {
EditLog editLog = spy(new EditLog(null));
doNothing().when(editLog).logEdit(anyShort(), any());
GlobalStateMgr.getCurrentState().setEditLog(editLog);
ConnectContext ctx = new ConnectContext();
ctx.setGlobalStateMgr(GlobalStateMgr.getCurrentState());
AuthorizationMgr authorizationMgr = new AuthorizationMgr(new DefaultAuthorizationProvider());
GlobalStateMgr.getCurrentState().setAuthorizationMgr(authorizationMgr);
GlobalStateMgr.getCurrentState().setAuthenticationMgr(new AuthenticationMgr());
for (int i = 1; i <= 3; i++) {
String sql = "create role r" + i;
StatementBase stmt = UtFrameUtils.parseStmtWithNewParser(sql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
}
GrantRoleStmt grantRoleStmt;
grantRoleStmt =
new GrantRoleStmt(List.of("r1", "r2", "r3"), "g1", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.grantRole(grantRoleStmt);
grantRoleStmt = new GrantRoleStmt(List.of("r1"), "g2", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.grantRole(grantRoleStmt);
RevokeRoleStmt revokeRoleStmt;
revokeRoleStmt = new RevokeRoleStmt(List.of("r3"), "g1", GrantType.GROUP, NodePosition.ZERO);
authorizationMgr.revokeRole(revokeRoleStmt);
ShowGrantsStmt stmt = new ShowGrantsStmt("g1", GrantType.GROUP, NodePosition.ZERO);
Analyzer.analyze(stmt, ctx);
ShowResultSet showResultSet = ShowExecutor.execute(stmt, ctx);
Assertions.assertEquals("[[g1, null, GRANT 'r1', 'r2' TO EXTERNAL GROUP g1]]", showResultSet.getResultRows().toString());
stmt = new ShowGrantsStmt("g2", GrantType.GROUP, NodePosition.ZERO);
showResultSet = ShowExecutor.execute(stmt, ctx);
Assertions.assertEquals("[[g2, null, GRANT 'r1' TO EXTERNAL GROUP g2]]", showResultSet.getResultRows().toString());
}
@Test
public void testPrivilege() throws Exception {
GlobalStateMgr globalStateMgr = GlobalStateMgr.getCurrentState();
EditLog editLog = spy(new EditLog(null));
doNothing().when(editLog).logEdit(anyShort(), any());
GlobalStateMgr.getCurrentState().setEditLog(editLog);
ConnectContext ctx = new ConnectContext();
ctx.setThreadLocalInfo();
ctx.setGlobalStateMgr(GlobalStateMgr.getCurrentState());
MockedLocalMetaStore
localMetastore = new MockedLocalMetaStore(globalStateMgr, globalStateMgr.getRecycleBin(), null);
globalStateMgr.setLocalMetastore(localMetastore);
MockedMetadataMgr mockedMetadataMgr = new MockedMetadataMgr(localMetastore, globalStateMgr.getConnectorMgr());
globalStateMgr.setMetadataMgr(mockedMetadataMgr);
localMetastore.createDb("db1");
String createTable = "create table db1.tbl1 (c1 bigint, c2 bigint, c3 bigint)";
CreateTableStmt createTableStmt =
(CreateTableStmt) SqlParser.parseSingleStatement(createTable, ctx.getSessionVariable().getSqlMode());
Analyzer.analyze(createTableStmt, ctx);
localMetastore.createTable(createTableStmt);
AuthorizationMgr authorizationMgr = new AuthorizationMgr(new DefaultAuthorizationProvider());
GlobalStateMgr.getCurrentState().setAuthorizationMgr(authorizationMgr);
GlobalStateMgr.getCurrentState().setAuthenticationMgr(new AuthenticationMgr());
String createRoleSql = "create role r1";
StatementBase stmt = UtFrameUtils.parseStmtWithNewParser(createRoleSql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
String createUserSql = "create user u1";
stmt = UtFrameUtils.parseStmtWithNewParser(createUserSql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
GrantRoleStmt grantRoleStmt = new GrantRoleStmt(List.of("r1"), "g1", GrantType.GROUP, NodePosition.ZERO);
Analyzer.analyze(grantRoleStmt, ctx);
authorizationMgr.grantRole(grantRoleStmt);
String sql = "grant select on table db1.tbl1 to role r1";
GrantPrivilegeStmt grantStmt = (GrantPrivilegeStmt) UtFrameUtils.parseStmtWithNewParser(sql, ctx);
authorizationMgr.grant(grantStmt);
ctx.setCurrentUserIdentity(new UserIdentity("u1", "%"));
Assertions.assertThrows(AccessDeniedException.class,
() -> Authorizer.checkTableAction(ctx, "db1", "tbl1", PrivilegeType.SELECT));
ctx.setGroups(Set.of("g1"));
try {
Authorizer.checkTableAction(ctx, "db1", "tbl1", PrivilegeType.SELECT);
} catch (Exception e) {
Assertions.fail();
}
ctx.setGroups(Set.of());
Assertions.assertThrows(AccessDeniedException.class,
() -> Authorizer.checkTableAction(ctx, "db1", "tbl1", PrivilegeType.SELECT));
}
@Test
public void testShowGrantsPrivilege() throws Exception {
GlobalStateMgr globalStateMgr = GlobalStateMgr.getCurrentState();
EditLog editLog = spy(new EditLog(null));
doNothing().when(editLog).logEdit(anyShort(), any());
GlobalStateMgr.getCurrentState().setEditLog(editLog);
ConnectContext ctx = new ConnectContext();
String createUserSql = "create user u_grant";
CreateUserStmt stmt = (CreateUserStmt) UtFrameUtils.parseStmtWithNewParser(createUserSql, ctx);
DDLStmtExecutor.execute(stmt, ctx);
ctx.setCurrentUserIdentity(new UserIdentity("u_grant", "%"));
ctx.setGroups(Set.of("g1"));
ShowGrantsStmt stmt2 = new ShowGrantsStmt("g1", GrantType.GROUP, NodePosition.ZERO);
Authorizer.check(stmt2, ctx);
ShowGrantsStmt stmt3 = new ShowGrantsStmt("g2", GrantType.GROUP, NodePosition.ZERO);
Assertions.assertThrows(AccessDeniedException.class, () -> Authorizer.checkSystemAction(ctx, PrivilegeType.GRANT));
Assertions.assertThrows(ErrorReportException.class, () -> Authorizer.check(stmt3, ctx));
}
}

View File

@ -1773,11 +1773,13 @@ showRolesStatement
grantRoleStatement
: GRANT identifierOrStringList TO USER? user #grantRoleToUser
| GRANT identifierOrStringList TO ROLE identifierOrString #grantRoleToRole
| GRANT identifierOrStringList TO EXTERNAL GROUP identifierOrString #grantRoleToGroup
;
revokeRoleStatement
: REVOKE identifierOrStringList FROM USER? user #revokeRoleFromUser
| REVOKE identifierOrStringList FROM ROLE identifierOrString #revokeRoleFromRole
| REVOKE identifierOrStringList FROM EXTERNAL GROUP identifierOrString #revokeRoleFromGroup
;
setRoleStatement
@ -1823,6 +1825,7 @@ revokePrivilegeStatement
showGrantsStatement
: SHOW GRANTS
| SHOW GRANTS FOR USER? user
| SHOW GRANTS FOR EXTERNAL GROUP identifierOrString
| SHOW GRANTS FOR ROLE identifierOrString
;

View File

@ -23,6 +23,7 @@ public class GrantRoleStmt extends BaseGrantRevokeRoleStmt {
public GrantRoleStmt(List<String> granteeRole, UserRef user, NodePosition pos) {
super(granteeRole, user, pos);
}
public GrantRoleStmt(List<String> granteeRole, String group, GrantType grantType, NodePosition pos) {
super(granteeRole, group, grantType, pos);
}

View File

@ -0,0 +1,160 @@
-- name: test_execute_as_internal_user
CREATE GROUP PROVIDER IF NOT EXISTS `test_execute_as_file_group_provider` PROPERTIES ("group_file_url" = "group_mapping", "type" = "file");
-- result:
-- !result
admin set frontend config ("group_provider"="test_execute_as_file_group_provider");
-- result:
-- !result
drop user if exists test_impersonate;
-- result:
-- !result
create user test_impersonate;
-- result:
-- !result
grant impersonate on user root to test_impersonate;
-- result:
-- !result
drop role if exists g1_role;
-- result:
-- !result
create role g1_role;
-- result:
-- !result
grant g1_role to external group r1_group;
-- result:
-- !result
drop role if exists r1;
-- result:
-- !result
create role r1;
-- result:
-- !result
drop user if exists u1;
-- result:
-- !result
create user u1 default role r1;
-- result:
-- !result
drop role if exists g2_role;
-- result:
-- !result
create role g2_role;
-- result:
-- !result
grant g2_role to external group r2_group;
-- result:
-- !result
drop role if exists r2;
-- result:
-- !result
create role r2;
-- result:
-- !result
drop user if exists u2;
-- result:
-- !result
create user u2 default role r2;
-- result:
-- !result
grant impersonate on user u1 to test_impersonate;
-- result:
-- !result
grant impersonate on user u2 to test_impersonate;
-- result:
-- !result
grant impersonate on user test_impersonate to u1;
-- result:
-- !result
grant impersonate on user test_impersonate to u2;
-- result:
-- !result
execute as test_impersonate with no revert;
-- result:
-- !result
select current_group();
-- result:
NONE
-- !result
select current_role();
-- result:
NONE
-- !result
execute as u1 with no revert;
-- result:
-- !result
show databases;
-- result:
information_schema
-- !result
select current_group();
-- result:
r1_group
-- !result
select current_role();
-- result:
g1_role, r1
-- !result
execute as test_impersonate with no revert;
-- result:
-- !result
select current_group();
-- result:
NONE
-- !result
select current_role();
-- result:
NONE
-- !result
execute as u2 with no revert;
-- result:
-- !result
show databases;
-- result:
information_schema
-- !result
select current_group();
-- result:
r2_group
-- !result
select current_role();
-- result:
g2_role, r2
-- !result
execute as test_impersonate with no revert;
-- result:
-- !result
select current_group();
-- result:
NONE
-- !result
select current_role();
-- result:
NONE
-- !result
execute as root with no revert;
-- result:
-- !result
drop user if exists test_impersonate;
-- result:
-- !result
drop role if exists r1;
-- result:
-- !result
drop role if exists r2;
-- result:
-- !result
drop role if exists g1_role;
-- result:
-- !result
drop role if exists g2_role;
-- result:
-- !result
drop user if exists u1;
-- result:
-- !result
drop user if exists u2;
-- result:
-- !result
drop group provider IF EXISTS test_execute_as_file_group_provider;
-- result:
-- !result

View File

@ -0,0 +1,62 @@
-- name: test_execute_as_internal_user
CREATE GROUP PROVIDER IF NOT EXISTS `test_execute_as_file_group_provider` PROPERTIES ("group_file_url" = "group_mapping", "type" = "file");
admin set frontend config ("group_provider"="test_execute_as_file_group_provider");
drop user if exists test_impersonate;
create user test_impersonate;
grant impersonate on user root to test_impersonate;
drop role if exists g1_role;
create role g1_role;
grant g1_role to external group r1_group;
drop role if exists r1;
create role r1;
drop user if exists u1;
create user u1 default role r1;
drop role if exists g2_role;
create role g2_role;
grant g2_role to external group r2_group;
drop role if exists r2;
create role r2;
drop user if exists u2;
create user u2 default role r2;
grant impersonate on user u1 to test_impersonate;
grant impersonate on user u2 to test_impersonate;
grant impersonate on user test_impersonate to u1;
grant impersonate on user test_impersonate to u2;
execute as test_impersonate with no revert;
select current_group();
select current_role();
execute as u1 with no revert;
show databases;
select current_group();
select current_role();
execute as test_impersonate with no revert;
select current_group();
select current_role();
execute as u2 with no revert;
show databases;
select current_group();
select current_role();
execute as test_impersonate with no revert;
select current_group();
select current_role();
execute as root with no revert;
drop user if exists test_impersonate;
drop role if exists r1;
drop role if exists r2;
drop role if exists g1_role;
drop role if exists g2_role;
drop user if exists u1;
drop user if exists u2;
drop group provider IF EXISTS test_execute_as_file_group_provider;