Access control: Refactor managed permission system to create api and frontend components (#42540)
* Refactor resource permissions * Add frondend components for resource permissions Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
co-authored by
kay delaney
Alex Khomenko
Gabriel MABILLE
Ieva
parent
9cf5623918
commit
c3ca2d214d
@@ -60,7 +60,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
||||
user, team := createUserAndTeam(t, sql, tt.orgID)
|
||||
|
||||
for _, id := range tt.userPermissions {
|
||||
_, err := store.SetUserResourcePermissions(context.Background(), tt.orgID, user.Id, accesscontrol.SetResourcePermissionsCommand{
|
||||
_, err := store.SetUserResourcePermission(context.Background(), tt.orgID, user.Id, accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: []string{"dashboards:read"},
|
||||
Resource: "dashboards",
|
||||
ResourceID: id,
|
||||
@@ -69,7 +69,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, id := range tt.teamPermissions {
|
||||
_, err := store.SetTeamResourcePermissions(context.Background(), tt.orgID, team.Id, accesscontrol.SetResourcePermissionsCommand{
|
||||
_, err := store.SetTeamResourcePermission(context.Background(), tt.orgID, team.Id, accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: []string{"dashboards:read"},
|
||||
Resource: "dashboards",
|
||||
ResourceID: id,
|
||||
@@ -78,7 +78,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, id := range tt.builtinPermissions {
|
||||
_, err := store.SetBuiltinResourcePermissions(context.Background(), tt.orgID, "Admin", accesscontrol.SetResourcePermissionsCommand{
|
||||
_, err := store.SetBuiltInResourcePermission(context.Background(), tt.orgID, "Admin", accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: []string{"dashboards:read"},
|
||||
Resource: "dashboards",
|
||||
ResourceID: id,
|
||||
|
||||
+144
-82
@@ -11,19 +11,39 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
)
|
||||
|
||||
func (s *AccessControlStore) SetUserResourcePermissions(ctx context.Context, orgID, userID int64, cmd accesscontrol.SetResourcePermissionsCommand) ([]accesscontrol.ResourcePermission, error) {
|
||||
type flatResourcePermission struct {
|
||||
ID int64 `xorm:"id"`
|
||||
ResourceID string `xorm:"resource_id"`
|
||||
RoleName string
|
||||
Action string
|
||||
Scope string
|
||||
UserId int64
|
||||
UserLogin string
|
||||
UserEmail string
|
||||
TeamId int64
|
||||
TeamEmail string
|
||||
Team string
|
||||
BuiltInRole string
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
func (p *flatResourcePermission) Managed() bool {
|
||||
return strings.HasPrefix(p.RoleName, "managed:")
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) SetUserResourcePermission(ctx context.Context, orgID, userID int64, cmd accesscontrol.SetResourcePermissionCommand) (*accesscontrol.ResourcePermission, error) {
|
||||
if userID == 0 {
|
||||
return nil, models.ErrUserNotFound
|
||||
}
|
||||
|
||||
var err error
|
||||
var permissions []accesscontrol.ResourcePermission
|
||||
var permission *accesscontrol.ResourcePermission
|
||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
permissions, err = s.setResourcePermissions(sess, orgID, managedUserRoleName(userID), s.userAdder(sess, orgID, userID), cmd)
|
||||
permission, err = s.setResourcePermission(sess, orgID, managedUserRoleName(userID), s.userAdder(sess, orgID, userID), cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -31,22 +51,22 @@ func (s *AccessControlStore) SetUserResourcePermissions(ctx context.Context, org
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) SetTeamResourcePermissions(ctx context.Context, orgID, teamID int64, cmd accesscontrol.SetResourcePermissionsCommand) ([]accesscontrol.ResourcePermission, error) {
|
||||
func (s *AccessControlStore) SetTeamResourcePermission(ctx context.Context, orgID, teamID int64, cmd accesscontrol.SetResourcePermissionCommand) (*accesscontrol.ResourcePermission, error) {
|
||||
if teamID == 0 {
|
||||
return nil, models.ErrTeamNotFound
|
||||
}
|
||||
|
||||
var err error
|
||||
var permissions []accesscontrol.ResourcePermission
|
||||
var permission *accesscontrol.ResourcePermission
|
||||
|
||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
permissions, err = s.setResourcePermissions(sess, orgID, managedTeamRoleName(teamID), s.teamAdder(sess, orgID, teamID), cmd)
|
||||
permission, err = s.setResourcePermission(sess, orgID, managedTeamRoleName(teamID), s.teamAdder(sess, orgID, teamID), cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -54,38 +74,34 @@ func (s *AccessControlStore) SetTeamResourcePermissions(ctx context.Context, org
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) SetBuiltinResourcePermissions(ctx context.Context, orgID int64, builtinRole string, cmd accesscontrol.SetResourcePermissionsCommand) ([]accesscontrol.ResourcePermission, error) {
|
||||
if !models.RoleType(builtinRole).IsValid() || builtinRole == accesscontrol.RoleGrafanaAdmin {
|
||||
return nil, fmt.Errorf("invalid role: %s", builtinRole)
|
||||
func (s *AccessControlStore) SetBuiltInResourcePermission(ctx context.Context, orgID int64, builtInRole string, cmd accesscontrol.SetResourcePermissionCommand) (*accesscontrol.ResourcePermission, error) {
|
||||
if !models.RoleType(builtInRole).IsValid() || builtInRole == accesscontrol.RoleGrafanaAdmin {
|
||||
return nil, fmt.Errorf("invalid role: %s", builtInRole)
|
||||
}
|
||||
|
||||
var err error
|
||||
var permissions []accesscontrol.ResourcePermission
|
||||
var permission *accesscontrol.ResourcePermission
|
||||
|
||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
permissions, err = s.setResourcePermissions(sess, orgID, managedBuiltInRoleName(builtinRole), s.builtinRoleAdder(sess, orgID, builtinRole), cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
permission, err = s.setResourcePermission(sess, orgID, managedBuiltInRoleName(builtInRole), s.builtInRoleAdder(sess, orgID, builtInRole), cmd)
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
type roleAdder func(roleID int64) error
|
||||
|
||||
func (s *AccessControlStore) setResourcePermissions(
|
||||
sess *sqlstore.DBSession, orgID int64, roleName string, adder roleAdder, cmd accesscontrol.SetResourcePermissionsCommand,
|
||||
) ([]accesscontrol.ResourcePermission, error) {
|
||||
func (s *AccessControlStore) setResourcePermission(
|
||||
sess *sqlstore.DBSession, orgID int64, roleName string, adder roleAdder, cmd accesscontrol.SetResourcePermissionCommand,
|
||||
) (*accesscontrol.ResourcePermission, error) {
|
||||
role, err := s.getOrCreateManagedRole(sess, orgID, roleName, adder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -125,7 +141,7 @@ func (s *AccessControlStore) setResourcePermissions(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var permissions []accesscontrol.ResourcePermission
|
||||
var permissions []flatResourcePermission
|
||||
|
||||
for action := range missing {
|
||||
p, err := createResourcePermission(sess, role.ID, action, cmd.Resource, cmd.ResourceID)
|
||||
@@ -135,51 +151,17 @@ func (s *AccessControlStore) setResourcePermissions(
|
||||
permissions = append(permissions, *p)
|
||||
}
|
||||
|
||||
keptPermissions, err := getManagedPermissions(sess, cmd.ResourceID, keep)
|
||||
keptPermissions, err := getResourcePermissions(sess, cmd.ResourceID, keep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions = append(permissions, keptPermissions...)
|
||||
return permissions, nil
|
||||
}
|
||||
permission := flatPermissionsToResourcePermission(append(permissions, keptPermissions...))
|
||||
if permission == nil {
|
||||
return &accesscontrol.ResourcePermission{}, nil
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) RemoveResourcePermission(ctx context.Context, orgID int64, cmd accesscontrol.RemoveResourcePermissionCommand) error {
|
||||
return s.sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
var permission accesscontrol.Permission
|
||||
rawSql := `
|
||||
SELECT
|
||||
p.*
|
||||
FROM permission p
|
||||
LEFT JOIN role r ON p.role_id = r.id
|
||||
WHERE r.name LIKE 'managed:%'
|
||||
AND r.org_id = ?
|
||||
AND p.id = ?
|
||||
AND p.scope = ?
|
||||
AND p.action IN(?` + strings.Repeat(",?", len(cmd.Actions)-1) + `)
|
||||
`
|
||||
|
||||
args := []interface{}{
|
||||
orgID,
|
||||
cmd.PermissionID,
|
||||
accesscontrol.GetResourceScope(cmd.Resource, cmd.ResourceID),
|
||||
}
|
||||
|
||||
for _, a := range cmd.Actions {
|
||||
args = append(args, a)
|
||||
}
|
||||
|
||||
exists, err := sess.SQL(rawSql, args...).Get(&permission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
return deletePermissions(sess, []int64{permission.ID})
|
||||
})
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) GetResourcesPermissions(ctx context.Context, orgID int64, query accesscontrol.GetResourcesPermissionsQuery) ([]accesscontrol.ResourcePermission, error) {
|
||||
@@ -194,7 +176,7 @@ func (s *AccessControlStore) GetResourcesPermissions(ctx context.Context, orgID
|
||||
return result, err
|
||||
}
|
||||
|
||||
func createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, resource string, resourceID string) (*accesscontrol.ResourcePermission, error) {
|
||||
func createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, resource string, resourceID string) (*flatResourcePermission, error) {
|
||||
permission := managedPermission(action, resource, resourceID)
|
||||
permission.RoleID = roleID
|
||||
permission.Created = time.Now()
|
||||
@@ -224,7 +206,7 @@ func createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, re
|
||||
WHERE p.id = ?
|
||||
`
|
||||
|
||||
p := &accesscontrol.ResourcePermission{}
|
||||
p := &flatResourcePermission{}
|
||||
if _, err := sess.SQL(rawSql, resourceID, permission.ID).Get(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -233,14 +215,12 @@ func createResourcePermission(sess *sqlstore.DBSession, roleID int64, action, re
|
||||
}
|
||||
|
||||
func getResourcesPermissions(sess *sqlstore.DBSession, orgID int64, query accesscontrol.GetResourcesPermissionsQuery, managed bool) ([]accesscontrol.ResourcePermission, error) {
|
||||
result := make([]accesscontrol.ResourcePermission, 0)
|
||||
|
||||
if len(query.Actions) == 0 {
|
||||
return result, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if len(query.ResourceIDs) == 0 {
|
||||
return result, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rawSelect := `
|
||||
@@ -329,27 +309,109 @@ func getResourcesPermissions(sess *sqlstore.DBSession, orgID int64, query access
|
||||
builtin := builtinSelect + builtinFrom + where
|
||||
sql := user + "UNION" + team + "UNION" + builtin
|
||||
|
||||
if err := sess.SQL(sql, args...).Find(&result); err != nil {
|
||||
queryResults := make([]flatResourcePermission, 0)
|
||||
if err := sess.SQL(sql, args...).Find(&queryResults); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scopeAll := accesscontrol.GetResourceAllScope(query.Resource)
|
||||
scopeAllIDs := accesscontrol.GetResourceAllIDScope(query.Resource)
|
||||
out := make([]accesscontrol.ResourcePermission, 0, len(result))
|
||||
|
||||
byResource := make(map[string][]flatResourcePermission)
|
||||
// Add resourceIds and generate permissions for `*`, `resource:*` and `resource:id:*`
|
||||
// TODO: handle scope with other key prefixes e.g. `resource:name:*` and `resource:name:name`
|
||||
for _, id := range query.ResourceIDs {
|
||||
scope := accesscontrol.GetResourceScope(query.Resource, id)
|
||||
for _, p := range result {
|
||||
for _, p := range queryResults {
|
||||
if p.Scope == scope || p.Scope == scopeAll || p.Scope == scopeAllIDs || p.Scope == "*" {
|
||||
p.ResourceID = id
|
||||
out = append(out, p)
|
||||
byResource[p.ResourceID] = append(byResource[p.ResourceID], p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
var result []accesscontrol.ResourcePermission
|
||||
for _, permissions := range byResource {
|
||||
users, teams, builtins := groupPermissionsByAssignment(permissions)
|
||||
for _, p := range users {
|
||||
result = append(result, flatPermissionsToResourcePermissions(p)...)
|
||||
}
|
||||
for _, p := range teams {
|
||||
result = append(result, flatPermissionsToResourcePermissions(p)...)
|
||||
}
|
||||
for _, p := range builtins {
|
||||
result = append(result, flatPermissionsToResourcePermissions(p)...)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func groupPermissionsByAssignment(permissions []flatResourcePermission) (map[int64][]flatResourcePermission, map[int64][]flatResourcePermission, map[string][]flatResourcePermission) {
|
||||
users := make(map[int64][]flatResourcePermission)
|
||||
teams := make(map[int64][]flatResourcePermission)
|
||||
builtins := make(map[string][]flatResourcePermission)
|
||||
|
||||
for _, p := range permissions {
|
||||
if p.UserId != 0 {
|
||||
users[p.UserId] = append(users[p.UserId], p)
|
||||
} else if p.TeamId != 0 {
|
||||
teams[p.TeamId] = append(teams[p.TeamId], p)
|
||||
} else if p.BuiltInRole != "" {
|
||||
builtins[p.BuiltInRole] = append(builtins[p.BuiltInRole], p)
|
||||
}
|
||||
}
|
||||
|
||||
return users, teams, builtins
|
||||
}
|
||||
|
||||
func flatPermissionsToResourcePermissions(permissions []flatResourcePermission) []accesscontrol.ResourcePermission {
|
||||
var managed, provisioned []flatResourcePermission
|
||||
for _, p := range permissions {
|
||||
if p.Managed() {
|
||||
managed = append(managed, p)
|
||||
} else {
|
||||
provisioned = append(provisioned, p)
|
||||
}
|
||||
}
|
||||
|
||||
var result []accesscontrol.ResourcePermission
|
||||
if g := flatPermissionsToResourcePermission(managed); g != nil {
|
||||
result = append(result, *g)
|
||||
}
|
||||
if g := flatPermissionsToResourcePermission(provisioned); g != nil {
|
||||
result = append(result, *g)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func flatPermissionsToResourcePermission(permissions []flatResourcePermission) *accesscontrol.ResourcePermission {
|
||||
if len(permissions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
actions := make([]string, 0, len(permissions))
|
||||
for _, p := range permissions {
|
||||
actions = append(actions, p.Action)
|
||||
}
|
||||
|
||||
first := permissions[0]
|
||||
return &accesscontrol.ResourcePermission{
|
||||
ID: first.ID,
|
||||
ResourceID: first.ResourceID,
|
||||
RoleName: first.RoleName,
|
||||
Actions: actions,
|
||||
Scope: first.Scope,
|
||||
UserId: first.UserId,
|
||||
UserLogin: first.UserLogin,
|
||||
UserEmail: first.UserEmail,
|
||||
TeamId: first.TeamId,
|
||||
TeamEmail: first.TeamEmail,
|
||||
Team: first.Team,
|
||||
BuiltInRole: first.BuiltInRole,
|
||||
Created: first.Created,
|
||||
Updated: first.Updated,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) userAdder(sess *sqlstore.DBSession, orgID, userID int64) roleAdder {
|
||||
@@ -393,7 +455,7 @@ func (s *AccessControlStore) teamAdder(sess *sqlstore.DBSession, orgID, teamID i
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) builtinRoleAdder(sess *sqlstore.DBSession, orgID int64, builtinRole string) roleAdder {
|
||||
func (s *AccessControlStore) builtInRoleAdder(sess *sqlstore.DBSession, orgID int64, builtinRole string) roleAdder {
|
||||
return func(roleID int64) error {
|
||||
if res, err := sess.Query("SELECT 1 FROM builtin_role WHERE role_id=? AND role=? AND org_id=?", roleID, builtinRole, orgID); err != nil {
|
||||
return err
|
||||
@@ -448,8 +510,8 @@ func (s *AccessControlStore) getOrCreateManagedRole(sess *sqlstore.DBSession, or
|
||||
return &role, nil
|
||||
}
|
||||
|
||||
func getManagedPermissions(sess *sqlstore.DBSession, resourceID string, ids []int64) ([]accesscontrol.ResourcePermission, error) {
|
||||
var result []accesscontrol.ResourcePermission
|
||||
func getResourcePermissions(sess *sqlstore.DBSession, resourceID string, ids []int64) ([]flatResourcePermission, error) {
|
||||
var result []flatResourcePermission
|
||||
if len(ids) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
@@ -502,6 +564,6 @@ func managedTeamRoleName(teamID int64) string {
|
||||
return fmt.Sprintf("managed:teams:%d:permissions", teamID)
|
||||
}
|
||||
|
||||
func managedBuiltInRoleName(builtinRole string) string {
|
||||
return fmt.Sprintf("managed:builtins:%s:permissions", strings.ToLower(builtinRole))
|
||||
func managedBuiltInRoleName(builtInRole string) string {
|
||||
return fmt.Sprintf("managed:builtins:%s:permissions", strings.ToLower(builtInRole))
|
||||
}
|
||||
+5
-5
@@ -51,7 +51,7 @@ func benchmarkDSPermissions(b *testing.B, dsNum, usersNum int) {
|
||||
}
|
||||
}
|
||||
|
||||
func getDSPermissions(b *testing.B, store accesscontrol.ResourceStore, dataSources []int64) {
|
||||
func getDSPermissions(b *testing.B, store accesscontrol.ResourcePermissionsStore, dataSources []int64) {
|
||||
dsId := dataSources[0]
|
||||
|
||||
permissions, err := store.GetResourcesPermissions(context.Background(), accesscontrol.GlobalOrgID, accesscontrol.GetResourcesPermissionsQuery{
|
||||
@@ -90,11 +90,11 @@ func GenerateDatasourcePermissions(b *testing.B, db *sqlstore.SQLStore, ac *Acce
|
||||
// Add DS permissions for the users
|
||||
maxPermissions := int(math.Min(float64(permissionsPerDs), float64(len(userIds))))
|
||||
for i := 0; i < maxPermissions; i++ {
|
||||
_, err := ac.SetUserResourcePermissions(
|
||||
_, err := ac.SetUserResourcePermission(
|
||||
context.Background(),
|
||||
accesscontrol.GlobalOrgID,
|
||||
userIds[i],
|
||||
accesscontrol.SetResourcePermissionsCommand{
|
||||
accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: []string{dsAction},
|
||||
Resource: dsResource,
|
||||
ResourceID: strconv.Itoa(int(dsID)),
|
||||
@@ -106,11 +106,11 @@ func GenerateDatasourcePermissions(b *testing.B, db *sqlstore.SQLStore, ac *Acce
|
||||
// Add DS permissions for the teams
|
||||
maxPermissions = int(math.Min(float64(permissionsPerDs), float64(len(teamIds))))
|
||||
for i := 0; i < maxPermissions; i++ {
|
||||
_, err := ac.SetTeamResourcePermissions(
|
||||
_, err := ac.SetTeamResourcePermission(
|
||||
context.Background(),
|
||||
accesscontrol.GlobalOrgID,
|
||||
teamIds[i],
|
||||
accesscontrol.SetResourcePermissionsCommand{
|
||||
accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: "datasources",
|
||||
ResourceID: strconv.Itoa(int(dsID)),
|
||||
+43
-121
@@ -13,18 +13,18 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
)
|
||||
|
||||
type setUserResourcePermissionsTest struct {
|
||||
type setUserResourcePermissionTest struct {
|
||||
desc string
|
||||
orgID int64
|
||||
userID int64
|
||||
actions []string
|
||||
resource string
|
||||
resourceID string
|
||||
seeds []accesscontrol.SetResourcePermissionsCommand
|
||||
seeds []accesscontrol.SetResourcePermissionCommand
|
||||
}
|
||||
|
||||
func TestAccessControlStore_SetUserResourcePermissions(t *testing.T) {
|
||||
tests := []setUserResourcePermissionsTest{
|
||||
func TestAccessControlStore_SetUserResourcePermission(t *testing.T) {
|
||||
tests := []setUserResourcePermissionTest{
|
||||
{
|
||||
desc: "should set resource permission for user",
|
||||
userID: 1,
|
||||
@@ -39,7 +39,7 @@ func TestAccessControlStore_SetUserResourcePermissions(t *testing.T) {
|
||||
actions: []string{},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
seeds: []accesscontrol.SetResourcePermissionsCommand{
|
||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
||||
{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: "datasources",
|
||||
@@ -54,7 +54,7 @@ func TestAccessControlStore_SetUserResourcePermissions(t *testing.T) {
|
||||
actions: []string{"datasources:query", "datasources:write"},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
seeds: []accesscontrol.SetResourcePermissionsCommand{
|
||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
||||
{
|
||||
Actions: []string{"datasources:write"},
|
||||
Resource: "datasources",
|
||||
@@ -69,37 +69,39 @@ func TestAccessControlStore_SetUserResourcePermissions(t *testing.T) {
|
||||
store, _ := setupTestEnv(t)
|
||||
|
||||
for _, s := range test.seeds {
|
||||
_, err := store.SetUserResourcePermissions(context.Background(), test.orgID, test.userID, s)
|
||||
_, err := store.SetUserResourcePermission(context.Background(), test.orgID, test.userID, s)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
added, err := store.SetUserResourcePermissions(context.Background(), test.userID, test.userID, accesscontrol.SetResourcePermissionsCommand{
|
||||
added, err := store.SetUserResourcePermission(context.Background(), test.userID, test.userID, accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: test.actions,
|
||||
Resource: test.resource,
|
||||
ResourceID: test.resourceID,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, added, len(test.actions))
|
||||
for _, p := range added {
|
||||
assert.Equal(t, accesscontrol.GetResourceScope(test.resource, test.resourceID), p.Scope)
|
||||
if len(test.actions) == 0 {
|
||||
assert.Equal(t, accesscontrol.ResourcePermission{}, *added)
|
||||
} else {
|
||||
assert.Len(t, added.Actions, len(test.actions))
|
||||
assert.Equal(t, accesscontrol.GetResourceScope(test.resource, test.resourceID), added.Scope)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type setTeamResourcePermissionsTest struct {
|
||||
type setTeamResourcePermissionTest struct {
|
||||
desc string
|
||||
orgID int64
|
||||
teamID int64
|
||||
actions []string
|
||||
resource string
|
||||
resourceID string
|
||||
seeds []accesscontrol.SetResourcePermissionsCommand
|
||||
seeds []accesscontrol.SetResourcePermissionCommand
|
||||
}
|
||||
|
||||
func TestAccessControlStore_SetTeamResourcePermissions(t *testing.T) {
|
||||
tests := []setTeamResourcePermissionsTest{
|
||||
func TestAccessControlStore_SetTeamResourcePermission(t *testing.T) {
|
||||
tests := []setTeamResourcePermissionTest{
|
||||
{
|
||||
desc: "should add new resource permission for team",
|
||||
orgID: 1,
|
||||
@@ -115,7 +117,7 @@ func TestAccessControlStore_SetTeamResourcePermissions(t *testing.T) {
|
||||
actions: []string{"datasources:query", "datasources:write"},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
seeds: []accesscontrol.SetResourcePermissionsCommand{
|
||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
||||
{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: "datasources",
|
||||
@@ -130,7 +132,7 @@ func TestAccessControlStore_SetTeamResourcePermissions(t *testing.T) {
|
||||
actions: []string{},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
seeds: []accesscontrol.SetResourcePermissionsCommand{
|
||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
||||
{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: "datasources",
|
||||
@@ -145,41 +147,43 @@ func TestAccessControlStore_SetTeamResourcePermissions(t *testing.T) {
|
||||
store, _ := setupTestEnv(t)
|
||||
|
||||
for _, s := range test.seeds {
|
||||
_, err := store.SetTeamResourcePermissions(context.Background(), test.orgID, test.teamID, s)
|
||||
_, err := store.SetTeamResourcePermission(context.Background(), test.orgID, test.teamID, s)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
added, err := store.SetTeamResourcePermissions(context.Background(), test.orgID, test.teamID, accesscontrol.SetResourcePermissionsCommand{
|
||||
added, err := store.SetTeamResourcePermission(context.Background(), test.orgID, test.teamID, accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: test.actions,
|
||||
Resource: test.resource,
|
||||
ResourceID: test.resourceID,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, added, len(test.actions))
|
||||
for _, p := range added {
|
||||
assert.Equal(t, accesscontrol.GetResourceScope(test.resource, test.resourceID), p.Scope)
|
||||
if len(test.actions) == 0 {
|
||||
assert.Equal(t, accesscontrol.ResourcePermission{}, *added)
|
||||
} else {
|
||||
assert.Len(t, added.Actions, len(test.actions))
|
||||
assert.Equal(t, accesscontrol.GetResourceScope(test.resource, test.resourceID), added.Scope)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type setBuiltinResourcePermissionsTest struct {
|
||||
type setBuiltInResourcePermissionTest struct {
|
||||
desc string
|
||||
orgID int64
|
||||
builtinRole string
|
||||
builtInRole string
|
||||
actions []string
|
||||
resource string
|
||||
resourceID string
|
||||
seeds []accesscontrol.SetResourcePermissionsCommand
|
||||
seeds []accesscontrol.SetResourcePermissionCommand
|
||||
}
|
||||
|
||||
func TestAccessControlStore_SetBuiltinResourcePermissions(t *testing.T) {
|
||||
tests := []setBuiltinResourcePermissionsTest{
|
||||
func TestAccessControlStore_SetBuiltInResourcePermission(t *testing.T) {
|
||||
tests := []setBuiltInResourcePermissionTest{
|
||||
{
|
||||
desc: "should add new resource permission for builtin role",
|
||||
orgID: 1,
|
||||
builtinRole: "Viewer",
|
||||
builtInRole: "Viewer",
|
||||
actions: []string{"datasources:query"},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
@@ -187,11 +191,11 @@ func TestAccessControlStore_SetBuiltinResourcePermissions(t *testing.T) {
|
||||
{
|
||||
desc: "should add new resource permission when others exist",
|
||||
orgID: 1,
|
||||
builtinRole: "Viewer",
|
||||
builtInRole: "Viewer",
|
||||
actions: []string{"datasources:query", "datasources:write"},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
seeds: []accesscontrol.SetResourcePermissionsCommand{
|
||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
||||
{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: "datasources",
|
||||
@@ -202,11 +206,11 @@ func TestAccessControlStore_SetBuiltinResourcePermissions(t *testing.T) {
|
||||
{
|
||||
desc: "should remove permissions for builtin role",
|
||||
orgID: 1,
|
||||
builtinRole: "Viewer",
|
||||
builtInRole: "Viewer",
|
||||
actions: []string{},
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
seeds: []accesscontrol.SetResourcePermissionsCommand{
|
||||
seeds: []accesscontrol.SetResourcePermissionCommand{
|
||||
{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: "datasources",
|
||||
@@ -221,104 +225,22 @@ func TestAccessControlStore_SetBuiltinResourcePermissions(t *testing.T) {
|
||||
store, _ := setupTestEnv(t)
|
||||
|
||||
for _, s := range test.seeds {
|
||||
_, err := store.SetBuiltinResourcePermissions(context.Background(), test.orgID, test.builtinRole, s)
|
||||
_, err := store.SetBuiltInResourcePermission(context.Background(), test.orgID, test.builtInRole, s)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
added, err := store.SetBuiltinResourcePermissions(context.Background(), test.orgID, test.builtinRole, accesscontrol.SetResourcePermissionsCommand{
|
||||
added, err := store.SetBuiltInResourcePermission(context.Background(), test.orgID, test.builtInRole, accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: test.actions,
|
||||
Resource: test.resource,
|
||||
ResourceID: test.resourceID,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, added, len(test.actions))
|
||||
for _, p := range added {
|
||||
assert.Equal(t, accesscontrol.GetResourceScope(test.resource, test.resourceID), p.Scope)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type resourcePermission struct {
|
||||
resource string
|
||||
resourceID string
|
||||
}
|
||||
|
||||
type removeResourcePermissionTest struct {
|
||||
desc string
|
||||
add resourcePermission
|
||||
remove resourcePermission
|
||||
expectedErr error
|
||||
}
|
||||
|
||||
func TestAccessControlStore_RemoveResourcePermission(t *testing.T) {
|
||||
tests := []removeResourcePermissionTest{
|
||||
{
|
||||
desc: "should remove resource permission",
|
||||
add: resourcePermission{
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
},
|
||||
remove: resourcePermission{
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return nil when permission does not exist",
|
||||
add: resourcePermission{
|
||||
resource: "datasources",
|
||||
resourceID: "1",
|
||||
},
|
||||
remove: resourcePermission{
|
||||
resource: "datasources",
|
||||
resourceID: "2",
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
store, sql := setupTestEnv(t)
|
||||
|
||||
user, err := sql.CreateUser(context.Background(), models.CreateUserCommand{
|
||||
Login: "user",
|
||||
OrgId: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Seed with permission
|
||||
seeded, err := store.SetUserResourcePermissions(context.Background(), user.OrgId, user.Id, accesscontrol.SetResourcePermissionsCommand{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: test.add.resource,
|
||||
ResourceID: test.add.resourceID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = store.RemoveResourcePermission(context.Background(), user.OrgId, accesscontrol.RemoveResourcePermissionCommand{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: test.remove.resource,
|
||||
ResourceID: test.remove.resourceID,
|
||||
PermissionID: seeded[0].ID,
|
||||
})
|
||||
|
||||
if test.expectedErr != nil {
|
||||
assert.ErrorIs(t, err, test.expectedErr)
|
||||
if len(test.actions) == 0 {
|
||||
assert.Equal(t, accesscontrol.ResourcePermission{}, *added)
|
||||
} else {
|
||||
permissions, err := store.GetResourcesPermissions(context.Background(), user.OrgId, accesscontrol.GetResourcesPermissionsQuery{
|
||||
Actions: []string{"datasources:query"},
|
||||
Resource: test.add.resource,
|
||||
ResourceIDs: []string{test.add.resourceID},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
if test.add.resourceID != test.remove.resourceID {
|
||||
assert.Len(t, permissions, 1)
|
||||
} else {
|
||||
assert.Len(t, permissions, 0)
|
||||
}
|
||||
assert.Len(t, added.Actions, len(test.actions))
|
||||
assert.Equal(t, accesscontrol.GetResourceScope(test.resource, test.resourceID), added.Scope)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -381,7 +303,7 @@ func seedResourcePermissions(t *testing.T, store *AccessControlStore, sql *sqlst
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = store.SetUserResourcePermissions(context.Background(), 1, u.Id, accesscontrol.SetResourcePermissionsCommand{
|
||||
_, err = store.SetUserResourcePermission(context.Background(), 1, u.Id, accesscontrol.SetResourcePermissionCommand{
|
||||
Actions: actions,
|
||||
Resource: resource,
|
||||
ResourceID: resourceID,
|
||||
Reference in New Issue
Block a user