Access control: use uid for dashboard and folder scopes (#46807)

* use uid:s for folder and dashboard permissions

* evaluate folder and dashboard permissions based on uids

* add dashboard.uid to accept list

* Check for exact suffix

* Check parent folder on create

* update test

* drop dashboard:create actions with dashboard scope

* fix typo

* AccessControl: test id 0 scope conversion

* AccessControl: store only parent folder UID

* AccessControl: extract general as a constant

* FolderServices: Prevent creation of a folder uid'd general

* FolderServices: Test folder creation prevention

* Update pkg/services/guardian/accesscontrol_guardian.go

* FolderServices: fix mock call expect

* FolderServices: remove uneeded mocks

Co-authored-by: jguer <joao.guerreiro@grafana.com>
This commit is contained in:
Karl Persson
2022-03-30 15:14:26 +02:00
committed by GitHub
co-authored by jguer
parent 56e9c24f08
commit a5e4a533fa
21 changed files with 369 additions and 256 deletions
+8 -9
View File
@@ -9,15 +9,14 @@ import (
)
var sqlIDAcceptList = map[string]struct{}{
"org_user.user_id": {},
"role.id": {},
"t.id": {},
"team.id": {},
"u.id": {},
"\"user\".\"id\"": {}, // For Postgres
"`user`.`id`": {}, // For MySQL and SQLite
"dashboard.id": {},
"dashboard.folder_id": {},
"org_user.user_id": {},
"role.id": {},
"t.id": {},
"team.id": {},
"u.id": {},
"\"user\".\"id\"": {}, // For Postgres
"`user`.`id`": {}, // For MySQL and SQLite
"dashboard.uid": {},
}
var (
+2 -1
View File
@@ -241,7 +241,8 @@ type SetResourcePermissionCommand struct {
}
const (
GlobalOrgID = 0
GlobalOrgID = 0
GeneralFolderUID = "general"
// Permission actions
@@ -23,11 +23,11 @@ func ProvidePermissionsServices(
if err != nil {
return nil, err
}
folderPermissions, err := provideFolderService(cfg, router, sql, ac, store)
folderPermissions, err := ProvideFolderPermissions(cfg, router, sql, ac, store)
if err != nil {
return nil, err
}
dashboardPermissions, err := provideDashboardService(cfg, router, sql, ac, store)
dashboardPermissions, err := ProvideDashboardPermissions(cfg, router, sql, ac, store)
if err != nil {
return nil, err
}
@@ -141,20 +141,13 @@ func ProvideTeamPermissions(
var DashboardViewActions = []string{accesscontrol.ActionDashboardsRead}
var DashboardEditActions = append(DashboardViewActions, []string{accesscontrol.ActionDashboardsWrite, accesscontrol.ActionDashboardsDelete}...)
var DashboardAdminActions = append(DashboardEditActions, []string{accesscontrol.ActionDashboardsPermissionsRead, accesscontrol.ActionDashboardsPermissionsWrite}...)
var FolderViewActions = []string{dashboards.ActionFoldersRead}
var FolderEditActions = append(FolderViewActions, []string{dashboards.ActionFoldersWrite, dashboards.ActionFoldersDelete, accesscontrol.ActionDashboardsCreate}...)
var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFoldersPermissionsRead, dashboards.ActionFoldersPermissionsWrite}...)
func provideDashboardService(
func ProvideDashboardPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
ac accesscontrol.AccessControl, store resourcepermissions.Store,
) (*resourcepermissions.Service, error) {
getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) {
id, err := strconv.ParseInt(resourceID, 10, 64)
if err != nil {
return nil, err
}
query := &models.GetDashboardQuery{Id: id, OrgId: orgID}
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil {
return nil, err
}
@@ -163,7 +156,7 @@ func provideDashboardService(
options := resourcepermissions.Options{
Resource: "dashboards",
ResourceAttribute: "id",
ResourceAttribute: "uid",
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
dashboard, err := getDashboard(ctx, orgID, resourceID)
if err != nil {
@@ -176,23 +169,13 @@ func provideDashboardService(
return nil
},
UidSolver: func(ctx context.Context, orgID int64, uid string) (int64, error) {
query := &models.GetDashboardQuery{
Uid: uid,
OrgId: orgID,
}
if err := sql.GetDashboard(ctx, query); err != nil {
return 0, err
}
return query.Result.Id, nil
},
InheritedScopesSolver: func(ctx context.Context, orgID int64, resourceID string) ([]string, error) {
dashboard, err := getDashboard(ctx, orgID, resourceID)
if err != nil {
return nil, err
}
if dashboard.FolderId > 0 {
return []string{accesscontrol.GetResourceScope("folders", strconv.FormatInt(dashboard.FolderId, 10))}, nil
return []string{dashboards.ScopeFoldersProvider.GetResourceScopeUID(dashboard.Uid)}, nil
}
return []string{}, nil
},
@@ -214,19 +197,19 @@ func provideDashboardService(
return resourcepermissions.New(options, cfg, router, ac, store, sql)
}
func provideFolderService(
var FolderViewActions = []string{dashboards.ActionFoldersRead}
var FolderEditActions = append(FolderViewActions, []string{dashboards.ActionFoldersWrite, dashboards.ActionFoldersDelete, accesscontrol.ActionDashboardsCreate}...)
var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFoldersPermissionsRead, dashboards.ActionFoldersPermissionsWrite}...)
func ProvideFolderPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store,
) (*resourcepermissions.Service, error) {
options := resourcepermissions.Options{
Resource: "folders",
ResourceAttribute: "id",
ResourceAttribute: "uid",
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
id, err := strconv.ParseInt(resourceID, 10, 64)
if err != nil {
return err
}
query := &models.GetDashboardQuery{Id: id, OrgId: orgID}
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil {
return err
}
@@ -237,16 +220,6 @@ func provideFolderService(
return nil
},
UidSolver: func(ctx context.Context, orgID int64, uid string) (int64, error) {
query := &models.GetDashboardQuery{
Uid: uid,
OrgId: orgID,
}
if err := sql.GetDashboard(ctx, query); err != nil {
return 0, err
}
return query.Result.Id, nil
},
Assignments: resourcepermissions.Assignments{
Users: true,
Teams: true,