Files
grafana/pkg/services/accesscontrol/ossaccesscontrol/folder.go
mohammad-hamid 3c5d905e0f AuthZ: Redirect legacy resource permissions handler to k8s (part I) (#114199)
* Add K8s API redirect for GET resource permissions

* wire

* move restconfig to options

* address comments

* fix helper after adding RestConfigProvider

* Revert K8s redirect changes for service accounts, teams, and receivers

Keep only dashboard and folder redirect functionality for this PR.
Service accounts, teams, and receivers will be handled in a separate PR.

* address comments

* lint
2025-12-04 10:04:23 -05:00

157 lines
5.9 KiB
Go

package ossaccesscontrol
import (
"context"
"errors"
folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
"github.com/grafana/grafana/pkg/services/apiserver"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/libraryelements"
"github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
type FolderPermissionsService struct {
*resourcepermissions.Service
}
var ErrFolderUnhandledError = errutil.Internal("folder.unhandled-error", errutil.WithPublicMessage("Unhandled folder error"))
var FolderViewActions = []string{dashboards.ActionFoldersRead, accesscontrol.ActionAlertingRuleRead, libraryelements.ActionLibraryPanelsRead, accesscontrol.ActionAlertingSilencesRead}
var FolderEditActions = append(FolderViewActions, []string{
dashboards.ActionFoldersWrite,
dashboards.ActionFoldersDelete,
dashboards.ActionDashboardsCreate,
accesscontrol.ActionAlertingRuleCreate,
accesscontrol.ActionAlertingRuleUpdate,
accesscontrol.ActionAlertingRuleDelete,
accesscontrol.ActionAlertingSilencesCreate,
accesscontrol.ActionAlertingSilencesWrite,
libraryelements.ActionLibraryPanelsCreate,
libraryelements.ActionLibraryPanelsWrite,
libraryelements.ActionLibraryPanelsDelete,
}...)
var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFoldersPermissionsRead, dashboards.ActionFoldersPermissionsWrite}...)
func registerFolderRoles(cfg *setting.Cfg, features featuremgmt.FeatureToggles, service accesscontrol.Service) error {
if !cfg.RBAC.PermissionsWildcardSeed("folder") {
return nil
}
viewer := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
Name: "fixed:folders:viewer",
DisplayName: "Viewer",
Description: "View all folders and dashboards.",
Group: "Folders",
Permissions: accesscontrol.PermissionsForActions(append(getDashboardViewActions(features), FolderViewActions...), dashboards.ScopeFoldersAll),
Hidden: true,
},
Grants: []string{"Viewer"},
}
editor := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
Name: "fixed:folders:editor",
DisplayName: "Editor",
Description: "Edit all folders and dashboards.",
Group: "Folders",
Permissions: accesscontrol.PermissionsForActions(append(getDashboardEditActions(features), FolderEditActions...), dashboards.ScopeFoldersAll),
Hidden: true,
},
Grants: []string{"Editor"},
}
admin := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
Name: "fixed:folders:admin",
DisplayName: "Admin",
Description: "Administer all folders and dashboards",
Group: "folders",
Permissions: accesscontrol.PermissionsForActions(append(getDashboardAdminActions(features), FolderAdminActions...), dashboards.ScopeFoldersAll),
Hidden: true,
},
Grants: []string{"Admin"},
}
return service.DeclareFixedRoles(viewer, editor, admin)
}
func ProvideFolderPermissions(
cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, accesscontrol accesscontrol.AccessControl,
license licensing.Licensing, folderService folder.Service, service accesscontrol.Service,
teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService,
restConfigProvider apiserver.RestConfigProvider,
) (*FolderPermissionsService, error) {
if err := registerFolderRoles(cfg, features, service); err != nil {
return nil, err
}
options := resourcepermissions.Options{
Resource: "folders",
ResourceAttribute: "uid",
APIGroup: folderv1.APIGroup,
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
ctx, span := tracer.Start(ctx, "accesscontrol.ossaccesscontrol.ProvideFolderPermissions.ResourceValidator")
defer span.End()
ctx, ident := identity.WithServiceIdentity(ctx, orgID)
_, err := folderService.Get(ctx, &folder.GetFolderQuery{
UID: &resourceID,
OrgID: orgID,
SignedInUser: ident,
})
if err != nil {
switch {
case func() bool {
var errUtilErr errutil.Error
return errors.As(err, &errUtilErr)
}():
return err
case errors.Is(err, dashboards.ErrFolderNotFound):
return folder.ErrFolderNotFound.Errorf("folder not found")
}
return ErrFolderUnhandledError.Errorf("unhandled folder error: %w", err)
}
return nil
},
InheritedScopesSolver: func(ctx context.Context, orgID int64, resourceID string) ([]string, error) {
ctx, _ = identity.WithServiceIdentity(ctx, orgID)
return dashboards.GetInheritedScopes(ctx, orgID, resourceID, folderService)
},
Assignments: resourcepermissions.Assignments{
Users: true,
Teams: true,
BuiltInRoles: true,
ServiceAccounts: true,
},
PermissionsToActions: map[string][]string{
"View": append(getDashboardViewActions(features), FolderViewActions...),
"Edit": append(getDashboardEditActions(features), FolderEditActions...),
"Admin": append(getDashboardAdminActions(features), FolderAdminActions...),
},
ReaderRoleName: "Permission reader",
WriterRoleName: "Permission writer",
RoleGroup: "Folders",
RestConfigProvider: restConfigProvider,
}
srv, err := resourcepermissions.New(cfg, options, features, router, license, accesscontrol, service, sql, teamService, userService, actionSetService)
if err != nil {
return nil, err
}
return &FolderPermissionsService{srv}, nil
}