From ff61b47eaa83c9026e5d10e4d2eab04b3fd1aead Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Thu, 14 Mar 2019 15:44:31 +0800 Subject: [PATCH 1/7] add grant role --- executor/simple.go | 48 +++++++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- planner/core/planbuilder.go | 8 +++++-- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/executor/simple.go b/executor/simple.go index b23c0b8d6edcf..9f06374c302a0 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -56,6 +56,8 @@ func (e *SimpleExec) Next(ctx context.Context, req *chunk.RecordBatch) (err erro return nil } switch x := e.Statement.(type) { + case *ast.GrantRoleStmt: + err = e.executeGrantRole(x) case *ast.UseStmt: err = e.executeUse(x) case *ast.FlushStmt: @@ -277,6 +279,52 @@ func (e *SimpleExec) executeAlterUser(s *ast.AlterUserStmt) error { return nil } +func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { + failedUsers := make([]string, 0, len(s.Users)) + for _, role := range s.Roles { + exists, err := userExists(e.ctx, role.Username, role.Hostname) + if err != nil { + return errors.Trace(err) + } + if !exists { + return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", role.String()) + } + } + + for _, user := range s.Users { + exists, err := userExists(e.ctx, user.Username, user.Hostname) + if err != nil { + return errors.Trace(err) + } + if !exists { + failedUsers = append(failedUsers, user.String()) + continue + } + // begin a transaction to insert role graph edges. + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + return errors.Trace(err) + } + for _, role := range s.Roles { + sql := fmt.Sprintf(`INSERT IGNORE INTO %s.%s (FROM_HOST, FROM_USER, TO_HOST, TO_USER) VALUES ('%s','%s','%s','%s')`, mysql.SystemDB, mysql.RoleEdgeTable, role.Hostname, role.Username, user.Hostname, user.Username) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { + failedUsers = append(failedUsers, user.String()) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); err != nil { + return errors.Trace(err) + } + continue + } + } + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + failedUsers = append(failedUsers, user.String()) + } + } + if len(failedUsers) > 0 { + return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", strings.Join(failedUsers, ",")) + } + err := domain.GetDomain(e.ctx).PrivilegeHandle().Update(e.ctx.(sessionctx.Context)) + return errors.Trace(err) +} + func (e *SimpleExec) executeDropUser(s *ast.DropUserStmt) error { failedUsers := make([]string, 0, len(s.UserList)) for _, user := range s.UserList { diff --git a/go.mod b/go.mod index 2334fa8c642a6..f46ff3a30c1a2 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e github.com/pingcap/kvproto v0.0.0-20190215154024-7f2fc73ef562 github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596 - github.com/pingcap/parser v0.0.0-20190321052000-f9a452f8f24e + github.com/pingcap/parser v0.0.0-20190325012055-cc0fa08f99ca github.com/pingcap/pd v2.1.0-rc.4+incompatible github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible github.com/pingcap/tipb v0.0.0-20190107072121-abbec73437b7 diff --git a/go.sum b/go.sum index 6341b69fed8c0..d483098e0b9d0 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/pingcap/kvproto v0.0.0-20190215154024-7f2fc73ef562 h1:32oF1/8lVnBR2JV github.com/pingcap/kvproto v0.0.0-20190215154024-7f2fc73ef562/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596 h1:t2OQTpPJnrPDGlvA+3FwJptMTt6MEPdzK1Wt99oaefQ= github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= -github.com/pingcap/parser v0.0.0-20190321052000-f9a452f8f24e h1:Evw2H5BmAGqHTKbbcrGXBuOq9I02w3iVn/e7yHR+zvg= -github.com/pingcap/parser v0.0.0-20190321052000-f9a452f8f24e/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= +github.com/pingcap/parser v0.0.0-20190325012055-cc0fa08f99ca h1:ylsmsndeqq4NUE3EvL+TIvZKTlv8Qrth6CFPxDpm570= +github.com/pingcap/parser v0.0.0-20190325012055-cc0fa08f99ca/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE= github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E= github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible h1:MkWCxgZpJBgY2f4HtwWMMFzSBb3+JPzeJgF3VrXE/bU= diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index ee1f5e640f29f..60bf1e532c66b 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -212,8 +212,9 @@ func (b *PlanBuilder) Build(node ast.Node) (Plan, error) { case *ast.AnalyzeTableStmt: return b.buildAnalyze(x) case *ast.BinlogStmt, *ast.FlushStmt, *ast.UseStmt, - *ast.BeginStmt, *ast.CommitStmt, *ast.RollbackStmt, *ast.CreateUserStmt, *ast.SetPwdStmt, *ast.GrantStmt, - *ast.DropUserStmt, *ast.AlterUserStmt, *ast.RevokeStmt, *ast.KillStmt, *ast.DropStatsStmt, *ast.SetRoleStmt: + *ast.BeginStmt, *ast.CommitStmt, *ast.RollbackStmt, *ast.CreateUserStmt, *ast.SetPwdStmt, + *ast.GrantStmt, *ast.DropUserStmt, *ast.AlterUserStmt, *ast.RevokeStmt, *ast.KillStmt, *ast.DropStatsStmt, + *ast.GrantRoleStmt, *ast.SetRoleStmt: return b.buildSimple(node.(ast.StmtNode)) case ast.DDLNode: return b.buildDDL(x) @@ -1042,6 +1043,9 @@ func (b *PlanBuilder) buildSimple(node ast.StmtNode) (Plan, error) { b.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreateUserPriv, "", "", "", err) case *ast.GrantStmt: b.visitInfo = collectVisitInfoFromGrantStmt(b.ctx, b.visitInfo, raw) + case *ast.GrantRoleStmt: + err := ErrSpecificAccessDenied.GenWithStackByArgs("GRANT ROLE") + b.visitInfo = appendVisitInfo(b.visitInfo, mysql.GrantPriv, "", "", "", err) case *ast.RevokeStmt: b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SuperPriv, "", "", "", nil) case *ast.KillStmt: From 1ae6b7a425e44af3d53e1bcc8101b005d1cdd8f6 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Thu, 14 Mar 2019 16:47:22 +0800 Subject: [PATCH 2/7] add unit test --- executor/simple_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/executor/simple_test.go b/executor/simple_test.go index 94305e7762fc1..8096c65b6299b 100644 --- a/executor/simple_test.go +++ b/executor/simple_test.go @@ -93,6 +93,7 @@ func (s *testSuite3) TestRole(c *C) { result := tk.MustQuery(`SELECT Password FROM mysql.User WHERE User="test" and Host="localhost"`) result.Check(nil) + // Test for DROP ROLE. createRoleSQL := `CREATE ROLE 'test'@'localhost';` tk.MustExec(createRoleSQL) // Make sure user test in mysql.User. @@ -119,6 +120,31 @@ func (s *testSuite3) TestRole(c *C) { result.Check(nil) result = tk.MustQuery(`SELECT * FROM mysql.default_roles WHERE DEFAULT_ROLE_USER="test" and DEFAULT_ROLE_HOST="localhost"`) result.Check(nil) + + // Test for GRANT ROLE + createRoleSQL = `CREATE ROLE 'r_1'@'localhost', 'r_2'@'localhost', 'r_3'@'localhost';` + tk.MustExec(createRoleSQL) + grantRoleSQL := `GRANT 'r_1'@'localhost' TO 'r_2'@'localhost';` + tk.MustExec(grantRoleSQL) + result = tk.MustQuery(`SELECT TO_USER FROM mysql.role_edges WHERE FROM_USER="r_1" and FROM_HOST="localhost"`) + result.Check(testkit.Rows("r_2")) + + grantRoleSQL = `GRANT 'r_1'@'localhost' TO 'r_3'@'localhost';` + _, err = tk.Exec(grantRoleSQL) + c.Check(err, NotNil) + + grantRoleSQL = `GRANT 'r_1'@'localhost' TO 'r_3'@'localhost', 'r_4'@'localhost';` + _, err = tk.Exec(grantRoleSQL) + c.Check(err, NotNil) + result = tk.MustQuery(`SELECT FROM_USER FROM mysql.role_edges WHERE TO_USER="r_3" and TO_HOST="localhost"`) + result.Check(testkit.Rows("r_1")) + + dropRoleSQL := `DROP ROLE IF EXISTS 'r_1'@'localhost' ;` + tk.MustExec(dropRoleSQL) + dropRoleSQL = `DROP ROLE IF EXISTS 'r_2'@'localhost' ;` + tk.MustExec(dropRoleSQL) + dropRoleSQL = `DROP ROLE IF EXISTS 'r_3'@'localhost' ;` + tk.MustExec(dropRoleSQL) } func (s *testSuite3) TestUser(c *C) { From 60bf2a25710a38db67c232d0a6dc966de742275b Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 25 Mar 2019 12:19:08 +0800 Subject: [PATCH 3/7] fix ci --- executor/simple_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/executor/simple_test.go b/executor/simple_test.go index 8096c65b6299b..2df5839b4c012 100644 --- a/executor/simple_test.go +++ b/executor/simple_test.go @@ -129,10 +129,6 @@ func (s *testSuite3) TestRole(c *C) { result = tk.MustQuery(`SELECT TO_USER FROM mysql.role_edges WHERE FROM_USER="r_1" and FROM_HOST="localhost"`) result.Check(testkit.Rows("r_2")) - grantRoleSQL = `GRANT 'r_1'@'localhost' TO 'r_3'@'localhost';` - _, err = tk.Exec(grantRoleSQL) - c.Check(err, NotNil) - grantRoleSQL = `GRANT 'r_1'@'localhost' TO 'r_3'@'localhost', 'r_4'@'localhost';` _, err = tk.Exec(grantRoleSQL) c.Check(err, NotNil) From bc7a68768a729ce54caad4643fa31c61ff5d4f06 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 25 Mar 2019 14:09:36 +0800 Subject: [PATCH 4/7] fix transcation problem --- executor/simple.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor/simple.go b/executor/simple.go index 9f06374c302a0..c7be52bd9fdcb 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -311,7 +311,7 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); err != nil { return errors.Trace(err) } - continue + break } } if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { From dedb2373975a68d76fe55f622212bdf0612e3d3e Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 25 Mar 2019 15:16:35 +0800 Subject: [PATCH 5/7] fix trans --- executor/simple.go | 29 ++++++++++++++--------------- executor/simple_test.go | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/executor/simple.go b/executor/simple.go index c7be52bd9fdcb..de255a139dd4e 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -284,26 +284,28 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { for _, role := range s.Roles { exists, err := userExists(e.ctx, role.Username, role.Hostname) if err != nil { - return errors.Trace(err) + return err } if !exists { return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", role.String()) } } - for _, user := range s.Users { exists, err := userExists(e.ctx, user.Username, user.Hostname) if err != nil { - return errors.Trace(err) + return err } if !exists { - failedUsers = append(failedUsers, user.String()) - continue - } - // begin a transaction to insert role graph edges. - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { - return errors.Trace(err) + return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", user.String()) } + } + + // begin a transaction to insert role graph edges. + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { + return errors.Trace(err) + } + + for _, user := range s.Users { for _, role := range s.Roles { sql := fmt.Sprintf(`INSERT IGNORE INTO %s.%s (FROM_HOST, FROM_USER, TO_HOST, TO_USER) VALUES ('%s','%s','%s','%s')`, mysql.SystemDB, mysql.RoleEdgeTable, role.Hostname, role.Username, user.Hostname, user.Username) if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { @@ -311,15 +313,12 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); err != nil { return errors.Trace(err) } - break + return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", user.String()) } } - if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { - failedUsers = append(failedUsers, user.String()) - } } - if len(failedUsers) > 0 { - return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", strings.Join(failedUsers, ",")) + if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { + return errors.Trace(err) } err := domain.GetDomain(e.ctx).PrivilegeHandle().Update(e.ctx.(sessionctx.Context)) return errors.Trace(err) diff --git a/executor/simple_test.go b/executor/simple_test.go index 2df5839b4c012..b20a15dbef8d8 100644 --- a/executor/simple_test.go +++ b/executor/simple_test.go @@ -133,7 +133,7 @@ func (s *testSuite3) TestRole(c *C) { _, err = tk.Exec(grantRoleSQL) c.Check(err, NotNil) result = tk.MustQuery(`SELECT FROM_USER FROM mysql.role_edges WHERE TO_USER="r_3" and TO_HOST="localhost"`) - result.Check(testkit.Rows("r_1")) + result.Check(nil) dropRoleSQL := `DROP ROLE IF EXISTS 'r_1'@'localhost' ;` tk.MustExec(dropRoleSQL) From 06b097c47d05a93c9dd3bcdefc8979ff0e9c0c60 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 25 Mar 2019 15:46:08 +0800 Subject: [PATCH 6/7] remove trace --- executor/simple.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/executor/simple.go b/executor/simple.go index de255a139dd4e..9d79ccd976cbb 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -302,7 +302,7 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { // begin a transaction to insert role graph edges. if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "begin"); err != nil { - return errors.Trace(err) + return err } for _, user := range s.Users { @@ -311,17 +311,17 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { failedUsers = append(failedUsers, user.String()) if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); err != nil { - return errors.Trace(err) + return err } return ErrCannotUser.GenWithStackByArgs("GRANT ROLE", user.String()) } } } if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "commit"); err != nil { - return errors.Trace(err) + return err } err := domain.GetDomain(e.ctx).PrivilegeHandle().Update(e.ctx.(sessionctx.Context)) - return errors.Trace(err) + return err } func (e *SimpleExec) executeDropUser(s *ast.DropUserStmt) error { From c0deb2a214398d045d3c9a33f0d2fe0e0ef8bf07 Mon Sep 17 00:00:00 2001 From: imtbkcat Date: Mon, 25 Mar 2019 19:29:20 +0800 Subject: [PATCH 7/7] add log --- executor/simple.go | 1 + 1 file changed, 1 insertion(+) diff --git a/executor/simple.go b/executor/simple.go index 9d79ccd976cbb..616187ac50558 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -310,6 +310,7 @@ func (e *SimpleExec) executeGrantRole(s *ast.GrantRoleStmt) error { sql := fmt.Sprintf(`INSERT IGNORE INTO %s.%s (FROM_HOST, FROM_USER, TO_HOST, TO_USER) VALUES ('%s','%s','%s','%s')`, mysql.SystemDB, mysql.RoleEdgeTable, role.Hostname, role.Username, user.Hostname, user.Username) if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), sql); err != nil { failedUsers = append(failedUsers, user.String()) + logutil.Logger(context.Background()).Error(fmt.Sprintf("Error occur when executing %s", sql)) if _, err := e.ctx.(sqlexec.SQLExecutor).Execute(context.Background(), "rollback"); err != nil { return err }