Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#7739
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <[email protected]>
  • Loading branch information
lance6716 authored and ti-chi-bot committed Nov 30, 2022
1 parent c164be5 commit a356dc7
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 1 deletion.
34 changes: 33 additions & 1 deletion dm/pkg/checker/privilege.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ import (
_ "github.com/pingcap/tidb/types/parser_driver" // for parser driver
"github.com/pingcap/tidb/util/dbutil"
"github.com/pingcap/tidb/util/filter"
<<<<<<< HEAD
=======
"github.com/pingcap/tidb/util/stringutil"
"github.com/pingcap/tiflow/dm/pkg/log"
"github.com/pingcap/tiflow/pkg/container/sortmap"
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
"go.uber.org/zap"

"github.com/pingcap/tiflow/dm/pkg/log"
Expand Down Expand Up @@ -172,7 +178,7 @@ func verifyPrivileges(result *Result, grants []string, lackPriv map[mysql.Privil
return NewError("grant has no user %s", grant)
}

dbName := grantStmt.Level.DBName
dbPatChar, dbPatType := stringutil.CompilePattern(grantStmt.Level.DBName, '\\')
tableName := grantStmt.Level.TableName
switch grantStmt.Level.Level {
case ast.GrantLevelGlobal:
Expand Down Expand Up @@ -203,33 +209,52 @@ func verifyPrivileges(result *Result, grants []string, lackPriv map[mysql.Privil
if priv == mysql.GrantPriv {
continue
}
<<<<<<< HEAD
if _, ok := lackPriv[priv][dbName]; !ok {
continue
}
delete(lackPriv[priv], dbName)
if len(lackPriv[priv]) == 0 {
delete(lackPriv, priv)
}
=======
for dbName := range privs.dbs {
if stringutil.DoMatch(dbName, dbPatChar, dbPatType) {
delete(privs.dbs, dbName)
}
}
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
}
continue
}
if _, ok := lackPriv[privElem.Priv]; !ok {
continue
}
<<<<<<< HEAD
if _, ok := lackPriv[privElem.Priv][dbName]; !ok {
continue
}
=======
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
// dumpling could report error if an allow-list table is lack of privilege.
// we only check that SELECT is granted on all columns, otherwise we can't SHOW CREATE TABLE
if privElem.Priv == mysql.SelectPriv && len(privElem.Cols) != 0 {
continue
}
<<<<<<< HEAD
delete(lackPriv[privElem.Priv], dbName)
if len(lackPriv[privElem.Priv]) == 0 {
delete(lackPriv, privElem.Priv)
=======
for dbName := range privs.dbs {
if stringutil.DoMatch(dbName, dbPatChar, dbPatType) {
delete(privs.dbs, dbName)
}
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
}
}
case ast.GrantLevelTable:
dbName := grantStmt.Level.DBName
for _, privElem := range grantStmt.Privs {
// all privileges available at a given privilege level (except GRANT OPTION)
// from https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html#priv_all
Expand All @@ -241,6 +266,7 @@ func verifyPrivileges(result *Result, grants []string, lackPriv map[mysql.Privil
if _, ok := lackPriv[priv][dbName]; !ok {
continue
}
<<<<<<< HEAD
if _, ok := lackPriv[priv][dbName][tableName]; !ok {
continue
}
Expand All @@ -251,6 +277,9 @@ func verifyPrivileges(result *Result, grants []string, lackPriv map[mysql.Privil
if len(lackPriv[priv]) == 0 {
delete(lackPriv, priv)
}
=======
delete(dbPrivs.tables, tableName)
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
}
continue
}
Expand All @@ -260,9 +289,12 @@ func verifyPrivileges(result *Result, grants []string, lackPriv map[mysql.Privil
if _, ok := lackPriv[privElem.Priv][dbName]; !ok {
continue
}
<<<<<<< HEAD
if _, ok := lackPriv[privElem.Priv][dbName][tableName]; !ok {
continue
}
=======
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
// dumpling could report error if an allow-list table is lack of privilege.
// we only check that SELECT is granted on all columns, otherwise we can't SHOW CREATE TABLE
if privElem.Priv == mysql.SelectPriv && len(privElem.Cols) != 0 {
Expand Down
141 changes: 141 additions & 0 deletions dm/pkg/checker/privilege_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,150 @@ func (t *testCheckSuite) TestVerifyReplicationPrivileges(c *tc.C) {
},
}

<<<<<<< HEAD
replicationPrivileges := map[mysql.PrivilegeType]struct{}{
mysql.ReplicationClientPriv: {},
mysql.ReplicationSlavePriv: {},
=======
for _, cs := range cases {
result := &Result{
State: StateFailure,
}
replRequiredPrivs := map[mysql.PrivilegeType]priv{
mysql.ReplicationSlavePriv: {needGlobal: true},
mysql.ReplicationClientPriv: {needGlobal: true},
}
err := verifyPrivilegesWithResult(result, cs.grants, replRequiredPrivs)
if cs.replicationState == StateSuccess {
require.Nil(t, err, "grants: %v", cs.grants)
} else {
require.NotNil(t, err, "grants: %v", cs.grants)
require.Equal(t, cs.errStr, err.ShortErr, "grants: %v", cs.grants)
}
}
}

func TestVerifyPrivilegesWildcard(t *testing.T) {
cases := []struct {
grants []string
checkTables []filter.Table
replicationState State
errStr string
}{
{
grants: []string{
"GRANT SELECT ON `demo\\_foobar`.* TO `dmuser`@`%`",
},
checkTables: []filter.Table{
{Schema: "demo_foobar", Name: "t1"},
},
replicationState: StateSuccess,
},
{
grants: []string{
"GRANT SELECT ON `demo\\_foobar`.* TO `dmuser`@`%`",
},
checkTables: []filter.Table{
{Schema: "demo2foobar", Name: "t1"},
},
replicationState: StateFailure,
errStr: "lack of Select privilege: {`demo2foobar`.`t1`}; ",
},
{
grants: []string{
"GRANT SELECT ON `demo_`.* TO `dmuser`@`%`",
},
checkTables: []filter.Table{
{Schema: "demo1", Name: "t1"},
{Schema: "demo2", Name: "t1"},
},
replicationState: StateSuccess,
},
{
grants: []string{
"GRANT SELECT ON `demo%`.* TO `dmuser`@`%`",
},
checkTables: []filter.Table{
{Schema: "demo_some", Name: "t1"},
{Schema: "block_db", Name: "t1"},
},
replicationState: StateFailure,
errStr: "lack of Select privilege: {`block_db`.`t1`}; ",
},
{
grants: []string{
"GRANT SELECT ON `demo_db`.`t1` TO `dmuser`@`%`",
},
checkTables: []filter.Table{
{Schema: "demo_db", Name: "t1"},
{Schema: "demo2db", Name: "t1"},
},
replicationState: StateFailure,
errStr: "lack of Select privilege: {`demo2db`.`t1`}; ",
},
}

for i, cs := range cases {
t.Logf("case %d", i)
result := &Result{
State: StateFailure,
}
requiredPrivs := map[mysql.PrivilegeType]priv{
mysql.SelectPriv: {
dbs: genTableLevelPrivs(cs.checkTables),
},
}
err := verifyPrivilegesWithResult(result, cs.grants, requiredPrivs)
if cs.replicationState == StateSuccess {
require.Nil(t, err, "grants: %v", cs.grants)
} else {
require.NotNil(t, err, "grants: %v", cs.grants)
require.Equal(t, cs.errStr, err.ShortErr, "grants: %v", cs.grants)
}
}
}

func TestVerifyTargetPrivilege(t *testing.T) {
cases := []struct {
grants []string
checkState State
errStr string
}{
{
grants: nil, // non grants
checkState: StateWarning,
errStr: "there is no such grant defined for current user on host '%'",
},
{
grants: []string{"invalid SQL statement"},
checkState: StateWarning,
errStr: "line 1 column 7 near \"invalid SQL statement\" ",
},
{
grants: []string{"CREATE DATABASE db1"}, // non GRANT statement
checkState: StateWarning,
errStr: "CREATE DATABASE db1 is not grant statement",
},
{
grants: []string{
"GRANT ALL PRIVILEGES ON *.* TO 'user'@'%'",
},
checkState: StateSuccess,
},
{
grants: []string{
"GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, ALTER, DROP ON *.* TO 'root'@'%'",
},
checkState: StateSuccess,
},
{
grants: []string{
"GRANT SELECT, INSERT, DELETE, ALTER, DROP ON *.* TO 'root'@'%'",
},
checkState: StateWarning,
errStr: "lack of Create global (*.*) privilege; lack of Update global (*.*) privilege; ",
},
>>>>>>> a2d2a5213c (checker(dm): support wildcard in privilege checking (#7739))
}
for _, cs := range cases {
result := &Result{
Expand Down

0 comments on commit a356dc7

Please sign in to comment.