mirror of
https://github.com/grafana/grafana.git
synced 2026-08-18 17:15:08 -05:00
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:
@@ -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 (
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user