Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource_control: introduce privilege RESOURCE_GROUP_USER to restrict the switch of resource group #53483

Merged
merged 14 commits into from
Jun 14, 2024
2 changes: 1 addition & 1 deletion pkg/planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1681,7 +1681,7 @@ func (er *expressionRewriter) rewriteVariable(planCtx *exprRewriterPlanCtx, v *a
}
if sem.IsEnabled() && sem.IsInvisibleSysVar(sysVar.Name) {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("RESTRICTED_VARIABLES_ADMIN")
planCtx.builder.visitInfo = appendDynamicVisitInfo(planCtx.builder.visitInfo, "RESTRICTED_VARIABLES_ADMIN", false, err)
planCtx.builder.visitInfo = appendDynamicVisitInfo(planCtx.builder.visitInfo, []string{"RESTRICTED_VARIABLES_ADMIN"}, false, err)
}
if v.ExplicitScope && !sysVar.HasNoneScope() {
if v.IsGlobal && !(sysVar.HasGlobalScope() || sysVar.HasInstanceScope()) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7288,10 +7288,10 @@ func collectTableName(node ast.ResultSetNode, updatableName *map[string]bool, in
}
}

func appendDynamicVisitInfo(vi []visitInfo, priv string, withGrant bool, err error) []visitInfo {
func appendDynamicVisitInfo(vi []visitInfo, privs []string, withGrant bool, err error) []visitInfo {
return append(vi, visitInfo{
privilege: mysql.ExtendedPriv,
dynamicPriv: priv,
dynamicPrivs: privs,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change necessary? Maybe you can 'git checkout master xxx.go' for most of the changes. @glorv

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think this change is necessary to express that user should have at least one of the privileges. I added a comment for the field dynamicPrivs

dynamicWithGrant: withGrant,
err: err,
})
Expand Down
322 changes: 161 additions & 161 deletions pkg/planner/core/logical_plans_test.go

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions pkg/planner/core/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,16 @@ func BuildLogicalPlanForTest(ctx context.Context, sctx sessionctx.Context, node
func CheckPrivilege(activeRoles []*auth.RoleIdentity, pm privilege.Manager, vs []visitInfo) error {
for _, v := range vs {
if v.privilege == mysql.ExtendedPriv {
if !pm.RequestDynamicVerification(activeRoles, v.dynamicPriv, v.dynamicWithGrant) {
hasPriv := false
for _, priv := range v.dynamicPrivs {
hasPriv = hasPriv || pm.RequestDynamicVerification(activeRoles, priv, v.dynamicWithGrant)
if hasPriv {
break
}
}
if !hasPriv {
if v.err == nil {
return plannererrors.ErrPrivilegeCheckFail.GenWithStackByArgs(v.dynamicPriv)
return plannererrors.ErrPrivilegeCheckFail.GenWithStackByArgs(v.dynamicPrivs)
}
return v.err
}
Expand Down
67 changes: 42 additions & 25 deletions pkg/planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding/binary"
"fmt"
"math"
"reflect"
"strconv"
"strings"

Expand Down Expand Up @@ -72,16 +73,29 @@ import (
)

type visitInfo struct {
privilege mysql.PrivilegeType
db string
table string
column string
err error
alterWritable bool
dynamicPriv string
privilege mysql.PrivilegeType
db string
table string
column string
err error
alterWritable bool
// if multiple privileges is provided, user should
// have at least one privilege to pass the check.
dynamicPrivs []string
dynamicWithGrant bool
}

func (v *visitInfo) Equals(other *visitInfo) bool {
return v.privilege == other.privilege &&
v.db == other.db &&
v.table == other.table &&
v.column == other.column &&
v.err == other.err &&
v.alterWritable == other.alterWritable &&
reflect.DeepEqual(v.dynamicPrivs, other.dynamicPrivs) &&
nolouch marked this conversation as resolved.
Show resolved Hide resolved
v.dynamicWithGrant == other.dynamicWithGrant
}

// clauseCode indicates in which clause the column is currently.
type clauseCode int

Expand Down Expand Up @@ -654,11 +668,11 @@ func (b *PlanBuilder) buildSet(ctx context.Context, v *ast.SetStmt) (base.Plan,
for _, vars := range v.Variables {
if vars.IsGlobal {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or SYSTEM_VARIABLES_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "SYSTEM_VARIABLES_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"SYSTEM_VARIABLES_ADMIN"}, false, err)
}
if sem.IsEnabled() && sem.IsInvisibleSysVar(strings.ToLower(vars.Name)) {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("RESTRICTED_VARIABLES_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESTRICTED_VARIABLES_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESTRICTED_VARIABLES_ADMIN"}, false, err)
}
assign := &expression.VarAssignment{
Name: vars.Name,
Expand Down Expand Up @@ -3167,10 +3181,10 @@ func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (base.P
b.visitInfo = appendVisitInfo(b.visitInfo, mysql.ShowViewPriv, show.Table.Schema.L, show.Table.Name.L, "", err)
case ast.ShowBackups:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or BACKUP_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "BACKUP_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"BACKUP_ADMIN"}, false, err)
case ast.ShowRestores:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESTORE_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESTORE_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESTORE_ADMIN"}, false, err)
case ast.ShowTableNextRowId:
p := &ShowNextRowID{TableName: show.Table}
p.setSchemaAndNames(buildShowNextRowID())
Expand Down Expand Up @@ -3288,28 +3302,28 @@ func (b *PlanBuilder) buildSimple(ctx context.Context, node ast.StmtNode) (base.
p.setSchemaAndNames(buildBRIESchema(raw.Kind))
if raw.Kind == ast.BRIEKindRestore {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESTORE_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESTORE_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESTORE_ADMIN"}, false, err)
} else {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or BACKUP_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "BACKUP_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"BACKUP_ADMIN"}, false, err)
}
case *ast.CalibrateResourceStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESOURCE_GROUP_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESOURCE_GROUP_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESOURCE_GROUP_ADMIN"}, false, err)
p.setSchemaAndNames(buildCalibrateResourceSchema())
case *ast.AddQueryWatchStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESOURCE_GROUP_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESOURCE_GROUP_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESOURCE_GROUP_ADMIN"}, false, err)
p.setSchemaAndNames(buildAddQueryWatchSchema())
case *ast.DropQueryWatchStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESOURCE_GROUP_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESOURCE_GROUP_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESOURCE_GROUP_ADMIN"}, false, err)
case *ast.GrantRoleStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or ROLE_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "ROLE_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"ROLE_ADMIN"}, false, err)
case *ast.RevokeRoleStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or ROLE_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "ROLE_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"ROLE_ADMIN"}, false, err)
// Check if any of the users are RESTRICTED
for _, user := range raw.Users {
b.visitInfo = appendVisitInfoIsRestrictedUser(b.visitInfo, b.ctx, user, "RESTRICTED_USER_ADMIN")
Expand All @@ -3330,13 +3344,13 @@ func (b *PlanBuilder) buildSimple(ctx context.Context, node ast.StmtNode) (base.
loginUser := b.ctx.GetSessionVars().User
if pi.User != loginUser.Username {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or CONNECTION_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "CONNECTION_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"CONNECTION_ADMIN"}, false, err)
b.visitInfo = appendVisitInfoIsRestrictedUser(b.visitInfo, b.ctx, &auth.UserIdentity{Username: pi.User, Hostname: pi.Host}, "RESTRICTED_CONNECTION_ADMIN")
}
} else if raw.ConnectionID == domain.GetDomain(b.ctx).GetAutoAnalyzeProcID() {
// Only the users with SUPER or CONNECTION_ADMIN privilege can kill auto analyze.
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or CONNECTION_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "CONNECTION_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"CONNECTION_ADMIN"}, false, err)
}
}
case *ast.UseStmt:
Expand Down Expand Up @@ -3381,6 +3395,9 @@ func (b *PlanBuilder) buildSimple(ctx context.Context, node ast.StmtNode) (base.
}
p.StaleTxnStartTS = startTS
}
case *ast.SetResourceGroupStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESOURCE_GROUP_ADMIN or RESOURCE_GROUP_USER")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESOURCE_GROUP_ADMIN", "RESOURCE_GROUP_USER"}, false, err)
}
return p, nil
}
Expand All @@ -3402,7 +3419,7 @@ func collectVisitInfoFromRevokeStmt(sctx base.PlanContext, vi []visitInfo, stmt
var allPrivs []mysql.PrivilegeType
for _, item := range stmt.Privs {
if item.Priv == mysql.ExtendedPriv {
vi = appendDynamicVisitInfo(vi, strings.ToUpper(item.Name), true, nil) // verified in MySQL: requires the dynamic grant option to revoke.
vi = appendDynamicVisitInfo(vi, []string{strings.ToUpper(item.Name)}, true, nil) // verified in MySQL: requires the dynamic grant option to revoke.
continue
}
nonDynamicPrivilege = true
Expand Down Expand Up @@ -3444,7 +3461,7 @@ func appendVisitInfoIsRestrictedUser(visitInfo []visitInfo, sctx base.PlanContex
checker := privilege.GetPrivilegeManager(sctx)
if checker != nil && checker.RequestDynamicVerificationWithUser("RESTRICTED_USER_ADMIN", false, user) {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs(priv)
visitInfo = appendDynamicVisitInfo(visitInfo, priv, false, err)
visitInfo = appendDynamicVisitInfo(visitInfo, []string{priv}, false, err)
}
return visitInfo
}
Expand Down Expand Up @@ -3479,7 +3496,7 @@ func collectVisitInfoFromGrantStmt(sctx base.PlanContext, vi []visitInfo, stmt *
// with dynamic privileges.

err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("GRANT OPTION")
vi = appendDynamicVisitInfo(vi, item.Name, true, err)
vi = appendDynamicVisitInfo(vi, []string{item.Name}, true, err)
continue
}
nonDynamicPrivilege = true
Expand Down Expand Up @@ -4843,10 +4860,10 @@ func (b *PlanBuilder) buildDDL(ctx context.Context, node ast.DDLNode) (base.Plan
b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SuperPriv, "", "", "", nil)
case *ast.DropPlacementPolicyStmt, *ast.CreatePlacementPolicyStmt, *ast.AlterPlacementPolicyStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or PLACEMENT_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "PLACEMENT_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"PLACEMENT_ADMIN"}, false, err)
case *ast.CreateResourceGroupStmt, *ast.DropResourceGroupStmt, *ast.AlterResourceGroupStmt:
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESOURCE_GROUP_ADMIN")
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, "RESOURCE_GROUP_ADMIN", false, err)
b.visitInfo = appendDynamicVisitInfo(b.visitInfo, []string{"RESOURCE_GROUP_ADMIN"}, false, err)
case *ast.OptimizeTableStmt:
return nil, dbterror.ErrGeneralUnsupportedDDL.GenWithStack("OPTIMIZE TABLE is not supported")
}
Expand Down
22 changes: 17 additions & 5 deletions pkg/planner/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,23 @@ func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in
// Override the resource group if the hint is set.
if retErr == nil && sessVars.StmtCtx.StmtHints.HasResourceGroup {
if variable.EnableResourceControl.Load() {
sessVars.StmtCtx.ResourceGroupName = sessVars.StmtCtx.StmtHints.ResourceGroup
// if we are in a txn, should update the txn resource name to let the txn
// commit with the hint resource group.
if txn, err := sctx.Txn(false); err == nil && txn != nil && txn.Valid() {
kv.SetTxnResourceGroup(txn, sessVars.StmtCtx.ResourceGroupName)
checker := privilege.GetPrivilegeManager(sctx)
hasPriv := true
if checker != nil {
hasRgAdminPriv := checker.RequestDynamicVerification(sctx.GetSessionVars().ActiveRoles, "RESOURCE_GROUP_ADMIN", false)
hasRgUserPriv := checker.RequestDynamicVerification(sctx.GetSessionVars().ActiveRoles, "RESOURCE_GROUP_USER", false)
hasPriv = hasRgAdminPriv || hasRgUserPriv
}
if hasPriv {
sessVars.StmtCtx.ResourceGroupName = sessVars.StmtCtx.StmtHints.ResourceGroup
// if we are in a txn, should update the txn resource name to let the txn
// commit with the hint resource group.
if txn, err := sctx.Txn(false); err == nil && txn != nil && txn.Valid() {
kv.SetTxnResourceGroup(txn, sessVars.StmtCtx.ResourceGroupName)
}
} else {
err := plannererrors.ErrSpecificAccessDenied.GenWithStackByArgs("SUPER or RESOURCE_GROUP_ADMIN or RESOURCE_GROUP_USER")
sessVars.StmtCtx.AppendWarning(err)
}
} else {
err := infoschema.ErrResourceGroupSupportDisabled
Expand Down
3 changes: 2 additions & 1 deletion pkg/privilege/privileges/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ func (p *MySQLPrivilege) HasExplicitlyGrantedDynamicPrivilege(activeRoles []*aut
}

// RequestDynamicVerification checks all roles for a specific DYNAMIC privilege.
func (p *MySQLPrivilege) RequestDynamicVerification(activeRoles []*auth.RoleIdentity, user, host, privName string, withGrant bool) bool {
func (p *MySQLPrivilege) RequestDynamicVerification(activeRoles []*auth.RoleIdentity, user, host string, privName string, withGrant bool) bool {
privName = strings.ToUpper(privName)
if p.HasExplicitlyGrantedDynamicPrivilege(activeRoles, user, host, privName, withGrant) {
return true
Expand All @@ -1135,6 +1135,7 @@ func (p *MySQLPrivilege) RequestDynamicVerification(activeRoles []*auth.RoleIden
if sem.IsEnabled() && sem.IsRestrictedPrivilege(privName) {
return false
}

// For compatibility reasons, the SUPER privilege also has all DYNAMIC privileges granted to it (dynamic privs are a super replacement)
// This may be changed in future, but will require a bootstrap task to assign all dynamic privileges
// to users with SUPER, otherwise tasks such as BACKUP and ROLE_ADMIN will start to fail.
Expand Down
1 change: 1 addition & 0 deletions pkg/privilege/privileges/privileges.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ var dynamicPrivs = []string{
"RESTRICTED_CONNECTION_ADMIN", // Can not be killed by PROCESS/CONNECTION_ADMIN privilege
"RESTRICTED_REPLICA_WRITER_ADMIN", // Can write to the sever even when tidb_restriced_read_only is turned on.
"RESOURCE_GROUP_ADMIN", // Create/Drop/Alter RESOURCE GROUP
"RESOURCE_GROUP_USER", // Can change the resource group of current session.
}
var dynamicPrivLock sync.Mutex
var defaultTokenLife = 15 * time.Minute
Expand Down
1 change: 1 addition & 0 deletions tests/integrationtest/r/executor/executor.result
Original file line number Diff line number Diff line change
Expand Up @@ -3220,6 +3220,7 @@ RESTRICTED_USER_ADMIN Server Admin
RESTRICTED_CONNECTION_ADMIN Server Admin
RESTRICTED_REPLICA_WRITER_ADMIN Server Admin
RESOURCE_GROUP_ADMIN Server Admin
RESOURCE_GROUP_USER Server Admin
show table status;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
t InnoDB 10 Compact 0 0 0 0 0 0 NULL 0 NULL NULL utf8mb4_bin
Expand Down
34 changes: 31 additions & 3 deletions tests/integrationtest/r/privilege/privileges.result
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,52 @@ drop placement policy if exists x;
create placement policy x PRIMARY_REGION="cn-east-1" REGIONS="cn-east-1";
drop placement policy if exists x;
drop user placement_user;
CREATE USER resource_group_admin;
CREATE USER resource_group_user;
set @@global.tidb_enable_resource_control = 1;
CREATE RESOURCE GROUP test RU_PER_SEC = 666;
Error 1227 (42000): Access denied; you need (at least one of) the SUPER or RESOURCE_GROUP_ADMIN privilege(s) for this operation
GRANT RESOURCE_GROUP_ADMIN ON *.* TO resource_group_user;
CREATE DATABASE IF NOT EXISTS test_rc;
CREATE TABLE test_rc.t(id int);
INSERT INTO test_rc.t VALUES (1);
GRANT RESOURCE_GROUP_ADMIN ON *.* TO resource_group_admin;
SHOW GRANTS FOR resource_group_admin;
Grants for resource_group_admin@%
GRANT USAGE ON *.* TO 'resource_group_admin'@'%'
GRANT RESOURCE_GROUP_ADMIN ON *.* TO 'resource_group_admin'@'%'
GRANT RESOURCE_GROUP_USER ON *.* TO resource_group_user;
SHOW GRANTS FOR resource_group_user;
Grants for resource_group_user@%
GRANT USAGE ON *.* TO 'resource_group_user'@'%'
GRANT RESOURCE_GROUP_ADMIN ON *.* TO 'resource_group_user'@'%'
GRANT RESOURCE_GROUP_USER ON *.* TO 'resource_group_user'@'%'
GRANT SELECT on test_rc.* TO resource_group_admin;
GRANT SELECT on test_rc.* TO resource_group_user;
CREATE RESOURCE GROUP test RU_PER_SEC = 666;
CREATE RESOURCE GROUP test2 RU_PER_SEC = 999;
ALTER RESOURCE GROUP test2 RU_PER_SEC = 1000;
DROP RESOURCE GROUP test2;
REVOKE RESOURCE_GROUP_ADMIN ON *.* FROM resource_group_user;
SELECT /*+ RESOURCE_GROUP(test) */ * from test_rc.t;
id
1
SET RESOURCE GROUP test;
SELECT /*+ RESOURCE_GROUP(test) */ * from test_rc.t;
id
1
SET RESOURCE GROUP test;
REVOKE RESOURCE_GROUP_ADMIN ON *.* FROM resource_group_admin;
REVOKE RESOURCE_GROUP_USER ON *.* FROM resource_group_user;
ALTER RESOURCE GROUP test RU_PER_SEC = 667;
Error 1227 (42000): Access denied; you need (at least one of) the SUPER or RESOURCE_GROUP_ADMIN privilege(s) for this operation
DROP RESOURCE GROUP test;
Error 1227 (42000): Access denied; you need (at least one of) the SUPER or RESOURCE_GROUP_ADMIN privilege(s) for this operation
SET RESOURCE GROUP test;
Error 1227 (42000): Access denied; you need (at least one of) the SUPER or RESOURCE_GROUP_ADMIN or RESOURCE_GROUP_USER privilege(s) for this operation
SELECT /*+ RESOURCE_GROUP(test) */ * from test_rc.t;
id
1
REVOKE SELECT on test_rc.* FROM resource_group_admin;
REVOKE SELECT on test_rc.* FROM resource_group_user;
DROP DATABASE test_rc;
CREATE SCHEMA IF NOT EXISTS privilege__privileges;
USE privilege__privileges;
CREATE TABLE reftest (a int);
Expand Down
35 changes: 30 additions & 5 deletions tests/integrationtest/t/privilege/privileges.test
Original file line number Diff line number Diff line change
Expand Up @@ -85,35 +85,60 @@ connection default;
drop user placement_user;

# TestResourceGroupAdminDynamicPriv
CREATE USER resource_group_admin;
CREATE USER resource_group_user;
# This should be the default value in the future, so we do not need to set if for testing?
set @@global.tidb_enable_resource_control = 1;

connect (resource_group_admin,localhost,resource_group_admin,,);
connect (resource_group_user,localhost,resource_group_user,,);
connection resource_group_user;

connection resource_group_admin;
--error 1227
CREATE RESOURCE GROUP test RU_PER_SEC = 666;

connection default;
GRANT RESOURCE_GROUP_ADMIN ON *.* TO resource_group_user;
CREATE DATABASE IF NOT EXISTS test_rc;
CREATE TABLE test_rc.t(id int);
INSERT INTO test_rc.t VALUES (1);
GRANT RESOURCE_GROUP_ADMIN ON *.* TO resource_group_admin;
SHOW GRANTS FOR resource_group_admin;
GRANT RESOURCE_GROUP_USER ON *.* TO resource_group_user;
SHOW GRANTS FOR resource_group_user;
GRANT SELECT on test_rc.* TO resource_group_admin;
GRANT SELECT on test_rc.* TO resource_group_user;

connection resource_group_user;
connection resource_group_admin;
CREATE RESOURCE GROUP test RU_PER_SEC = 666;
CREATE RESOURCE GROUP test2 RU_PER_SEC = 999;
ALTER RESOURCE GROUP test2 RU_PER_SEC = 1000;
DROP RESOURCE GROUP test2;
SELECT /*+ RESOURCE_GROUP(test) */ * from test_rc.t;
SET RESOURCE GROUP test;

connection resource_group_user;
SELECT /*+ RESOURCE_GROUP(test) */ * from test_rc.t;
SET RESOURCE GROUP test;

connection default;
REVOKE RESOURCE_GROUP_ADMIN ON *.* FROM resource_group_user;
REVOKE RESOURCE_GROUP_ADMIN ON *.* FROM resource_group_admin;
REVOKE RESOURCE_GROUP_USER ON *.* FROM resource_group_user;

connection resource_group_user;
connection resource_group_admin;
--error 1227
ALTER RESOURCE GROUP test RU_PER_SEC = 667;
--error 1227
DROP RESOURCE GROUP test;
--error 1227
SET RESOURCE GROUP test;
SELECT /*+ RESOURCE_GROUP(test) */ * from test_rc.t;

disconnect resource_group_admin;
disconnect resource_group_user;
connection default;
REVOKE SELECT on test_rc.* FROM resource_group_admin;
REVOKE SELECT on test_rc.* FROM resource_group_user;
DROP DATABASE test_rc;

# TestGrantReferences
CREATE SCHEMA IF NOT EXISTS privilege__privileges;
Expand Down