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

priviege, executor: add set role option #10268

Merged
merged 3 commits into from May 8, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

Next

add set role option

  • Loading branch information...
imtbkcat committed Apr 25, 2019
commit 46238e7ab83eae4c7d0ed47f356fa7d8fa4af6a0
@@ -233,7 +233,8 @@ func (e *SimpleExec) executeSetDefaultRole(s *ast.SetDefaultRoleStmt) error {
return err
}

func (e *SimpleExec) executeSetRole(s *ast.SetRoleStmt) error {
func (e *SimpleExec) setRoleRegular(s *ast.SetRoleStmt) error {
// Deal with SQL like `SET ROLE role1, role2;`
checkDup := make(map[string]*auth.RoleIdentity, len(s.RoleList))
// Check whether RoleNameList contain duplicate role name.
for _, r := range s.RoleList {
@@ -254,6 +255,89 @@ func (e *SimpleExec) executeSetRole(s *ast.SetRoleStmt) error {
return nil
}

func (e *SimpleExec) setRoleAll(s *ast.SetRoleStmt) error {
// Deal with SQL like `SET ROLE ALL;`
checker := privilege.GetPrivilegeManager(e.ctx)
user, host := e.ctx.GetSessionVars().User.AuthUsername, e.ctx.GetSessionVars().User.AuthHostname
roles := checker.GetAllRoles(user, host)
ok, roleName := checker.ActiveRoles(e.ctx, roles)
if !ok {
u := e.ctx.GetSessionVars().User
return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
}
return nil
}

func (e *SimpleExec) setRoleAllExcept(s *ast.SetRoleStmt) error {
// Deal with SQL like `SET ROLE ALL EXCEPT role1, role2;`
for _, r := range s.RoleList {
if r.Hostname == "" {
r.Hostname = "%"
}
}
checker := privilege.GetPrivilegeManager(e.ctx)
user, host := e.ctx.GetSessionVars().User.AuthUsername, e.ctx.GetSessionVars().User.AuthHostname
roles, afterExcept := checker.GetAllRoles(user, host), make([]*auth.RoleIdentity, 0)

This comment has been minimized.

Copy link
@tiancaiamao

tiancaiamao Apr 30, 2019

Contributor

make([]*auth.RoleIdentity, 0, len(s.RoleList))

for _, r := range roles {

This comment has been minimized.

Copy link
@tiancaiamao

tiancaiamao Apr 30, 2019

Contributor

It remind me of functional programming...

func filter(arr []*auth.RoleIdentity, fn f(*auth.RoleIdentity) bool) []*auth.RoleIdentity {
     i, j := 0,0
     for i:=0; i<len(arr); i++ {
         if f(arr[i]) {
            arr[j] = arr[i]
            j++
         }
     }
     return arr[:j]
}

banned := func(*auth.RoleIdentity) bool {
          for _, ban := range s.RoleList {
              if ban.Hostname == r.Hostname && ban.Username == r.Username {
                 return true
			        }        
          }
          return false
}

filter(roles, not(banned))
flag := true
for _, ban := range s.RoleList {
if ban.Hostname == r.Hostname && ban.Username == r.Username {
flag = false
}
}
if flag {
afterExcept = append(afterExcept, r)
}
}
ok, roleName := checker.ActiveRoles(e.ctx, afterExcept)
if !ok {
u := e.ctx.GetSessionVars().User
return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
}
return nil
}

func (e *SimpleExec) setRoleDefault(s *ast.SetRoleStmt) error {
// Deal with SQL like `SET ROLE DEFAULT;`
checker := privilege.GetPrivilegeManager(e.ctx)
user, host := e.ctx.GetSessionVars().User.AuthUsername, e.ctx.GetSessionVars().User.AuthHostname
roles := checker.GetDefaultRoles(user, host)
ok, roleName := checker.ActiveRoles(e.ctx, roles)
if !ok {
u := e.ctx.GetSessionVars().User
return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
}
return nil
}

func (e *SimpleExec) setRoleNone(s *ast.SetRoleStmt) error {
// Deal with SQL like `SET ROLE NONE;`
checker := privilege.GetPrivilegeManager(e.ctx)
roles := make([]*auth.RoleIdentity, 0)
ok, roleName := checker.ActiveRoles(e.ctx, roles)

This comment has been minimized.

Copy link
@tiancaiamao

tiancaiamao Apr 30, 2019

Contributor

checker.ActiveRoles(e.ctx, nil) ?

if !ok {
u := e.ctx.GetSessionVars().User
return ErrRoleNotGranted.GenWithStackByArgs(roleName, u.String())
}
return nil
}

func (e *SimpleExec) executeSetRole(s *ast.SetRoleStmt) error {
switch s.SetRoleOpt {
case ast.SetRoleRegular:
return e.setRoleRegular(s)
case ast.SetRoleAll:
return e.setRoleAll(s)
case ast.SetRoleAllExcept:
return e.setRoleAllExcept(s)
case ast.SetRoleNone:
return e.setRoleNone(s)
case ast.SetRoleDefault:
return e.setRoleDefault(s)
}
return nil
}

func (e *SimpleExec) dbAccessDenied(dbname string) error {
user := e.ctx.GetSessionVars().User
u := user.Username
@@ -62,6 +62,9 @@ type Manager interface {

// GetDefaultRoles returns all default roles for certain user.
GetDefaultRoles(user, host string) []*auth.RoleIdentity

// GetAllRoles return all roles of user.
GetAllRoles(user, host string) []*auth.RoleIdentity
}

const key keyType = 0
@@ -940,6 +940,18 @@ func (p *MySQLPrivilege) getDefaultRoles(user, host string) []*auth.RoleIdentity
return ret
}

func (p *MySQLPrivilege) getAllRoles(user, host string) []*auth.RoleIdentity {
ret := make([]*auth.RoleIdentity, 0)
key := user + "@" + host
edgeTable, ok := p.RoleGraph[key]

This comment has been minimized.

Copy link
@tiancaiamao

tiancaiamao Apr 30, 2019

Contributor
if !ok {
    return nil
}

ret := make([]*auth.RoleIdentity, 0, len(edgeTable.roleList))

When you're writing Go, remind:

  1. test the branch that could return early
  2. write cap for make() whenever possible

This comment has been minimized.

Copy link
@imtbkcat

imtbkcat May 5, 2019

Author Contributor

fixed @tiancaiamao

if ok {
for _, r := range edgeTable.roleList {
ret = append(ret, r)
}
}
return ret
}

// Handle wraps MySQLPrivilege providing thread safe access.
type Handle struct {
priv atomic.Value
@@ -224,3 +224,9 @@ func (p *UserPrivileges) GetDefaultRoles(user, host string) []*auth.RoleIdentity
ret := mysqlPrivilege.getDefaultRoles(user, host)
return ret
}

// GetAllRoles return all roles of user.
func (p *UserPrivileges) GetAllRoles(user, host string) []*auth.RoleIdentity {
mysqlPrivilege := p.Handle.Get()
return mysqlPrivilege.getAllRoles(user, host)
}
@@ -171,6 +171,7 @@ func (s *testPrivilegeSuite) TestCheckPrivilegeWithRoles(c *C) {
se := newSession(c, s.store, s.dbName)
c.Assert(se.Auth(&auth.UserIdentity{Username: "test_role", Hostname: "localhost"}, nil, nil), IsTrue)
mustExec(c, se, `SET ROLE r_1, r_2;`)
mustExec(c, rootSe, `SET DEFAULT ROLE r_1 TO 'test_role'@'localhost';`)

mustExec(c, rootSe, `GRANT SELECT ON test.* TO r_1;`)
pc := privilege.GetPrivilegeManager(se)
@@ -179,6 +180,16 @@ func (s *testPrivilegeSuite) TestCheckPrivilegeWithRoles(c *C) {
c.Assert(pc.RequestVerification(activeRoles, "test", "", "", mysql.UpdatePriv), IsFalse)
mustExec(c, rootSe, `GRANT UPDATE ON test.* TO r_2;`)
c.Assert(pc.RequestVerification(activeRoles, "test", "", "", mysql.UpdatePriv), IsTrue)

mustExec(c, se, `flush privileges`)
mustExec(c, se, `SET ROLE NONE;`)
c.Assert(len(se.GetSessionVars().ActiveRoles), Equals, 0)
mustExec(c, se, `SET ROLE DEFAULT;`)
c.Assert(len(se.GetSessionVars().ActiveRoles), Equals, 1)
mustExec(c, se, `SET ROLE ALL;`)
c.Assert(len(se.GetSessionVars().ActiveRoles), Equals, 3)
mustExec(c, se, `SET ROLE ALL EXCEPT r_1, r_2;`)
c.Assert(len(se.GetSessionVars().ActiveRoles), Equals, 1)
}

func (s *testPrivilegeSuite) TestShowGrants(c *C) {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.