mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Access Control: Add function to set several permissions on a resource in one transaction (#44768)
This commit is contained in:
parent
178193c84b
commit
922b9465ec
@ -42,6 +42,8 @@ type ResourcePermissionsService interface {
|
|||||||
SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID, permission string) (*ResourcePermission, error)
|
SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID, permission string) (*ResourcePermission, error)
|
||||||
// SetBuiltInRolePermission sets permission on resource for a built-in role (Admin, Editor, Viewer)
|
// SetBuiltInRolePermission sets permission on resource for a built-in role (Admin, Editor, Viewer)
|
||||||
SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole string, resourceID string, permission string) (*ResourcePermission, error)
|
SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole string, resourceID string, permission string) (*ResourcePermission, error)
|
||||||
|
// SetPermissions sets several permissions on resource for either built-in role, team or user
|
||||||
|
SetPermissions(ctx context.Context, orgID int64, resourceID string, commands ...SetResourcePermissionCommand) ([]ResourcePermission, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
|||||||
user, team := createUserAndTeam(t, sql, tt.orgID)
|
user, team := createUserAndTeam(t, sql, tt.orgID)
|
||||||
|
|
||||||
for _, id := range tt.userPermissions {
|
for _, id := range tt.userPermissions {
|
||||||
_, err := store.SetUserResourcePermission(context.Background(), tt.orgID, accesscontrol.User{ID: user.Id}, accesscontrol.SetResourcePermissionCommand{
|
_, err := store.SetUserResourcePermission(context.Background(), tt.orgID, accesscontrol.User{ID: user.Id}, types.SetResourcePermissionCommand{
|
||||||
Actions: []string{"dashboards:write"},
|
Actions: []string{"dashboards:write"},
|
||||||
Resource: "dashboards",
|
Resource: "dashboards",
|
||||||
ResourceID: id,
|
ResourceID: id,
|
||||||
@ -89,7 +90,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, id := range tt.teamPermissions {
|
for _, id := range tt.teamPermissions {
|
||||||
_, err := store.SetTeamResourcePermission(context.Background(), tt.orgID, team.Id, accesscontrol.SetResourcePermissionCommand{
|
_, err := store.SetTeamResourcePermission(context.Background(), tt.orgID, team.Id, types.SetResourcePermissionCommand{
|
||||||
Actions: []string{"dashboards:read"},
|
Actions: []string{"dashboards:read"},
|
||||||
Resource: "dashboards",
|
Resource: "dashboards",
|
||||||
ResourceID: id,
|
ResourceID: id,
|
||||||
@ -98,7 +99,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, id := range tt.builtinPermissions {
|
for _, id := range tt.builtinPermissions {
|
||||||
_, err := store.SetBuiltInResourcePermission(context.Background(), tt.orgID, "Admin", accesscontrol.SetResourcePermissionCommand{
|
_, err := store.SetBuiltInResourcePermission(context.Background(), tt.orgID, "Admin", types.SetResourcePermissionCommand{
|
||||||
Actions: []string{"dashboards:read"},
|
Actions: []string{"dashboards:read"},
|
||||||
Resource: "dashboards",
|
Resource: "dashboards",
|
||||||
ResourceID: id,
|
ResourceID: id,
|
||||||
|
@ -35,7 +35,7 @@ func (p *flatResourcePermission) Managed() bool {
|
|||||||
|
|
||||||
func (s *AccessControlStore) SetUserResourcePermission(
|
func (s *AccessControlStore) SetUserResourcePermission(
|
||||||
ctx context.Context, orgID int64, user accesscontrol.User,
|
ctx context.Context, orgID int64, user accesscontrol.User,
|
||||||
cmd accesscontrol.SetResourcePermissionCommand,
|
cmd types.SetResourcePermissionCommand,
|
||||||
hook types.UserResourceHookFunc,
|
hook types.UserResourceHookFunc,
|
||||||
) (*accesscontrol.ResourcePermission, error) {
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
if user.ID == 0 {
|
if user.ID == 0 {
|
||||||
@ -45,24 +45,34 @@ func (s *AccessControlStore) SetUserResourcePermission(
|
|||||||
var err error
|
var err error
|
||||||
var permission *accesscontrol.ResourcePermission
|
var permission *accesscontrol.ResourcePermission
|
||||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
permission, err = s.setResourcePermission(sess, orgID, managedUserRoleName(user.ID), s.userAdder(sess, orgID, user.ID), cmd)
|
permission, err = s.setUserResourcePermission(sess, orgID, user, cmd, hook)
|
||||||
if err == nil && hook != nil {
|
|
||||||
return hook(sess, orgID, user, cmd.ResourceID, cmd.Permission)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return permission, err
|
||||||
|
}
|
||||||
|
func (s *AccessControlStore) setUserResourcePermission(
|
||||||
|
sess *sqlstore.DBSession, orgID int64, user accesscontrol.User,
|
||||||
|
cmd types.SetResourcePermissionCommand,
|
||||||
|
hook types.UserResourceHookFunc,
|
||||||
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
|
permission, err := s.setResourcePermission(sess, orgID, managedUserRoleName(user.ID), s.userAdder(sess, orgID, user.ID), cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hook != nil {
|
||||||
|
if err := hook(sess, orgID, user, cmd.ResourceID, cmd.Permission); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return permission, nil
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessControlStore) SetTeamResourcePermission(
|
func (s *AccessControlStore) SetTeamResourcePermission(
|
||||||
ctx context.Context, orgID, teamID int64,
|
ctx context.Context, orgID, teamID int64,
|
||||||
cmd accesscontrol.SetResourcePermissionCommand,
|
cmd types.SetResourcePermissionCommand,
|
||||||
hook types.TeamResourceHookFunc,
|
hook types.TeamResourceHookFunc,
|
||||||
) (*accesscontrol.ResourcePermission, error) {
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
if teamID == 0 {
|
if teamID == 0 {
|
||||||
@ -73,24 +83,35 @@ func (s *AccessControlStore) SetTeamResourcePermission(
|
|||||||
var permission *accesscontrol.ResourcePermission
|
var permission *accesscontrol.ResourcePermission
|
||||||
|
|
||||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
permission, err = s.setResourcePermission(sess, orgID, managedTeamRoleName(teamID), s.teamAdder(sess, orgID, teamID), cmd)
|
permission, err = s.setTeamResourcePermission(sess, orgID, teamID, cmd, hook)
|
||||||
if err == nil && hook != nil {
|
|
||||||
return hook(sess, orgID, teamID, cmd.ResourceID, cmd.Permission)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return permission, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AccessControlStore) setTeamResourcePermission(
|
||||||
|
sess *sqlstore.DBSession, orgID, teamID int64,
|
||||||
|
cmd types.SetResourcePermissionCommand,
|
||||||
|
hook types.TeamResourceHookFunc,
|
||||||
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
|
permission, err := s.setResourcePermission(sess, orgID, managedTeamRoleName(teamID), s.teamAdder(sess, orgID, teamID), cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hook != nil {
|
||||||
|
if err := hook(sess, orgID, teamID, cmd.ResourceID, cmd.Permission); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return permission, nil
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessControlStore) SetBuiltInResourcePermission(
|
func (s *AccessControlStore) SetBuiltInResourcePermission(
|
||||||
ctx context.Context, orgID int64, builtInRole string,
|
ctx context.Context, orgID int64, builtInRole string,
|
||||||
cmd accesscontrol.SetResourcePermissionCommand,
|
cmd types.SetResourcePermissionCommand,
|
||||||
hook types.BuiltinResourceHookFunc,
|
hook types.BuiltinResourceHookFunc,
|
||||||
) (*accesscontrol.ResourcePermission, error) {
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
if !models.RoleType(builtInRole).IsValid() || builtInRole == accesscontrol.RoleGrafanaAdmin {
|
if !models.RoleType(builtInRole).IsValid() || builtInRole == accesscontrol.RoleGrafanaAdmin {
|
||||||
@ -101,10 +122,7 @@ func (s *AccessControlStore) SetBuiltInResourcePermission(
|
|||||||
var permission *accesscontrol.ResourcePermission
|
var permission *accesscontrol.ResourcePermission
|
||||||
|
|
||||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
permission, err = s.setResourcePermission(sess, orgID, managedBuiltInRoleName(builtInRole), s.builtInRoleAdder(sess, orgID, builtInRole), cmd)
|
permission, err = s.setBuiltInResourcePermission(sess, orgID, builtInRole, cmd, hook)
|
||||||
if err == nil && hook != nil {
|
|
||||||
return hook(sess, orgID, builtInRole, cmd.ResourceID, cmd.Permission)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -115,10 +133,61 @@ func (s *AccessControlStore) SetBuiltInResourcePermission(
|
|||||||
return permission, nil
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AccessControlStore) setBuiltInResourcePermission(
|
||||||
|
sess *sqlstore.DBSession, orgID int64, builtInRole string,
|
||||||
|
cmd types.SetResourcePermissionCommand,
|
||||||
|
hook types.BuiltinResourceHookFunc,
|
||||||
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
|
permission, err := s.setResourcePermission(sess, orgID, managedBuiltInRoleName(builtInRole), s.builtInRoleAdder(sess, orgID, builtInRole), cmd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if hook != nil {
|
||||||
|
if err := hook(sess, orgID, builtInRole, cmd.ResourceID, cmd.Permission); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return permission, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AccessControlStore) SetResourcePermissions(
|
||||||
|
ctx context.Context, orgID int64,
|
||||||
|
commands []types.SetResourcePermissionsCommand,
|
||||||
|
hooks types.ResourceHooks,
|
||||||
|
) ([]accesscontrol.ResourcePermission, error) {
|
||||||
|
var err error
|
||||||
|
var permissions []accesscontrol.ResourcePermission
|
||||||
|
|
||||||
|
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
for _, cmd := range commands {
|
||||||
|
var p *accesscontrol.ResourcePermission
|
||||||
|
if cmd.User.ID != 0 {
|
||||||
|
p, err = s.setUserResourcePermission(sess, orgID, cmd.User, cmd.SetResourcePermissionCommand, hooks.User)
|
||||||
|
} else if cmd.TeamID != 0 {
|
||||||
|
p, err = s.setTeamResourcePermission(sess, orgID, cmd.TeamID, cmd.SetResourcePermissionCommand, hooks.Team)
|
||||||
|
} else if models.RoleType(cmd.BuiltinRole).IsValid() || cmd.BuiltinRole == accesscontrol.RoleGrafanaAdmin {
|
||||||
|
p, err = s.setBuiltInResourcePermission(sess, orgID, cmd.BuiltinRole, cmd.SetResourcePermissionCommand, hooks.BuiltInRole)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if p != nil {
|
||||||
|
permissions = append(permissions, *p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return permissions, err
|
||||||
|
}
|
||||||
|
|
||||||
type roleAdder func(roleID int64) error
|
type roleAdder func(roleID int64) error
|
||||||
|
|
||||||
func (s *AccessControlStore) setResourcePermission(
|
func (s *AccessControlStore) setResourcePermission(
|
||||||
sess *sqlstore.DBSession, orgID int64, roleName string, adder roleAdder, cmd accesscontrol.SetResourcePermissionCommand,
|
sess *sqlstore.DBSession, orgID int64, roleName string, adder roleAdder, cmd types.SetResourcePermissionCommand,
|
||||||
) (*accesscontrol.ResourcePermission, error) {
|
) (*accesscontrol.ResourcePermission, error) {
|
||||||
role, err := s.getOrCreateManagedRole(sess, orgID, roleName, adder)
|
role, err := s.getOrCreateManagedRole(sess, orgID, roleName, adder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -159,22 +228,20 @@ func (s *AccessControlStore) setResourcePermission(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var permissions []flatResourcePermission
|
|
||||||
|
|
||||||
for action := range missing {
|
for action := range missing {
|
||||||
p, err := s.createResourcePermission(sess, role.ID, action, cmd.Resource, cmd.ResourceID)
|
id, err := s.createResourcePermission(sess, role.ID, action, cmd.Resource, cmd.ResourceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
permissions = append(permissions, *p)
|
keep = append(keep, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
keptPermissions, err := s.getResourcePermissions(sess, cmd.ResourceID, keep)
|
permissions, err := s.getResourcePermissions(sess, cmd.ResourceID, keep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
permission := flatPermissionsToResourcePermission(append(permissions, keptPermissions...))
|
permission := flatPermissionsToResourcePermission(permissions)
|
||||||
if permission == nil {
|
if permission == nil {
|
||||||
return &accesscontrol.ResourcePermission{}, nil
|
return &accesscontrol.ResourcePermission{}, nil
|
||||||
}
|
}
|
||||||
@ -182,7 +249,7 @@ func (s *AccessControlStore) setResourcePermission(
|
|||||||
return permission, nil
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessControlStore) GetResourcesPermissions(ctx context.Context, orgID int64, query accesscontrol.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error) {
|
func (s *AccessControlStore) GetResourcesPermissions(ctx context.Context, orgID int64, query types.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error) {
|
||||||
var result []accesscontrol.ResourcePermission
|
var result []accesscontrol.ResourcePermission
|
||||||
|
|
||||||
err := s.sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
err := s.sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
@ -194,45 +261,19 @@ func (s *AccessControlStore) GetResourcesPermissions(ctx context.Context, orgID
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessControlStore) createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, resource string, resourceID string) (*flatResourcePermission, error) {
|
func (s *AccessControlStore) createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, resource string, resourceID string) (int64, error) {
|
||||||
permission := managedPermission(action, resource, resourceID)
|
permission := managedPermission(action, resource, resourceID)
|
||||||
permission.RoleID = roleID
|
permission.RoleID = roleID
|
||||||
permission.Created = time.Now()
|
permission.Created = time.Now()
|
||||||
permission.Updated = time.Now()
|
permission.Updated = time.Now()
|
||||||
|
|
||||||
if _, err := sess.Insert(&permission); err != nil {
|
if _, err := sess.Insert(&permission); err != nil {
|
||||||
return nil, err
|
return 0, err
|
||||||
|
}
|
||||||
|
return permission.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSql := `
|
func (s *AccessControlStore) getResourcesPermissions(sess *sqlstore.DBSession, orgID int64, query types.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error) {
|
||||||
SELECT
|
|
||||||
p.*,
|
|
||||||
? AS resource_id,
|
|
||||||
ur.user_id AS user_id,
|
|
||||||
u.login AS user_login,
|
|
||||||
u.email AS user_email,
|
|
||||||
tr.team_id AS team_id,
|
|
||||||
t.name AS team,
|
|
||||||
t.email AS team_email,
|
|
||||||
r.name as role_name
|
|
||||||
FROM permission p
|
|
||||||
LEFT JOIN role r ON p.role_id = r.id
|
|
||||||
LEFT JOIN team_role tr ON r.id = tr.role_id
|
|
||||||
LEFT JOIN team t ON tr.team_id = t.id
|
|
||||||
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
|
|
||||||
WHERE p.id = ?
|
|
||||||
`
|
|
||||||
|
|
||||||
p := &flatResourcePermission{}
|
|
||||||
if _, err := sess.SQL(rawSql, resourceID, permission.ID).Get(p); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AccessControlStore) getResourcesPermissions(sess *sqlstore.DBSession, orgID int64, query accesscontrol.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error) {
|
|
||||||
if len(query.Actions) == 0 {
|
if len(query.Actions) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -544,13 +585,15 @@ func (s *AccessControlStore) getResourcePermissions(sess *sqlstore.DBSession, re
|
|||||||
tr.team_id AS team_id,
|
tr.team_id AS team_id,
|
||||||
t.name AS team,
|
t.name AS team,
|
||||||
t.email AS team_email,
|
t.email AS team_email,
|
||||||
r.name as role_name
|
r.name as role_name,
|
||||||
|
br.role AS built_in_role
|
||||||
FROM permission p
|
FROM permission p
|
||||||
INNER JOIN role r ON p.role_id = r.id
|
INNER JOIN role r ON p.role_id = r.id
|
||||||
LEFT JOIN team_role tr ON r.id = tr.role_id
|
LEFT JOIN team_role tr ON r.id = tr.role_id
|
||||||
LEFT JOIN team t ON tr.team_id = t.id
|
LEFT JOIN team t ON tr.team_id = t.id
|
||||||
LEFT JOIN user_role ur ON r.id = ur.role_id
|
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 ` + 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 p.id IN (?` + strings.Repeat(",?", len(ids)-1) + `)
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ func benchmarkDSPermissions(b *testing.B, dsNum, usersNum int) {
|
|||||||
func getDSPermissions(b *testing.B, store *AccessControlStore, dataSources []int64) {
|
func getDSPermissions(b *testing.B, store *AccessControlStore, dataSources []int64) {
|
||||||
dsId := dataSources[0]
|
dsId := dataSources[0]
|
||||||
|
|
||||||
permissions, err := store.GetResourcesPermissions(context.Background(), accesscontrol.GlobalOrgID, accesscontrol.GetResourcesPermissionsQuery{
|
permissions, err := store.GetResourcesPermissions(context.Background(), accesscontrol.GlobalOrgID, types.GetResourcesPermissionsQuery{
|
||||||
Actions: []string{dsAction},
|
Actions: []string{dsAction},
|
||||||
Resource: dsResource,
|
Resource: dsResource,
|
||||||
ResourceIDs: []string{strconv.Itoa(int(dsId))},
|
ResourceIDs: []string{strconv.Itoa(int(dsId))},
|
||||||
@ -94,7 +95,7 @@ func GenerateDatasourcePermissions(b *testing.B, db *sqlstore.SQLStore, ac *Acce
|
|||||||
context.Background(),
|
context.Background(),
|
||||||
accesscontrol.GlobalOrgID,
|
accesscontrol.GlobalOrgID,
|
||||||
accesscontrol.User{ID: userIds[i]},
|
accesscontrol.User{ID: userIds[i]},
|
||||||
accesscontrol.SetResourcePermissionCommand{
|
types.SetResourcePermissionCommand{
|
||||||
Actions: []string{dsAction},
|
Actions: []string{dsAction},
|
||||||
Resource: dsResource,
|
Resource: dsResource,
|
||||||
ResourceID: strconv.Itoa(int(dsID)),
|
ResourceID: strconv.Itoa(int(dsID)),
|
||||||
@ -111,7 +112,7 @@ func GenerateDatasourcePermissions(b *testing.B, db *sqlstore.SQLStore, ac *Acce
|
|||||||
context.Background(),
|
context.Background(),
|
||||||
accesscontrol.GlobalOrgID,
|
accesscontrol.GlobalOrgID,
|
||||||
teamIds[i],
|
teamIds[i],
|
||||||
accesscontrol.SetResourcePermissionCommand{
|
types.SetResourcePermissionCommand{
|
||||||
Actions: []string{"datasources:query"},
|
Actions: []string{"datasources:query"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
ResourceID: strconv.Itoa(int(dsID)),
|
ResourceID: strconv.Itoa(int(dsID)),
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ type setUserResourcePermissionTest struct {
|
|||||||
actions []string
|
actions []string
|
||||||
resource string
|
resource string
|
||||||
resourceID string
|
resourceID string
|
||||||
seeds []accesscontrol.SetResourcePermissionCommand
|
seeds []types.SetResourcePermissionCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessControlStore_SetUserResourcePermission(t *testing.T) {
|
func TestAccessControlStore_SetUserResourcePermission(t *testing.T) {
|
||||||
@ -40,7 +41,7 @@ func TestAccessControlStore_SetUserResourcePermission(t *testing.T) {
|
|||||||
actions: []string{},
|
actions: []string{},
|
||||||
resource: "datasources",
|
resource: "datasources",
|
||||||
resourceID: "1",
|
resourceID: "1",
|
||||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
seeds: []types.SetResourcePermissionCommand{
|
||||||
{
|
{
|
||||||
Actions: []string{"datasources:query"},
|
Actions: []string{"datasources:query"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
@ -55,7 +56,7 @@ func TestAccessControlStore_SetUserResourcePermission(t *testing.T) {
|
|||||||
actions: []string{"datasources:query", "datasources:write"},
|
actions: []string{"datasources:query", "datasources:write"},
|
||||||
resource: "datasources",
|
resource: "datasources",
|
||||||
resourceID: "1",
|
resourceID: "1",
|
||||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
seeds: []types.SetResourcePermissionCommand{
|
||||||
{
|
{
|
||||||
Actions: []string{"datasources:write"},
|
Actions: []string{"datasources:write"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
@ -74,7 +75,7 @@ func TestAccessControlStore_SetUserResourcePermission(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
added, err := store.SetUserResourcePermission(context.Background(), test.userID, accesscontrol.User{ID: test.userID}, accesscontrol.SetResourcePermissionCommand{
|
added, err := store.SetUserResourcePermission(context.Background(), test.userID, accesscontrol.User{ID: test.userID}, types.SetResourcePermissionCommand{
|
||||||
Actions: test.actions,
|
Actions: test.actions,
|
||||||
Resource: test.resource,
|
Resource: test.resource,
|
||||||
ResourceID: test.resourceID,
|
ResourceID: test.resourceID,
|
||||||
@ -98,7 +99,7 @@ type setTeamResourcePermissionTest struct {
|
|||||||
actions []string
|
actions []string
|
||||||
resource string
|
resource string
|
||||||
resourceID string
|
resourceID string
|
||||||
seeds []accesscontrol.SetResourcePermissionCommand
|
seeds []types.SetResourcePermissionCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessControlStore_SetTeamResourcePermission(t *testing.T) {
|
func TestAccessControlStore_SetTeamResourcePermission(t *testing.T) {
|
||||||
@ -118,7 +119,7 @@ func TestAccessControlStore_SetTeamResourcePermission(t *testing.T) {
|
|||||||
actions: []string{"datasources:query", "datasources:write"},
|
actions: []string{"datasources:query", "datasources:write"},
|
||||||
resource: "datasources",
|
resource: "datasources",
|
||||||
resourceID: "1",
|
resourceID: "1",
|
||||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
seeds: []types.SetResourcePermissionCommand{
|
||||||
{
|
{
|
||||||
Actions: []string{"datasources:query"},
|
Actions: []string{"datasources:query"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
@ -133,7 +134,7 @@ func TestAccessControlStore_SetTeamResourcePermission(t *testing.T) {
|
|||||||
actions: []string{},
|
actions: []string{},
|
||||||
resource: "datasources",
|
resource: "datasources",
|
||||||
resourceID: "1",
|
resourceID: "1",
|
||||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
seeds: []types.SetResourcePermissionCommand{
|
||||||
{
|
{
|
||||||
Actions: []string{"datasources:query"},
|
Actions: []string{"datasources:query"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
@ -152,7 +153,7 @@ func TestAccessControlStore_SetTeamResourcePermission(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
added, err := store.SetTeamResourcePermission(context.Background(), test.orgID, test.teamID, accesscontrol.SetResourcePermissionCommand{
|
added, err := store.SetTeamResourcePermission(context.Background(), test.orgID, test.teamID, types.SetResourcePermissionCommand{
|
||||||
Actions: test.actions,
|
Actions: test.actions,
|
||||||
Resource: test.resource,
|
Resource: test.resource,
|
||||||
ResourceID: test.resourceID,
|
ResourceID: test.resourceID,
|
||||||
@ -176,7 +177,7 @@ type setBuiltInResourcePermissionTest struct {
|
|||||||
actions []string
|
actions []string
|
||||||
resource string
|
resource string
|
||||||
resourceID string
|
resourceID string
|
||||||
seeds []accesscontrol.SetResourcePermissionCommand
|
seeds []types.SetResourcePermissionCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
||||||
@ -196,7 +197,7 @@ func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
|||||||
actions: []string{"datasources:query", "datasources:write"},
|
actions: []string{"datasources:query", "datasources:write"},
|
||||||
resource: "datasources",
|
resource: "datasources",
|
||||||
resourceID: "1",
|
resourceID: "1",
|
||||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
seeds: []types.SetResourcePermissionCommand{
|
||||||
{
|
{
|
||||||
Actions: []string{"datasources:query"},
|
Actions: []string{"datasources:query"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
@ -211,7 +212,7 @@ func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
|||||||
actions: []string{},
|
actions: []string{},
|
||||||
resource: "datasources",
|
resource: "datasources",
|
||||||
resourceID: "1",
|
resourceID: "1",
|
||||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
seeds: []types.SetResourcePermissionCommand{
|
||||||
{
|
{
|
||||||
Actions: []string{"datasources:query"},
|
Actions: []string{"datasources:query"},
|
||||||
Resource: "datasources",
|
Resource: "datasources",
|
||||||
@ -230,7 +231,7 @@ func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
added, err := store.SetBuiltInResourcePermission(context.Background(), test.orgID, test.builtInRole, accesscontrol.SetResourcePermissionCommand{
|
added, err := store.SetBuiltInResourcePermission(context.Background(), test.orgID, test.builtInRole, types.SetResourcePermissionCommand{
|
||||||
Actions: test.actions,
|
Actions: test.actions,
|
||||||
Resource: test.resource,
|
Resource: test.resource,
|
||||||
ResourceID: test.resourceID,
|
ResourceID: test.resourceID,
|
||||||
@ -247,6 +248,69 @@ func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type setResourcePermissionsTest struct {
|
||||||
|
desc string
|
||||||
|
orgID int64
|
||||||
|
commands []types.SetResourcePermissionsCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccessControlStore_SetResourcePermissions(t *testing.T) {
|
||||||
|
tests := []setResourcePermissionsTest{
|
||||||
|
{
|
||||||
|
desc: "should set all permissions provided",
|
||||||
|
orgID: 1,
|
||||||
|
commands: []types.SetResourcePermissionsCommand{
|
||||||
|
{
|
||||||
|
User: accesscontrol.User{ID: 1},
|
||||||
|
SetResourcePermissionCommand: types.SetResourcePermissionCommand{
|
||||||
|
Actions: []string{"datasources:query"},
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TeamID: 3,
|
||||||
|
SetResourcePermissionCommand: types.SetResourcePermissionCommand{
|
||||||
|
Actions: []string{"datasources:query"},
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BuiltinRole: "Admin",
|
||||||
|
SetResourcePermissionCommand: types.SetResourcePermissionCommand{
|
||||||
|
Actions: []string{"datasources:query"},
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
store, _ := setupTestEnv(t)
|
||||||
|
|
||||||
|
permissions, err := store.SetResourcePermissions(context.Background(), tt.orgID, tt.commands, types.ResourceHooks{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, permissions, len(tt.commands))
|
||||||
|
for i, c := range tt.commands {
|
||||||
|
if len(c.Actions) == 0 {
|
||||||
|
assert.Equal(t, accesscontrol.ResourcePermission{}, permissions[i])
|
||||||
|
} else {
|
||||||
|
assert.Len(t, permissions[i].Actions, len(c.Actions))
|
||||||
|
assert.Equal(t, c.TeamID, permissions[i].TeamId)
|
||||||
|
assert.Equal(t, c.User.ID, permissions[i].UserId)
|
||||||
|
assert.Equal(t, c.BuiltinRole, permissions[i].BuiltInRole)
|
||||||
|
assert.Equal(t, accesscontrol.GetResourceScope(c.Resource, c.ResourceID), permissions[i].Scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type getResourcesPermissionsTest struct {
|
type getResourcesPermissionsTest struct {
|
||||||
desc string
|
desc string
|
||||||
numUsers int
|
numUsers int
|
||||||
@ -318,7 +382,7 @@ func TestAccessControlStore_GetResourcesPermissions(t *testing.T) {
|
|||||||
seedResourcePermissions(t, store, sql, test.actions, test.resource, id, test.numUsers)
|
seedResourcePermissions(t, store, sql, test.actions, test.resource, id, test.numUsers)
|
||||||
}
|
}
|
||||||
|
|
||||||
permissions, err := store.GetResourcesPermissions(context.Background(), 1, accesscontrol.GetResourcesPermissionsQuery{
|
permissions, err := store.GetResourcesPermissions(context.Background(), 1, types.GetResourcesPermissionsQuery{
|
||||||
Actions: test.actions,
|
Actions: test.actions,
|
||||||
Resource: test.resource,
|
Resource: test.resource,
|
||||||
ResourceIDs: test.resourceIDs,
|
ResourceIDs: test.resourceIDs,
|
||||||
@ -352,7 +416,7 @@ func seedResourcePermissions(t *testing.T, store *AccessControlStore, sql *sqlst
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: u.Id}, accesscontrol.SetResourcePermissionCommand{
|
_, err = store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: u.Id}, types.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
Resource: resource,
|
Resource: resource,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
|
@ -235,19 +235,12 @@ func (p *ResourcePermission) Contains(targetActions []string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SetResourcePermissionCommand struct {
|
type SetResourcePermissionCommand struct {
|
||||||
Actions []string
|
UserID int64
|
||||||
Resource string
|
TeamID int64
|
||||||
ResourceID string
|
BuiltinRole string
|
||||||
Permission string
|
Permission string
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetResourcesPermissionsQuery struct {
|
|
||||||
Actions []string
|
|
||||||
Resource string
|
|
||||||
ResourceIDs []string
|
|
||||||
OnlyManaged bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type SQLFilter struct {
|
type SQLFilter struct {
|
||||||
Where string
|
Where string
|
||||||
Args []interface{}
|
Args []interface{}
|
||||||
|
@ -18,26 +18,32 @@ type Store interface {
|
|||||||
SetUserResourcePermission(
|
SetUserResourcePermission(
|
||||||
ctx context.Context, orgID int64,
|
ctx context.Context, orgID int64,
|
||||||
user accesscontrol.User,
|
user accesscontrol.User,
|
||||||
cmd accesscontrol.SetResourcePermissionCommand,
|
cmd types.SetResourcePermissionCommand,
|
||||||
hook types.UserResourceHookFunc,
|
hook types.UserResourceHookFunc,
|
||||||
) (*accesscontrol.ResourcePermission, error)
|
) (*accesscontrol.ResourcePermission, error)
|
||||||
|
|
||||||
// SetTeamResourcePermission sets permission for managed team role on a resource
|
// SetTeamResourcePermission sets permission for managed team role on a resource
|
||||||
SetTeamResourcePermission(
|
SetTeamResourcePermission(
|
||||||
ctx context.Context, orgID, teamID int64,
|
ctx context.Context, orgID, teamID int64,
|
||||||
cmd accesscontrol.SetResourcePermissionCommand,
|
cmd types.SetResourcePermissionCommand,
|
||||||
hook types.TeamResourceHookFunc,
|
hook types.TeamResourceHookFunc,
|
||||||
) (*accesscontrol.ResourcePermission, error)
|
) (*accesscontrol.ResourcePermission, error)
|
||||||
|
|
||||||
// SetBuiltInResourcePermission sets permissions for managed builtin role on a resource
|
// SetBuiltInResourcePermission sets permissions for managed builtin role on a resource
|
||||||
SetBuiltInResourcePermission(
|
SetBuiltInResourcePermission(
|
||||||
ctx context.Context, orgID int64, builtinRole string,
|
ctx context.Context, orgID int64, builtinRole string,
|
||||||
cmd accesscontrol.SetResourcePermissionCommand,
|
cmd types.SetResourcePermissionCommand,
|
||||||
hook types.BuiltinResourceHookFunc,
|
hook types.BuiltinResourceHookFunc,
|
||||||
) (*accesscontrol.ResourcePermission, error)
|
) (*accesscontrol.ResourcePermission, error)
|
||||||
|
|
||||||
|
SetResourcePermissions(
|
||||||
|
ctx context.Context, orgID int64,
|
||||||
|
commands []types.SetResourcePermissionsCommand,
|
||||||
|
hooks types.ResourceHooks,
|
||||||
|
) ([]accesscontrol.ResourcePermission, error)
|
||||||
|
|
||||||
// GetResourcesPermissions will return all permission for all supplied resource ids
|
// GetResourcesPermissions will return all permission for all supplied resource ids
|
||||||
GetResourcesPermissions(ctx context.Context, orgID int64, query accesscontrol.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error)
|
GetResourcesPermissions(ctx context.Context, orgID int64, query types.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(options Options, router routing.RouteRegister, ac accesscontrol.AccessControl, store Store, sqlStore *sqlstore.SQLStore) (*Service, error) {
|
func New(options Options, router routing.RouteRegister, ac accesscontrol.AccessControl, store Store, sqlStore *sqlstore.SQLStore) (*Service, error) {
|
||||||
@ -93,7 +99,7 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetPermissions(ctx context.Context, orgID int64, resourceID string) ([]accesscontrol.ResourcePermission, error) {
|
func (s *Service) GetPermissions(ctx context.Context, orgID int64, resourceID string) ([]accesscontrol.ResourcePermission, error) {
|
||||||
return s.store.GetResourcesPermissions(ctx, orgID, accesscontrol.GetResourcesPermissionsQuery{
|
return s.store.GetResourcesPermissions(ctx, orgID, types.GetResourcesPermissionsQuery{
|
||||||
Actions: s.actions,
|
Actions: s.actions,
|
||||||
Resource: s.options.Resource,
|
Resource: s.options.Resource,
|
||||||
ResourceIDs: []string{resourceID},
|
ResourceIDs: []string{resourceID},
|
||||||
@ -102,10 +108,6 @@ func (s *Service) GetPermissions(ctx context.Context, orgID int64, resourceID st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user accesscontrol.User, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user accesscontrol.User, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
||||||
if !s.options.Assignments.Users {
|
|
||||||
return nil, ErrInvalidAssignment
|
|
||||||
}
|
|
||||||
|
|
||||||
actions, err := s.mapPermission(permission)
|
actions, err := s.mapPermission(permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -119,7 +121,7 @@ func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user acces
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.store.SetUserResourcePermission(ctx, orgID, user, accesscontrol.SetResourcePermissionCommand{
|
return s.store.SetUserResourcePermission(ctx, orgID, user, types.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
Permission: permission,
|
Permission: permission,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
@ -128,10 +130,6 @@ func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user acces
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
||||||
if !s.options.Assignments.Teams {
|
|
||||||
return nil, ErrInvalidAssignment
|
|
||||||
}
|
|
||||||
|
|
||||||
actions, err := s.mapPermission(permission)
|
actions, err := s.mapPermission(permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -145,7 +143,7 @@ func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, re
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.store.SetTeamResourcePermission(ctx, orgID, teamID, accesscontrol.SetResourcePermissionCommand{
|
return s.store.SetTeamResourcePermission(ctx, orgID, teamID, types.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
Permission: permission,
|
Permission: permission,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
@ -154,10 +152,6 @@ func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
||||||
if !s.options.Assignments.BuiltInRoles {
|
|
||||||
return nil, ErrInvalidAssignment
|
|
||||||
}
|
|
||||||
|
|
||||||
actions, err := s.mapPermission(permission)
|
actions, err := s.mapPermission(permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -171,7 +165,7 @@ func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, bui
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.store.SetBuiltInResourcePermission(ctx, orgID, builtInRole, accesscontrol.SetResourcePermissionCommand{
|
return s.store.SetBuiltInResourcePermission(ctx, orgID, builtInRole, types.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
Permission: permission,
|
Permission: permission,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
@ -179,6 +173,55 @@ func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, bui
|
|||||||
}, s.options.OnSetBuiltInRole)
|
}, s.options.OnSetBuiltInRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) SetPermissions(
|
||||||
|
ctx context.Context, orgID int64, resourceID string,
|
||||||
|
commands ...accesscontrol.SetResourcePermissionCommand,
|
||||||
|
) ([]accesscontrol.ResourcePermission, error) {
|
||||||
|
if err := s.validateResource(ctx, orgID, resourceID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbCommands := make([]types.SetResourcePermissionsCommand, 0, len(commands))
|
||||||
|
for _, cmd := range commands {
|
||||||
|
if cmd.UserID != 0 {
|
||||||
|
if err := s.validateUser(ctx, orgID, cmd.UserID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else if cmd.TeamID != 0 {
|
||||||
|
if err := s.validateTeam(ctx, orgID, cmd.TeamID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := s.validateBuiltinRole(ctx, cmd.BuiltinRole); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actions, err := s.mapPermission(cmd.Permission)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbCommands = append(dbCommands, types.SetResourcePermissionsCommand{
|
||||||
|
User: accesscontrol.User{ID: cmd.UserID},
|
||||||
|
TeamID: cmd.TeamID,
|
||||||
|
BuiltinRole: cmd.BuiltinRole,
|
||||||
|
SetResourcePermissionCommand: types.SetResourcePermissionCommand{
|
||||||
|
Actions: actions,
|
||||||
|
Resource: s.options.Resource,
|
||||||
|
ResourceID: resourceID,
|
||||||
|
Permission: cmd.Permission,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.store.SetResourcePermissions(ctx, orgID, dbCommands, types.ResourceHooks{
|
||||||
|
User: s.options.OnSetUser,
|
||||||
|
Team: s.options.OnSetTeam,
|
||||||
|
BuiltInRole: s.options.OnSetBuiltInRole,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) mapActions(permission accesscontrol.ResourcePermission) string {
|
func (s *Service) mapActions(permission accesscontrol.ResourcePermission) string {
|
||||||
for _, p := range s.permissions {
|
for _, p := range s.permissions {
|
||||||
if permission.Contains(s.options.PermissionsToActions[p]) {
|
if permission.Contains(s.options.PermissionsToActions[p]) {
|
||||||
@ -209,6 +252,10 @@ func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
|
func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
|
||||||
|
if !s.options.Assignments.Users {
|
||||||
|
return ErrInvalidAssignment
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.sqlStore.GetSignedInUser(ctx, &models.GetSignedInUserQuery{OrgId: orgID, UserId: userID}); err != nil {
|
if err := s.sqlStore.GetSignedInUser(ctx, &models.GetSignedInUserQuery{OrgId: orgID, UserId: userID}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -216,6 +263,10 @@ func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
|
func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
|
||||||
|
if !s.options.Assignments.Teams {
|
||||||
|
return ErrInvalidAssignment
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.sqlStore.GetTeamById(ctx, &models.GetTeamByIdQuery{OrgId: orgID, Id: teamID}); err != nil {
|
if err := s.sqlStore.GetTeamById(ctx, &models.GetTeamByIdQuery{OrgId: orgID, Id: teamID}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -223,6 +274,10 @@ func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) validateBuiltinRole(ctx context.Context, builtinRole string) error {
|
func (s *Service) validateBuiltinRole(ctx context.Context, builtinRole string) error {
|
||||||
|
if !s.options.Assignments.BuiltInRoles {
|
||||||
|
return ErrInvalidAssignment
|
||||||
|
}
|
||||||
|
|
||||||
if err := accesscontrol.ValidateBuiltInRoles([]string{builtinRole}); err != nil {
|
if err := accesscontrol.ValidateBuiltInRoles([]string{builtinRole}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,77 @@ func TestService_SetBuiltInRolePermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type setPermissionsTest struct {
|
||||||
|
desc string
|
||||||
|
options Options
|
||||||
|
commands []accesscontrol.SetResourcePermissionCommand
|
||||||
|
expectErr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SetPermissions(t *testing.T) {
|
||||||
|
tests := []setPermissionsTest{
|
||||||
|
{
|
||||||
|
desc: "should set all permissions",
|
||||||
|
options: Options{
|
||||||
|
Resource: "dashboards",
|
||||||
|
Assignments: Assignments{
|
||||||
|
Users: true,
|
||||||
|
Teams: true,
|
||||||
|
BuiltInRoles: true,
|
||||||
|
},
|
||||||
|
PermissionsToActions: map[string][]string{
|
||||||
|
"View": {"dashboards:read"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
commands: []accesscontrol.SetResourcePermissionCommand{
|
||||||
|
{UserID: 1, Permission: "View"},
|
||||||
|
{TeamID: 1, Permission: "View"},
|
||||||
|
{BuiltinRole: "Editor", Permission: "View"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "should return error for invalid permission",
|
||||||
|
options: Options{
|
||||||
|
Resource: "dashboards",
|
||||||
|
Assignments: Assignments{
|
||||||
|
Users: true,
|
||||||
|
Teams: true,
|
||||||
|
BuiltInRoles: true,
|
||||||
|
},
|
||||||
|
PermissionsToActions: map[string][]string{
|
||||||
|
"View": {"dashboards:read"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
commands: []accesscontrol.SetResourcePermissionCommand{
|
||||||
|
{UserID: 1, Permission: "View"},
|
||||||
|
{TeamID: 1, Permission: "View"},
|
||||||
|
{BuiltinRole: "Editor", Permission: "Not real permission"},
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
service, sql := setupTestEnvironment(t, []*accesscontrol.Permission{}, tt.options)
|
||||||
|
|
||||||
|
// seed user
|
||||||
|
_, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "user", OrgId: 1})
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = sql.CreateTeam("team", "", 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
permissions, err := service.SetPermissions(context.Background(), 1, "1", tt.commands...)
|
||||||
|
if tt.expectErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, permissions, len(tt.commands))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setupTestEnvironment(t *testing.T, permissions []*accesscontrol.Permission, ops Options) (*Service, *sqlstore.SQLStore) {
|
func setupTestEnvironment(t *testing.T, permissions []*accesscontrol.Permission, ops Options) (*Service, *sqlstore.SQLStore) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
@ -5,6 +5,12 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ResourceHooks struct {
|
||||||
|
User UserResourceHookFunc
|
||||||
|
Team TeamResourceHookFunc
|
||||||
|
BuiltInRole BuiltinResourceHookFunc
|
||||||
|
}
|
||||||
|
|
||||||
type UserResourceHookFunc func(session *sqlstore.DBSession, orgID int64, user accesscontrol.User, resourceID, permission string) error
|
type UserResourceHookFunc func(session *sqlstore.DBSession, orgID int64, user accesscontrol.User, resourceID, permission string) error
|
||||||
type TeamResourceHookFunc func(session *sqlstore.DBSession, orgID, teamID int64, resourceID, permission string) error
|
type TeamResourceHookFunc func(session *sqlstore.DBSession, orgID, teamID int64, resourceID, permission string) error
|
||||||
type BuiltinResourceHookFunc func(session *sqlstore.DBSession, orgID int64, builtInRole, resourceID, permission string) error
|
type BuiltinResourceHookFunc func(session *sqlstore.DBSession, orgID int64, builtInRole, resourceID, permission string) error
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
|
||||||
|
type SetResourcePermissionCommand struct {
|
||||||
|
Actions []string
|
||||||
|
Resource string
|
||||||
|
ResourceID string
|
||||||
|
Permission string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetResourcePermissionsCommand struct {
|
||||||
|
User accesscontrol.User
|
||||||
|
TeamID int64
|
||||||
|
BuiltinRole string
|
||||||
|
|
||||||
|
SetResourcePermissionCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetResourcesPermissionsQuery struct {
|
||||||
|
Actions []string
|
||||||
|
Resource string
|
||||||
|
ResourceIDs []string
|
||||||
|
OnlyManaged bool
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user