mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AccessControl: Add resource permission deletion helper (#71222)
* add method for deleting managed resource permissions * test method
This commit is contained in:
parent
a7aca983a5
commit
49e42d1a8d
@ -96,6 +96,8 @@ type PermissionsService interface {
|
|||||||
SetPermissions(ctx context.Context, orgID int64, resourceID string, commands ...SetResourcePermissionCommand) ([]ResourcePermission, error)
|
SetPermissions(ctx context.Context, orgID int64, resourceID string, commands ...SetResourcePermissionCommand) ([]ResourcePermission, error)
|
||||||
// MapActions will map actions for a ResourcePermissions to it's "friendly" name configured in PermissionsToActions map.
|
// MapActions will map actions for a ResourcePermissions to it's "friendly" name configured in PermissionsToActions map.
|
||||||
MapActions(permission ResourcePermission) string
|
MapActions(permission ResourcePermission) string
|
||||||
|
// DeleteResourcePermissions removes all permissions for a resource
|
||||||
|
DeleteResourcePermissions(ctx context.Context, orgID int64, resourceID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
@ -140,6 +140,10 @@ func (f *FakePermissionsService) SetPermissions(ctx context.Context, orgID int64
|
|||||||
return f.ExpectedPermissions, f.ExpectedErr
|
return f.ExpectedPermissions, f.ExpectedErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FakePermissionsService) DeleteResourcePermissions(ctx context.Context, orgID int64, resourceID string) error {
|
||||||
|
return f.ExpectedErr
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FakePermissionsService) MapActions(permission accesscontrol.ResourcePermission) string {
|
func (f *FakePermissionsService) MapActions(permission accesscontrol.ResourcePermission) string {
|
||||||
return f.ExpectedMappedAction
|
return f.ExpectedMappedAction
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,11 @@ func (m *MockPermissionsService) SetPermissions(ctx context.Context, orgID int64
|
|||||||
return mockedArgs.Get(0).([]accesscontrol.ResourcePermission), mockedArgs.Error(1)
|
return mockedArgs.Get(0).([]accesscontrol.ResourcePermission), mockedArgs.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockPermissionsService) DeleteResourcePermissions(ctx context.Context, orgID int64, resourceID string) error {
|
||||||
|
mockedArgs := m.Called(ctx, orgID, resourceID)
|
||||||
|
return mockedArgs.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockPermissionsService) MapActions(permission accesscontrol.ResourcePermission) string {
|
func (m *MockPermissionsService) MapActions(permission accesscontrol.ResourcePermission) string {
|
||||||
mockedArgs := m.Called(permission)
|
mockedArgs := m.Called(permission)
|
||||||
return mockedArgs.Get(0).(string)
|
return mockedArgs.Get(0).(string)
|
||||||
|
@ -273,6 +273,11 @@ func (e DatasourcePermissionsService) SetPermissions(ctx context.Context, orgID
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e DatasourcePermissionsService) DeleteResourcePermissions(ctx context.Context, orgID int64, resourceID string) error {
|
||||||
|
// TODO: implement
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e DatasourcePermissionsService) MapActions(permission accesscontrol.ResourcePermission) string {
|
func (e DatasourcePermissionsService) MapActions(permission accesscontrol.ResourcePermission) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,9 @@ type Store interface {
|
|||||||
|
|
||||||
// GetResourcePermissions will return all permission for supplied resource id
|
// GetResourcePermissions will return all permission for supplied resource id
|
||||||
GetResourcePermissions(ctx context.Context, orgID int64, query GetResourcePermissionsQuery) ([]accesscontrol.ResourcePermission, error)
|
GetResourcePermissions(ctx context.Context, orgID int64, query GetResourcePermissionsQuery) ([]accesscontrol.ResourcePermission, error)
|
||||||
|
|
||||||
|
// DeleteResourcePermissions will delete all permissions for supplied resource id
|
||||||
|
DeleteResourcePermissions(ctx context.Context, orgID int64, cmd *DeleteResourcePermissionsCmd) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
@ -264,6 +267,14 @@ func (s *Service) MapActions(permission accesscontrol.ResourcePermission) string
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteResourcePermissions(ctx context.Context, orgID int64, resourceID string) error {
|
||||||
|
return s.store.DeleteResourcePermissions(ctx, orgID, &DeleteResourcePermissionsCmd{
|
||||||
|
Resource: s.options.Resource,
|
||||||
|
ResourceAttribute: s.options.ResourceAttribute,
|
||||||
|
ResourceID: resourceID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) mapPermission(permission string) ([]string, error) {
|
func (s *Service) mapPermission(permission string) ([]string, error) {
|
||||||
if permission == "" {
|
if permission == "" {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
|
@ -48,6 +48,33 @@ func (p *flatResourcePermission) IsInherited(scope string) bool {
|
|||||||
return strings.HasPrefix(p.RoleName, accesscontrol.ManagedRolePrefix) && p.Scope != scope
|
return strings.HasPrefix(p.RoleName, accesscontrol.ManagedRolePrefix) && p.Scope != scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeleteResourcePermissionsCmd struct {
|
||||||
|
Resource string
|
||||||
|
ResourceAttribute string
|
||||||
|
ResourceID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *store) DeleteResourcePermissions(ctx context.Context, orgID int64, cmd *DeleteResourcePermissionsCmd) error {
|
||||||
|
scope := accesscontrol.Scope(cmd.Resource, cmd.ResourceAttribute, cmd.ResourceID)
|
||||||
|
|
||||||
|
err := s.sql.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||||
|
var permissionIDs []int64
|
||||||
|
err := sess.SQL(
|
||||||
|
"SELECT permission.id FROM permission INNER JOIN role ON permission.role_id = role.id WHERE permission.scope = ? AND role.org_id = ?",
|
||||||
|
scope, orgID).Find(&permissionIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deletePermissions(sess, permissionIDs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *store) SetUserResourcePermission(
|
func (s *store) SetUserResourcePermission(
|
||||||
ctx context.Context, orgID int64, usr accesscontrol.User,
|
ctx context.Context, orgID int64, usr accesscontrol.User,
|
||||||
cmd SetResourcePermissionCommand,
|
cmd SetResourcePermissionCommand,
|
||||||
|
@ -577,3 +577,140 @@ func TestStore_IsInherited(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type orgPermission struct {
|
||||||
|
OrgID int64 `xorm:"org_id"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationStore_DeleteResourcePermissions(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test")
|
||||||
|
}
|
||||||
|
|
||||||
|
type deleteResourcePermissionsTest struct {
|
||||||
|
desc string
|
||||||
|
orgID int64
|
||||||
|
resourceAttribute string
|
||||||
|
command DeleteResourcePermissionsCmd
|
||||||
|
shouldExist []orgPermission
|
||||||
|
shouldNotExist []orgPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []deleteResourcePermissionsTest{
|
||||||
|
{
|
||||||
|
desc: "should delete all permissions for resource id in org 1",
|
||||||
|
orgID: 1,
|
||||||
|
resourceAttribute: "uid",
|
||||||
|
command: DeleteResourcePermissionsCmd{
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "1",
|
||||||
|
ResourceAttribute: "uid",
|
||||||
|
},
|
||||||
|
shouldExist: []orgPermission{
|
||||||
|
{
|
||||||
|
OrgID: 2,
|
||||||
|
Action: "datasources:query",
|
||||||
|
Scope: "datasources:uid:1",
|
||||||
|
}, {
|
||||||
|
OrgID: 2,
|
||||||
|
Action: "datasources:write",
|
||||||
|
Scope: "datasources:uid:1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
OrgID: 1,
|
||||||
|
Action: "datasources:query",
|
||||||
|
Scope: "datasources:uid:2",
|
||||||
|
}, {
|
||||||
|
OrgID: 1,
|
||||||
|
Action: "datasources:write",
|
||||||
|
Scope: "datasources:uid:2",
|
||||||
|
}},
|
||||||
|
shouldNotExist: []orgPermission{
|
||||||
|
{
|
||||||
|
OrgID: 1,
|
||||||
|
Action: "datasources:query",
|
||||||
|
Scope: "datasources:uid:1",
|
||||||
|
}, {
|
||||||
|
OrgID: 1,
|
||||||
|
Action: "datasources:write",
|
||||||
|
Scope: "datasources:uid:1",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
store, _ := setupTestEnv(t)
|
||||||
|
|
||||||
|
_, err := store.SetResourcePermissions(context.Background(), 1, []SetResourcePermissionsCommand{
|
||||||
|
{
|
||||||
|
User: accesscontrol.User{ID: 1},
|
||||||
|
SetResourcePermissionCommand: SetResourcePermissionCommand{
|
||||||
|
Actions: []string{"datasources:query", "datasources:write"},
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "1",
|
||||||
|
ResourceAttribute: "uid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, ResourceHooks{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = store.SetResourcePermissions(context.Background(), 1, []SetResourcePermissionsCommand{
|
||||||
|
{
|
||||||
|
User: accesscontrol.User{ID: 1},
|
||||||
|
SetResourcePermissionCommand: SetResourcePermissionCommand{
|
||||||
|
Actions: []string{"datasources:query", "datasources:write"},
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "2",
|
||||||
|
ResourceAttribute: "uid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, ResourceHooks{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = store.SetResourcePermissions(context.Background(), 2, []SetResourcePermissionsCommand{
|
||||||
|
{
|
||||||
|
User: accesscontrol.User{ID: 1},
|
||||||
|
SetResourcePermissionCommand: SetResourcePermissionCommand{
|
||||||
|
Actions: []string{"datasources:query", "datasources:write"},
|
||||||
|
Resource: "datasources",
|
||||||
|
ResourceID: "1",
|
||||||
|
ResourceAttribute: "uid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, ResourceHooks{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = store.DeleteResourcePermissions(context.Background(), tt.orgID, &tt.command)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
permissions := retrievePermissionsHelper(store, t)
|
||||||
|
|
||||||
|
for _, p := range tt.shouldExist {
|
||||||
|
assert.Contains(t, permissions, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range tt.shouldNotExist {
|
||||||
|
assert.NotContains(t, permissions, p)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func retrievePermissionsHelper(store *store, t *testing.T) []orgPermission {
|
||||||
|
permissions := []orgPermission{}
|
||||||
|
err := store.sql.WithDbSession(context.Background(), func(sess *db.Session) error {
|
||||||
|
err := sess.SQL(`
|
||||||
|
SELECT permission.*, role.org_id
|
||||||
|
FROM permission
|
||||||
|
INNER JOIN role ON permission.role_id = role.id
|
||||||
|
`).Find(&permissions)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
return permissions
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user