mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 12:14:08 -06:00
0de66a8099
* remove use of SignedInUserCopies * add extra safety to not cross assign permissions unwind circular dependency dashboardacl->dashboardaccess fix missing import * correctly set teams for permissions * fix missing inits * nit: check err * exit early for api keys
642 lines
23 KiB
Go
642 lines
23 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
|
"github.com/grafana/grafana/pkg/infra/localcache"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
rs "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
|
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
|
"github.com/grafana/grafana/pkg/services/team"
|
|
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
|
)
|
|
|
|
type getUserPermissionsTestCase struct {
|
|
desc string
|
|
anonymousUser bool
|
|
orgID int64
|
|
role string
|
|
userPermissions []string
|
|
teamPermissions []string
|
|
builtinPermissions []string
|
|
expected int
|
|
policyCount int
|
|
}
|
|
|
|
func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
|
tests := []getUserPermissionsTestCase{
|
|
{
|
|
desc: "should successfully get user, team and builtin permissions",
|
|
orgID: 1,
|
|
role: "Admin",
|
|
userPermissions: []string{"1", "2", "10"},
|
|
teamPermissions: []string{"100", "2"},
|
|
builtinPermissions: []string{"5", "6"},
|
|
expected: 7,
|
|
policyCount: 7,
|
|
},
|
|
{
|
|
desc: "Should not get admin roles",
|
|
orgID: 1,
|
|
role: "Viewer",
|
|
userPermissions: []string{"1", "2", "10"},
|
|
teamPermissions: []string{"100", "2"},
|
|
builtinPermissions: []string{"5", "6"},
|
|
expected: 5,
|
|
policyCount: 7,
|
|
},
|
|
{
|
|
desc: "Should work without org role",
|
|
orgID: 1,
|
|
role: "",
|
|
userPermissions: []string{"1", "2", "10"},
|
|
teamPermissions: []string{"100", "2"},
|
|
builtinPermissions: []string{"5", "6"},
|
|
expected: 5,
|
|
policyCount: 7,
|
|
},
|
|
{
|
|
desc: "should only get br permissions for anonymous user",
|
|
anonymousUser: true,
|
|
orgID: 1,
|
|
role: "Admin",
|
|
userPermissions: []string{"1", "2", "10"},
|
|
teamPermissions: []string{"100", "2"},
|
|
builtinPermissions: []string{"5", "6"},
|
|
expected: 2,
|
|
policyCount: 7,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
store, permissionStore, sql, teamSvc, _ := setupTestEnv(t)
|
|
|
|
user, team := createUserAndTeam(t, sql, teamSvc, tt.orgID)
|
|
|
|
for _, id := range tt.userPermissions {
|
|
_, err := permissionStore.SetUserResourcePermission(context.Background(), tt.orgID, accesscontrol.User{ID: user.ID}, rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:write"},
|
|
Resource: "dashboards",
|
|
ResourceID: id,
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
for _, id := range tt.teamPermissions {
|
|
_, err := permissionStore.SetTeamResourcePermission(context.Background(), tt.orgID, team.ID, rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:read"},
|
|
Resource: "dashboards",
|
|
ResourceID: id,
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
for _, id := range tt.builtinPermissions {
|
|
_, err := permissionStore.SetBuiltInResourcePermission(context.Background(), tt.orgID, "Admin", rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:read"},
|
|
Resource: "dashboards",
|
|
ResourceID: id,
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
var roles []string
|
|
role := org.RoleType(tt.role)
|
|
|
|
if role.IsValid() {
|
|
roles = append(roles, string(role))
|
|
for _, c := range role.Children() {
|
|
roles = append(roles, string(c))
|
|
}
|
|
}
|
|
|
|
userID := user.ID
|
|
teamIDs := []int64{team.ID}
|
|
if tt.anonymousUser {
|
|
userID = 0
|
|
teamIDs = []int64{}
|
|
}
|
|
permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
|
|
OrgID: tt.orgID,
|
|
UserID: userID,
|
|
Roles: roles,
|
|
TeamIDs: teamIDs,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
assert.Len(t, permissions, tt.expected)
|
|
|
|
policies, err := GetAccessPolicies(context.Background(), user.OrgID, store.sql.GetSqlxSession(),
|
|
func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
|
return strings.Split(scope, ":"), nil
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, policies, tt.policyCount)
|
|
|
|
for idx, p := range policies {
|
|
fmt.Printf("POLICIES[%d] %+v\n", idx, p.Spec)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAccessControlStore_DeleteUserPermissions(t *testing.T) {
|
|
t.Run("expect permissions in all orgs to be deleted", func(t *testing.T) {
|
|
store, permissionsStore, sql, teamSvc, _ := setupTestEnv(t)
|
|
user, _ := createUserAndTeam(t, sql, teamSvc, 1)
|
|
|
|
// generate permissions in org 1
|
|
_, err := permissionsStore.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: user.ID}, rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:write"},
|
|
Resource: "dashboards",
|
|
ResourceID: "1",
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
|
|
// generate permissions in org 2
|
|
_, err = permissionsStore.SetUserResourcePermission(context.Background(), 2, accesscontrol.User{ID: user.ID}, rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:write"},
|
|
Resource: "dashboards",
|
|
ResourceID: "1",
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
|
|
err = store.DeleteUserPermissions(context.Background(), accesscontrol.GlobalOrgID, user.ID)
|
|
require.NoError(t, err)
|
|
|
|
permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
|
|
OrgID: 1,
|
|
UserID: user.ID,
|
|
Roles: []string{"Admin"},
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, permissions, 0)
|
|
|
|
permissions, err = store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
|
|
OrgID: 2,
|
|
UserID: user.ID,
|
|
Roles: []string{"Admin"},
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, permissions, 0)
|
|
})
|
|
|
|
t.Run("expect permissions in org 1 to be deleted", func(t *testing.T) {
|
|
store, permissionsStore, sql, teamSvc, _ := setupTestEnv(t)
|
|
user, _ := createUserAndTeam(t, sql, teamSvc, 1)
|
|
|
|
// generate permissions in org 1
|
|
_, err := permissionsStore.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: user.ID}, rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:write"},
|
|
Resource: "dashboards",
|
|
ResourceID: "1",
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
|
|
// generate permissions in org 2
|
|
_, err = permissionsStore.SetUserResourcePermission(context.Background(), 2, accesscontrol.User{ID: user.ID}, rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:write"},
|
|
Resource: "dashboards",
|
|
ResourceID: "1",
|
|
}, nil)
|
|
require.NoError(t, err)
|
|
|
|
err = store.DeleteUserPermissions(context.Background(), 1, user.ID)
|
|
require.NoError(t, err)
|
|
|
|
permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
|
|
OrgID: 1,
|
|
UserID: user.ID,
|
|
Roles: []string{"Admin"},
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, permissions, 0)
|
|
|
|
permissions, err = store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{
|
|
OrgID: 2,
|
|
UserID: user.ID,
|
|
Roles: []string{"Admin"},
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, permissions, 1)
|
|
})
|
|
}
|
|
|
|
func createUserAndTeam(t *testing.T, userSrv user.Service, teamSvc team.Service, orgID int64) (*user.User, team.Team) {
|
|
t.Helper()
|
|
|
|
user, err := userSrv.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: "user",
|
|
OrgID: orgID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
team, err := teamSvc.CreateTeam("team", "", orgID)
|
|
require.NoError(t, err)
|
|
|
|
err = teamSvc.AddTeamMember(user.ID, orgID, team.ID, false, dashboardaccess.PERMISSION_VIEW)
|
|
require.NoError(t, err)
|
|
|
|
return user, team
|
|
}
|
|
|
|
type helperServices struct {
|
|
userSvc user.Service
|
|
teamSvc team.Service
|
|
orgSvc org.Service
|
|
}
|
|
|
|
type testUser struct {
|
|
orgRole org.RoleType
|
|
isAdmin bool
|
|
}
|
|
|
|
type dbUser struct {
|
|
userID int64
|
|
teamID int64
|
|
}
|
|
|
|
func createUsersAndTeams(t *testing.T, svcs helperServices, orgID int64, users []testUser) []dbUser {
|
|
t.Helper()
|
|
res := []dbUser{}
|
|
|
|
for i := range users {
|
|
user, err := svcs.userSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: fmt.Sprintf("user%v", i+1),
|
|
OrgID: orgID,
|
|
IsAdmin: users[i].isAdmin,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, orgID, user.OrgID)
|
|
|
|
// User is not member of the org
|
|
if users[i].orgRole == "" {
|
|
err = svcs.orgSvc.RemoveOrgUser(context.Background(),
|
|
&org.RemoveOrgUserCommand{OrgID: orgID, UserID: user.ID})
|
|
require.NoError(t, err)
|
|
|
|
res = append(res, dbUser{userID: user.ID})
|
|
continue
|
|
}
|
|
|
|
team, err := svcs.teamSvc.CreateTeam(fmt.Sprintf("team%v", i+1), "", orgID)
|
|
require.NoError(t, err)
|
|
|
|
err = svcs.teamSvc.AddTeamMember(user.ID, orgID, team.ID, false, dashboardaccess.PERMISSION_VIEW)
|
|
require.NoError(t, err)
|
|
|
|
err = svcs.orgSvc.UpdateOrgUser(context.Background(),
|
|
&org.UpdateOrgUserCommand{Role: users[i].orgRole, OrgID: orgID, UserID: user.ID})
|
|
require.NoError(t, err)
|
|
|
|
res = append(res, dbUser{userID: user.ID, teamID: team.ID})
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func setupTestEnv(t testing.TB) (*AccessControlStore, rs.Store, user.Service, team.Service, org.Service) {
|
|
sql, cfg := db.InitTestDBwithCfg(t)
|
|
cfg.AutoAssignOrg = true
|
|
cfg.AutoAssignOrgRole = "Viewer"
|
|
cfg.AutoAssignOrgId = 1
|
|
acstore := ProvideService(sql)
|
|
permissionStore := rs.NewStore(sql, featuremgmt.WithFeatures())
|
|
teamService := teamimpl.ProvideService(sql, cfg)
|
|
orgService, err := orgimpl.ProvideService(sql, cfg, quotatest.New(false, nil))
|
|
require.NoError(t, err)
|
|
|
|
orgID, err := orgService.GetOrCreate(context.Background(), "test")
|
|
require.Equal(t, int64(1), orgID)
|
|
require.NoError(t, err)
|
|
|
|
userService, err := userimpl.ProvideService(sql, orgService, cfg, teamService, localcache.ProvideService(), quotatest.New(false, nil), supportbundlestest.NewFakeBundleService())
|
|
require.NoError(t, err)
|
|
return acstore, permissionStore, userService, teamService, orgService
|
|
}
|
|
|
|
func TestIntegrationAccessControlStore_SearchUsersPermissions(t *testing.T) {
|
|
ctx := context.Background()
|
|
readTeamPerm := func(teamID string) rs.SetResourcePermissionCommand {
|
|
return rs.SetResourcePermissionCommand{
|
|
Actions: []string{"teams:read"},
|
|
Resource: "teams",
|
|
ResourceAttribute: "id",
|
|
ResourceID: teamID,
|
|
}
|
|
}
|
|
writeTeamPerm := func(teamID string) rs.SetResourcePermissionCommand {
|
|
return rs.SetResourcePermissionCommand{
|
|
Actions: []string{"teams:read", "teams:write"},
|
|
Resource: "teams",
|
|
ResourceAttribute: "id",
|
|
ResourceID: teamID,
|
|
}
|
|
}
|
|
readDashPerm := func(dashUID string) rs.SetResourcePermissionCommand {
|
|
return rs.SetResourcePermissionCommand{
|
|
Actions: []string{"dashboards:read"},
|
|
Resource: "dashboards",
|
|
ResourceAttribute: "uid",
|
|
ResourceID: dashUID,
|
|
}
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
users []testUser
|
|
permCmds []rs.SetResourcePermissionsCommand
|
|
options accesscontrol.SearchOptions
|
|
wantPerm map[int64][]accesscontrol.Permission
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "user assignment by actionPrefix",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {{Action: "teams:read", Scope: "teams:id:1"}}},
|
|
},
|
|
{
|
|
name: "users assignment by actionPrefix",
|
|
users: []testUser{
|
|
{orgRole: org.RoleAdmin, isAdmin: false},
|
|
{orgRole: org.RoleEditor, isAdmin: false},
|
|
},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: writeTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 2, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("2")},
|
|
},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{
|
|
1: {{Action: "teams:read", Scope: "teams:id:1"}, {Action: "teams:write", Scope: "teams:id:1"}},
|
|
2: {{Action: "teams:read", Scope: "teams:id:2"}},
|
|
},
|
|
},
|
|
{
|
|
name: "team assignment by actionPrefix",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{{TeamID: 1, SetResourcePermissionCommand: readTeamPerm("1")}},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {{Action: "teams:read", Scope: "teams:id:1"}}},
|
|
},
|
|
{
|
|
name: "basic role assignment by actionPrefix",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{BuiltinRole: string(org.RoleAdmin), SetResourcePermissionCommand: readTeamPerm("1")},
|
|
},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {{Action: "teams:read", Scope: "teams:id:1"}}},
|
|
},
|
|
{
|
|
name: "server admin assignment by actionPrefix",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: true}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{BuiltinRole: accesscontrol.RoleGrafanaAdmin, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {{Action: "teams:read", Scope: "teams:id:1"}}},
|
|
},
|
|
{
|
|
name: "all assignments by actionPrefix",
|
|
users: []testUser{
|
|
{orgRole: org.RoleAdmin, isAdmin: true},
|
|
{orgRole: org.RoleEditor, isAdmin: false},
|
|
},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
// User assignments
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 2, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("2")},
|
|
// Team assignments
|
|
{TeamID: 1, SetResourcePermissionCommand: readTeamPerm("10")},
|
|
{TeamID: 2, SetResourcePermissionCommand: readTeamPerm("20")},
|
|
// Basic Assignments
|
|
{BuiltinRole: string(org.RoleAdmin), SetResourcePermissionCommand: readTeamPerm("100")},
|
|
{BuiltinRole: string(org.RoleEditor), SetResourcePermissionCommand: readTeamPerm("200")},
|
|
// Server Admin Assignment
|
|
{BuiltinRole: accesscontrol.RoleGrafanaAdmin, SetResourcePermissionCommand: readTeamPerm("1000")},
|
|
},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{
|
|
1: {{Action: "teams:read", Scope: "teams:id:1"}, {Action: "teams:read", Scope: "teams:id:10"},
|
|
{Action: "teams:read", Scope: "teams:id:100"}, {Action: "teams:read", Scope: "teams:id:1000"}},
|
|
2: {{Action: "teams:read", Scope: "teams:id:2"}, {Action: "teams:read", Scope: "teams:id:20"},
|
|
{Action: "teams:read", Scope: "teams:id:200"}},
|
|
},
|
|
},
|
|
{
|
|
name: "all assignments for one user by actionPrefix",
|
|
users: []testUser{
|
|
{orgRole: org.RoleAdmin, isAdmin: true},
|
|
{orgRole: org.RoleEditor, isAdmin: false},
|
|
},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
// User assignments
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 2, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("2")},
|
|
// Team assignments
|
|
{TeamID: 1, SetResourcePermissionCommand: readTeamPerm("10")},
|
|
{TeamID: 2, SetResourcePermissionCommand: readTeamPerm("20")},
|
|
// Basic Assignments
|
|
{BuiltinRole: string(org.RoleAdmin), SetResourcePermissionCommand: readTeamPerm("100")},
|
|
{BuiltinRole: string(org.RoleEditor), SetResourcePermissionCommand: readTeamPerm("200")},
|
|
// Server Admin Assignment
|
|
{BuiltinRole: accesscontrol.RoleGrafanaAdmin, SetResourcePermissionCommand: readTeamPerm("1000")},
|
|
},
|
|
options: accesscontrol.SearchOptions{
|
|
ActionPrefix: "teams:",
|
|
UserID: 1,
|
|
},
|
|
wantPerm: map[int64][]accesscontrol.Permission{
|
|
1: {{Action: "teams:read", Scope: "teams:id:1"}, {Action: "teams:read", Scope: "teams:id:10"},
|
|
{Action: "teams:read", Scope: "teams:id:100"}, {Action: "teams:read", Scope: "teams:id:1000"}},
|
|
},
|
|
},
|
|
{
|
|
name: "filter permissions by action prefix",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: true}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
// User assignments
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readDashPerm("d1")},
|
|
// Team assignments
|
|
{TeamID: 1, SetResourcePermissionCommand: readTeamPerm("10")},
|
|
{TeamID: 1, SetResourcePermissionCommand: readDashPerm("d10")},
|
|
// Basic Assignments
|
|
{BuiltinRole: string(org.RoleAdmin), SetResourcePermissionCommand: readTeamPerm("100")},
|
|
{BuiltinRole: string(org.RoleAdmin), SetResourcePermissionCommand: readDashPerm("d100")},
|
|
// Server Admin Assignment
|
|
{BuiltinRole: accesscontrol.RoleGrafanaAdmin, SetResourcePermissionCommand: readTeamPerm("1000")},
|
|
{BuiltinRole: accesscontrol.RoleGrafanaAdmin, SetResourcePermissionCommand: readDashPerm("d1000")},
|
|
},
|
|
options: accesscontrol.SearchOptions{ActionPrefix: "teams:"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{
|
|
1: {{Action: "teams:read", Scope: "teams:id:1"}, {Action: "teams:read", Scope: "teams:id:10"},
|
|
{Action: "teams:read", Scope: "teams:id:100"}, {Action: "teams:read", Scope: "teams:id:1000"}},
|
|
},
|
|
},
|
|
{
|
|
name: "include not org member server admin permissions by actionPrefix",
|
|
// Three users, one member, one not member but Server Admin, one not member and not server admin
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}, {isAdmin: true}, {}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{{BuiltinRole: accesscontrol.RoleGrafanaAdmin, SetResourcePermissionCommand: readTeamPerm("1")}},
|
|
wantPerm: map[int64][]accesscontrol.Permission{
|
|
2: {{Action: "teams:read", Scope: "teams:id:1"}},
|
|
},
|
|
},
|
|
{
|
|
name: "user assignment by action",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("2")},
|
|
},
|
|
options: accesscontrol.SearchOptions{Action: "teams:read"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {
|
|
{Action: "teams:read", Scope: "teams:id:1"},
|
|
{Action: "teams:read", Scope: "teams:id:2"}},
|
|
},
|
|
},
|
|
{
|
|
name: "user assignment by scope",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: writeTeamPerm("1")},
|
|
},
|
|
options: accesscontrol.SearchOptions{Scope: "teams:id:1"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {
|
|
{Action: "teams:read", Scope: "teams:id:1"},
|
|
{Action: "teams:write", Scope: "teams:id:1"},
|
|
}},
|
|
},
|
|
{
|
|
name: "user assignment by action and scope",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
permCmds: []rs.SetResourcePermissionsCommand{
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("1")},
|
|
{User: accesscontrol.User{ID: 1, IsExternal: false}, SetResourcePermissionCommand: readTeamPerm("2")},
|
|
},
|
|
options: accesscontrol.SearchOptions{Action: "teams:read", Scope: "teams:id:1"},
|
|
wantPerm: map[int64][]accesscontrol.Permission{1: {{Action: "teams:read", Scope: "teams:id:1"}}},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
acStore, permissionsStore, userSvc, teamSvc, orgSvc := setupTestEnv(t)
|
|
dbUsers := createUsersAndTeams(t, helperServices{userSvc, teamSvc, orgSvc}, 1, tt.users)
|
|
|
|
// Switch userID and TeamID by the real stored ones
|
|
for i := range tt.permCmds {
|
|
if tt.permCmds[i].User.ID != 0 {
|
|
tt.permCmds[i].User.ID = dbUsers[tt.permCmds[i].User.ID-1].userID
|
|
}
|
|
if tt.permCmds[i].TeamID != 0 {
|
|
tt.permCmds[i].TeamID = dbUsers[tt.permCmds[i].TeamID-1].teamID
|
|
}
|
|
}
|
|
_, err := permissionsStore.SetResourcePermissions(ctx, 1, tt.permCmds, rs.ResourceHooks{})
|
|
require.NoError(t, err)
|
|
|
|
// Test
|
|
dbPermissions, err := acStore.SearchUsersPermissions(ctx, 1, tt.options)
|
|
if tt.wantErr {
|
|
require.NotNil(t, err)
|
|
return
|
|
}
|
|
require.Nil(t, err)
|
|
require.Len(t, dbPermissions, len(tt.wantPerm))
|
|
|
|
for userID, expectedUserPerms := range tt.wantPerm {
|
|
dbUserPerms, ok := dbPermissions[dbUsers[userID-1].userID]
|
|
require.True(t, ok, "expected permissions for user", userID)
|
|
require.ElementsMatch(t, expectedUserPerms, dbUserPerms)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAccessControlStore_GetUsersBasicRoles(t *testing.T) {
|
|
ctx := context.Background()
|
|
tests := []struct {
|
|
name string
|
|
users []testUser
|
|
userFilter []int64
|
|
wantRoles map[int64][]string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "user with basic role",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}},
|
|
wantRoles: map[int64][]string{1: {string(org.RoleAdmin)}},
|
|
},
|
|
{
|
|
name: "one admin, one editor",
|
|
users: []testUser{
|
|
{orgRole: org.RoleAdmin, isAdmin: false},
|
|
{orgRole: org.RoleEditor, isAdmin: false},
|
|
},
|
|
wantRoles: map[int64][]string{
|
|
1: {string(org.RoleAdmin)},
|
|
2: {string(org.RoleEditor)},
|
|
},
|
|
},
|
|
{
|
|
name: "one org member, one not member but Server Admin, one not member and not server admin",
|
|
users: []testUser{{orgRole: org.RoleAdmin, isAdmin: false}, {isAdmin: true}, {}},
|
|
wantRoles: map[int64][]string{
|
|
1: {string(org.RoleAdmin)},
|
|
2: {accesscontrol.RoleGrafanaAdmin},
|
|
},
|
|
},
|
|
{
|
|
name: "when filtered to one user, returns results only for that user",
|
|
userFilter: []int64{2},
|
|
users: []testUser{
|
|
{orgRole: org.RoleAdmin, isAdmin: false},
|
|
{orgRole: org.RoleEditor, isAdmin: true},
|
|
},
|
|
wantRoles: map[int64][]string{
|
|
2: {string(org.RoleEditor), accesscontrol.RoleGrafanaAdmin},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
acStore, _, userSvc, teamSvc, orgSvc := setupTestEnv(t)
|
|
dbUsers := createUsersAndTeams(t, helperServices{userSvc, teamSvc, orgSvc}, 1, tt.users)
|
|
|
|
// Test
|
|
dbRoles, err := acStore.GetUsersBasicRoles(ctx, tt.userFilter, 1)
|
|
if tt.wantErr {
|
|
require.NotNil(t, err)
|
|
return
|
|
}
|
|
require.Nil(t, err)
|
|
require.Len(t, dbRoles, len(tt.wantRoles))
|
|
|
|
for userID, expectedUserRoles := range tt.wantRoles {
|
|
dbUserRoles, ok := dbRoles[dbUsers[userID-1].userID]
|
|
require.True(t, ok, "expected organization role for user", userID)
|
|
require.ElementsMatch(t, expectedUserRoles, dbUserRoles)
|
|
}
|
|
})
|
|
}
|
|
}
|