RBAC: Add an endpoint to list all user permissions (#57644)
* RBAC: Add an endpoint to see all user permissions Co-authored-by: Joey Orlando <joey.orlando@grafana.com> * Fix mock * Add feature flag * Fix merging * Return normal permissions instead of simplified ones * Fix test * Fix tests * Fix tests * Create benchtests * Split function to get basic roles * Comments * Reorg * Add two more tests to the bench * bench comment * Re-ran the test * Rename GetUsersPermissions to SearchUsersPermissions and prepare search options * Remove from model unused struct * Start adding option to get permissions by Action+Scope * Wrong import * Action and Scope * slightly tweak users permissions actionPrefix query param validation logic * Fix xor check * Lint * Account for suggeston Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add search * Remove comment on global scope * use union all and update test to make it run on all dbs * Fix MySQL needs a space * Account for suggestion. Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> Co-authored-by: Joey Orlando <joey.orlando@grafana.com> Co-authored-by: Joey Orlando <joseph.t.orlando@gmail.com> Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com>
This commit is contained in:
co-authored by
Joey Orlando
ievaVasiljeva
Joey Orlando
parent
fee50be1bb
commit
bf49c20050
@@ -55,6 +55,110 @@ func (s *AccessControlStore) GetUserPermissions(ctx context.Context, query acces
|
||||
return result, err
|
||||
}
|
||||
|
||||
// SearchUsersPermissions returns the list of user permissions indexed by UserID
|
||||
func (s *AccessControlStore) SearchUsersPermissions(ctx context.Context, orgID int64, options accesscontrol.SearchOptions) (map[int64][]accesscontrol.Permission, error) {
|
||||
type UserRBACPermission struct {
|
||||
UserID int64 `xorm:"user_id"`
|
||||
Action string `xorm:"action"`
|
||||
Scope string `xorm:"scope"`
|
||||
}
|
||||
dbPerms := make([]UserRBACPermission, 0)
|
||||
if err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
// Find permissions
|
||||
q := `
|
||||
SELECT
|
||||
user_id,
|
||||
action,
|
||||
scope
|
||||
FROM (
|
||||
SELECT ur.user_id, ur.org_id, p.action, p.scope
|
||||
FROM permission AS p
|
||||
INNER JOIN user_role AS ur on ur.role_id = p.role_id
|
||||
UNION ALL
|
||||
SELECT tm.user_id, tr.org_id, p.action, p.scope
|
||||
FROM permission AS p
|
||||
INNER JOIN team_role AS tr ON tr.role_id = p.role_id
|
||||
INNER JOIN team_member AS tm ON tm.team_id = tr.team_id
|
||||
UNION ALL
|
||||
SELECT ou.user_id, br.org_id, p.action, p.scope
|
||||
FROM permission AS p
|
||||
INNER JOIN builtin_role AS br ON br.role_id = p.role_id
|
||||
INNER JOIN org_user AS ou ON ou.role = br.role
|
||||
UNION ALL
|
||||
SELECT sa.user_id, br.org_id, p.action, p.scope
|
||||
FROM permission AS p
|
||||
INNER JOIN builtin_role AS br ON br.role_id = p.role_id
|
||||
INNER JOIN (
|
||||
SELECT u.id AS user_id
|
||||
FROM ` + s.sql.GetDialect().Quote("user") + ` AS u WHERE u.is_admin
|
||||
) AS sa ON 1 = 1
|
||||
WHERE br.role = ?
|
||||
) AS up
|
||||
WHERE (org_id = ? OR org_id = ?)
|
||||
`
|
||||
params := []interface{}{accesscontrol.RoleGrafanaAdmin, accesscontrol.GlobalOrgID, orgID}
|
||||
|
||||
if options.ActionPrefix != "" {
|
||||
q += ` AND action LIKE ?`
|
||||
params = append(params, options.ActionPrefix+"%")
|
||||
}
|
||||
if options.Action != "" {
|
||||
q += ` AND action = ?`
|
||||
params = append(params, options.Action)
|
||||
}
|
||||
if options.Scope != "" {
|
||||
q += ` AND scope = ?`
|
||||
params = append(params, options.Scope)
|
||||
}
|
||||
|
||||
return sess.SQL(q, params...).
|
||||
Find(&dbPerms)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mapped := map[int64][]accesscontrol.Permission{}
|
||||
for i := range dbPerms {
|
||||
mapped[dbPerms[i].UserID] = append(mapped[dbPerms[i].UserID], accesscontrol.Permission{Action: dbPerms[i].Action, Scope: dbPerms[i].Scope})
|
||||
}
|
||||
|
||||
return mapped, nil
|
||||
}
|
||||
|
||||
// GetUsersBasicRoles returns the list of user basic roles (Admin, Editor, Viewer, Grafana Admin) indexed by UserID
|
||||
func (s *AccessControlStore) GetUsersBasicRoles(ctx context.Context, orgID int64) (map[int64][]string, error) {
|
||||
type UserOrgRole struct {
|
||||
UserID int64 `xorm:"id"`
|
||||
OrgRole string `xorm:"role"`
|
||||
IsAdmin bool `xorm:"is_admin"`
|
||||
}
|
||||
dbRoles := make([]UserOrgRole, 0)
|
||||
if err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
// Find roles
|
||||
q := `
|
||||
SELECT u.id, ou.role, u.is_admin
|
||||
FROM ` + s.sql.GetDialect().Quote("user") + ` AS u
|
||||
LEFT JOIN org_user AS ou ON u.id = ou.user_id
|
||||
WHERE u.is_admin OR ou.org_id = ?
|
||||
`
|
||||
|
||||
return sess.SQL(q, orgID).Find(&dbRoles)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := map[int64][]string{}
|
||||
for i := range dbRoles {
|
||||
if dbRoles[i].OrgRole != "" {
|
||||
roles[dbRoles[i].UserID] = []string{dbRoles[i].OrgRole}
|
||||
}
|
||||
if dbRoles[i].IsAdmin {
|
||||
roles[dbRoles[i].UserID] = append(roles[dbRoles[i].UserID], accesscontrol.RoleGrafanaAdmin)
|
||||
}
|
||||
}
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) DeleteUserPermissions(ctx context.Context, orgID, userID int64) error {
|
||||
err := s.sql.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
roleDeleteQuery := "DELETE FROM user_role WHERE user_id = ?"
|
||||
|
||||
@@ -2,20 +2,24 @@ package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"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/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
rs "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"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 {
|
||||
@@ -82,7 +86,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
store, permissionStore, sql, teamSvc := setupTestEnv(t)
|
||||
store, permissionStore, sql, teamSvc, _ := setupTestEnv(t)
|
||||
|
||||
user, team := createUserAndTeam(t, sql, teamSvc, tt.orgID)
|
||||
|
||||
@@ -145,7 +149,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
|
||||
|
||||
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)
|
||||
store, permissionsStore, sql, teamSvc, _ := setupTestEnv(t)
|
||||
user, _ := createUserAndTeam(t, sql, teamSvc, 1)
|
||||
|
||||
// generate permissions in org 1
|
||||
@@ -185,7 +189,7 @@ func TestAccessControlStore_DeleteUserPermissions(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("expect permissions in org 1 to be deleted", func(t *testing.T) {
|
||||
store, permissionsStore, sql, teamSvc := setupTestEnv(t)
|
||||
store, permissionsStore, sql, teamSvc, _ := setupTestEnv(t)
|
||||
user, _ := createUserAndTeam(t, sql, teamSvc, 1)
|
||||
|
||||
// generate permissions in org 1
|
||||
@@ -225,10 +229,10 @@ func TestAccessControlStore_DeleteUserPermissions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func createUserAndTeam(t *testing.T, sql *sqlstore.SQLStore, teamSvc team.Service, orgID int64) (*user.User, models.Team) {
|
||||
func createUserAndTeam(t *testing.T, userSrv user.Service, teamSvc team.Service, orgID int64) (*user.User, models.Team) {
|
||||
t.Helper()
|
||||
|
||||
user, err := sql.CreateUser(context.Background(), user.CreateUserCommand{
|
||||
user, err := userSrv.Create(context.Background(), &user.CreateUserCommand{
|
||||
Login: "user",
|
||||
OrgID: orgID,
|
||||
})
|
||||
@@ -243,10 +247,339 @@ func createUserAndTeam(t *testing.T, sql *sqlstore.SQLStore, teamSvc team.Servic
|
||||
return user, team
|
||||
}
|
||||
|
||||
func setupTestEnv(t testing.TB) (*AccessControlStore, rs.Store, *sqlstore.SQLStore, team.Service) {
|
||||
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)
|
||||
|
||||
// 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, models.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)
|
||||
acstore := ProvideService(sql)
|
||||
permissionStore := rs.NewStore(sql)
|
||||
teamService := teamimpl.ProvideService(sql, cfg)
|
||||
return acstore, permissionStore, sql, teamService
|
||||
orgService, err := orgimpl.ProvideService(sql, cfg, quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
userService, err := userimpl.ProvideService(sql, orgService, cfg, teamService, localcache.ProvideService(), quotatest.New(false, nil))
|
||||
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: "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
|
||||
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},
|
||||
},
|
||||
},
|
||||
}
|
||||
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, 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user