From d896db6d3012125a2b22fd7c6ea30c7df1d4639b Mon Sep 17 00:00:00 2001 From: Karl Persson Date: Wed, 14 Sep 2022 15:14:09 +0200 Subject: [PATCH] RBAC: Batch permission creation (#55075) --- .../resourcepermissions/store.go | 96 ++++++++----------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/pkg/services/accesscontrol/resourcepermissions/store.go b/pkg/services/accesscontrol/resourcepermissions/store.go index 76f6702468a..12aa1246614 100644 --- a/pkg/services/accesscontrol/resourcepermissions/store.go +++ b/pkg/services/accesscontrol/resourcepermissions/store.go @@ -6,13 +6,12 @@ import ( "strings" "time" - "github.com/grafana/grafana/pkg/util" - "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/util" ) func NewStore(sql *sqlstore.SQLStore) *store { @@ -208,14 +207,7 @@ func (s *store) setResourcePermission( return nil, err } - rawSQL := ` - SELECT - p.* - FROM permission as p - INNER JOIN role r on r.id = p.role_id - WHERE r.id = ? - AND p.scope = ? - ` + rawSQL := `SELECT p.* FROM permission as p INNER JOIN role r on r.id = p.role_id WHERE r.id = ? AND p.scope = ?` var current []accesscontrol.Permission scope := accesscontrol.Scope(cmd.Resource, cmd.ResourceAttribute, cmd.ResourceID) @@ -228,11 +220,9 @@ func (s *store) setResourcePermission( missing[a] = struct{}{} } - var keep []int64 var remove []int64 for _, p := range current { if _, ok := missing[p.Action]; ok { - keep = append(keep, p.ID) delete(missing, p.Action) } else if !ok { remove = append(remove, p.ID) @@ -243,15 +233,11 @@ func (s *store) setResourcePermission( return nil, err } - for action := range missing { - id, err := s.createResourcePermission(sess, role.ID, action, cmd.Resource, cmd.ResourceID, cmd.ResourceAttribute) - if err != nil { - return nil, err - } - keep = append(keep, id) + if err := s.createPermissions(sess, role.ID, cmd.Resource, cmd.ResourceID, cmd.ResourceAttribute, missing); err != nil { + return nil, err } - permissions, err := s.getResourcePermissionsByIds(sess, cmd.Resource, cmd.ResourceID, cmd.ResourceAttribute, keep) + permissions, err := s.getPermissions(sess, cmd.Resource, cmd.ResourceID, cmd.ResourceAttribute, role.ID) if err != nil { return nil, err } @@ -276,18 +262,6 @@ func (s *store) GetResourcePermissions(ctx context.Context, orgID int64, query G return result, err } -func (s *store) createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, resource, resourceID, resourceAttribute string) (int64, error) { - permission := managedPermission(action, resource, resourceID, resourceAttribute) - permission.RoleID = roleID - permission.Created = time.Now() - permission.Updated = time.Now() - - if _, err := sess.Insert(&permission); err != nil { - return 0, err - } - return permission.ID, nil -} - func (s *store) getResourcePermissions(sess *sqlstore.DBSession, orgID int64, query GetResourcePermissionsQuery) ([]accesscontrol.ResourcePermission, error) { if len(query.Actions) == 0 { return nil, nil @@ -582,11 +556,25 @@ func (s *store) getOrCreateManagedRole(sess *sqlstore.DBSession, orgID int64, na return &role, nil } -func (s *store) getResourcePermissionsByIds(sess *sqlstore.DBSession, resource, resourceID, resourceAttribute string, ids []int64) ([]flatResourcePermission, error) { - var result []flatResourcePermission - if len(ids) == 0 { - return result, nil +func generateNewRoleUID(sess *sqlstore.DBSession, orgID int64) (string, error) { + for i := 0; i < 3; i++ { + uid := util.GenerateShortUID() + + exists, err := sess.Where("org_id=? AND uid=?", orgID, uid).Get(&accesscontrol.Role{}) + if err != nil { + return "", err + } + + if !exists { + return uid, nil + } } + + return "", fmt.Errorf("failed to generate uid") +} + +func (s *store) getPermissions(sess *sqlstore.DBSession, resource, resourceID, resourceAttribute string, roleID int64) ([]flatResourcePermission, error) { + var result []flatResourcePermission rawSql := ` SELECT p.*, @@ -605,36 +593,32 @@ func (s *store) getResourcePermissionsByIds(sess *sqlstore.DBSession, resource, LEFT JOIN user_role ur ON r.id = ur.role_id LEFT JOIN ` + s.sql.Dialect.Quote("user") + ` u ON ur.user_id = u.id LEFT JOIN builtin_role br ON r.id = br.role_id - WHERE p.id IN (?` + strings.Repeat(",?", len(ids)-1) + `) + WHERE r.id = ? AND p.scope = ? ` - - args := make([]interface{}, 0, len(ids)+1) - for _, id := range ids { - args = append(args, id) - } - - if err := sess.SQL(rawSql, args...).Find(&result); err != nil { + if err := sess.SQL(rawSql, roleID, accesscontrol.Scope(resource, resourceAttribute, resourceID)).Find(&result); err != nil { return nil, err } return result, nil } -func generateNewRoleUID(sess *sqlstore.DBSession, orgID int64) (string, error) { - for i := 0; i < 3; i++ { - uid := util.GenerateShortUID() - - exists, err := sess.Where("org_id=? AND uid=?", orgID, uid).Get(&accesscontrol.Role{}) - if err != nil { - return "", err - } - - if !exists { - return uid, nil - } +func (s *store) createPermissions(sess *sqlstore.DBSession, roleID int64, resource, resourceID, resourceAttribute string, actions map[string]struct{}) error { + if len(actions) == 0 { + return nil + } + var permissions []accesscontrol.Permission + for action := range actions { + p := managedPermission(action, resource, resourceID, resourceAttribute) + p.RoleID = roleID + p.Created = time.Now() + p.Updated = time.Now() + permissions = append(permissions, p) } - return "", fmt.Errorf("failed to generate uid") + if _, err := sess.InsertMulti(&permissions); err != nil { + return err + } + return nil } func deletePermissions(sess *sqlstore.DBSession, ids []int64) error {