From 1690912375cb9961fce3c55ff91ce59c524b9524 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Wed, 8 May 2019 15:23:47 +0800 Subject: [PATCH] privilege,executor: update DBIsVisible() function for RBAC (#10261) --- executor/show.go | 20 +++++++++++++------- executor/simple.go | 6 ++++-- privilege/privilege.go | 2 +- privilege/privileges/privileges.go | 13 +++++++++++-- privilege/privileges/privileges_test.go | 17 ++++++++++++++++- 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/executor/show.go b/executor/show.go index 5d9b129755502..e6e01a2fbcbfc 100644 --- a/executor/show.go +++ b/executor/show.go @@ -238,7 +238,7 @@ func (e *ShowExec) fetchShowDatabases() error { // let information_schema be the first database moveInfoSchemaToFront(dbs) for _, d := range dbs { - if checker != nil && !checker.DBIsVisible(d) { + if checker != nil && !checker.DBIsVisible(e.ctx.GetSessionVars().ActiveRoles, d) { continue } e.appendRow([]interface{}{ @@ -283,8 +283,10 @@ func (e *ShowExec) fetchShowOpenTables() error { func (e *ShowExec) fetchShowTables() error { checker := privilege.GetPrivilegeManager(e.ctx) - if checker != nil && e.ctx.GetSessionVars().User != nil && !checker.DBIsVisible(e.DBName.O) { - return e.dbAccessDenied() + if checker != nil && e.ctx.GetSessionVars().User != nil { + if !checker.DBIsVisible(e.ctx.GetSessionVars().ActiveRoles, e.DBName.O) { + return e.dbAccessDenied() + } } if !e.is.SchemaExists(e.DBName) { return ErrBadDB.GenWithStackByArgs(e.DBName) @@ -319,8 +321,10 @@ func (e *ShowExec) fetchShowTables() error { func (e *ShowExec) fetchShowTableStatus() error { checker := privilege.GetPrivilegeManager(e.ctx) - if checker != nil && e.ctx.GetSessionVars().User != nil && !checker.DBIsVisible(e.DBName.O) { - return e.dbAccessDenied() + if checker != nil && e.ctx.GetSessionVars().User != nil { + if !checker.DBIsVisible(e.ctx.GetSessionVars().ActiveRoles, e.DBName.O) { + return e.dbAccessDenied() + } } if !e.is.SchemaExists(e.DBName) { return ErrBadDB.GenWithStackByArgs(e.DBName) @@ -883,8 +887,10 @@ func appendPartitionInfo(partitionInfo *model.PartitionInfo, buf *bytes.Buffer) // fetchShowCreateDatabase composes show create database result. func (e *ShowExec) fetchShowCreateDatabase() error { checker := privilege.GetPrivilegeManager(e.ctx) - if checker != nil && e.ctx.GetSessionVars().User != nil && !checker.DBIsVisible(fmt.Sprint(e.DBName)) { - return e.dbAccessDenied() + if checker != nil && e.ctx.GetSessionVars().User != nil { + if !checker.DBIsVisible(e.ctx.GetSessionVars().ActiveRoles, e.DBName.String()) { + return e.dbAccessDenied() + } } db, ok := e.is.SchemaByName(e.DBName) if !ok { diff --git a/executor/simple.go b/executor/simple.go index 1cf8d35ecfccd..f742e86844931 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -363,8 +363,10 @@ func (e *SimpleExec) executeUse(s *ast.UseStmt) error { dbname := model.NewCIStr(s.DBName) checker := privilege.GetPrivilegeManager(e.ctx) - if checker != nil && e.ctx.GetSessionVars().User != nil && !checker.DBIsVisible(fmt.Sprint(dbname)) { - return e.dbAccessDenied(dbname.O) + if checker != nil && e.ctx.GetSessionVars().User != nil { + if !checker.DBIsVisible(e.ctx.GetSessionVars().ActiveRoles, dbname.String()) { + return e.dbAccessDenied(dbname.O) + } } dbinfo, exists := e.is.SchemaByName(dbname) diff --git a/privilege/privilege.go b/privilege/privilege.go index 5294f88ea2dea..9362239618441 100644 --- a/privilege/privilege.go +++ b/privilege/privilege.go @@ -48,7 +48,7 @@ type Manager interface { ConnectionVerification(user, host string, auth, salt []byte) (string, string, bool) // DBIsVisible returns true is the database is visible to current user. - DBIsVisible(db string) bool + DBIsVisible(activeRole []*auth.RoleIdentity, db string) bool // UserPrivilegesTable provide data for INFORMATION_SCHEMA.USERS_PRIVILEGE table. UserPrivilegesTable() [][]types.Datum diff --git a/privilege/privileges/privileges.go b/privilege/privileges/privileges.go index 06db3511499c6..b9a74b09df24f 100644 --- a/privilege/privileges/privileges.go +++ b/privilege/privileges/privileges.go @@ -160,12 +160,21 @@ func (p *UserPrivileges) ConnectionVerification(user, host string, authenticatio } // DBIsVisible implements the Manager interface. -func (p *UserPrivileges) DBIsVisible(db string) bool { +func (p *UserPrivileges) DBIsVisible(activeRoles []*auth.RoleIdentity, db string) bool { if SkipWithGrant { return true } mysqlPriv := p.Handle.Get() - return mysqlPriv.DBIsVisible(p.user, p.host, db) + if mysqlPriv.DBIsVisible(p.user, p.host, db) { + return true + } + allRoles := mysqlPriv.FindAllRole(activeRoles) + for _, role := range allRoles { + if mysqlPriv.DBIsVisible(role.Username, role.Hostname, db) { + return true + } + } + return false } // UserPrivilegesTable implements the Manager interface. diff --git a/privilege/privileges/privileges_test.go b/privilege/privileges/privileges_test.go index 114bac6d19854..82b80cbc8c752 100644 --- a/privilege/privileges/privileges_test.go +++ b/privilege/privileges/privileges_test.go @@ -445,7 +445,7 @@ func (s *testPrivilegeSuite) TestCheckAuthenticate(c *C) { mustExec(c, se1, "drop user 'r3@example.com'@'localhost'") } -func (s *testPrivilegeSuite) TestUseDb(c *C) { +func (s *testPrivilegeSuite) TestUseDB(c *C) { se := newSession(c, s.store, s.dbName) // high privileged user @@ -465,6 +465,21 @@ func (s *testPrivilegeSuite) TestUseDb(c *C) { c.Assert(se.Auth(&auth.UserIdentity{Username: "usenobody", Hostname: "localhost", AuthUsername: "usenobody", AuthHostname: "%"}, nil, nil), IsTrue) _, err = se.Execute(context.Background(), "use mysql") c.Assert(err, IsNil) + + // test `use db` for role. + c.Assert(se.Auth(&auth.UserIdentity{Username: "usesuper", Hostname: "localhost", AuthUsername: "usesuper", AuthHostname: "%"}, nil, nil), IsTrue) + mustExec(c, se, `CREATE DATABASE app_db`) + mustExec(c, se, `CREATE ROLE 'app_developer'`) + mustExec(c, se, `GRANT ALL ON app_db.* TO 'app_developer'`) + mustExec(c, se, `CREATE USER 'dev'@'localhost'`) + mustExec(c, se, `GRANT 'app_developer' TO 'dev'@'localhost'`) + mustExec(c, se, `SET DEFAULT ROLE 'app_developer' TO 'dev'@'localhost'`) + mustExec(c, se, `FLUSH PRIVILEGES`) + c.Assert(se.Auth(&auth.UserIdentity{Username: "dev", Hostname: "localhost", AuthUsername: "dev", AuthHostname: "localhost"}, nil, nil), IsTrue) + _, err = se.Execute(context.Background(), "use app_db") + c.Assert(err, IsNil) + _, err = se.Execute(context.Background(), "use mysql") + c.Assert(err, NotNil) } func (s *testPrivilegeSuite) TestSetGlobal(c *C) {