AccessControl: Add resource permission deletion helper (#71222)

* add method for deleting managed resource permissions

* test method
This commit is contained in:
Jo 2023-07-10 11:13:05 +02:00 committed by GitHub
parent a7aca983a5
commit 49e42d1a8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 191 additions and 0 deletions

View File

@ -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 {

View File

@ -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
} }

View File

@ -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)

View File

@ -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 ""
} }

View File

@ -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

View File

@ -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,

View File

@ -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
}