provisioning: add isAdminOrAccessPolicy helper for auth checks

Consolidates authorization logic for provisioning endpoints:
- Adds isAdminOrAccessPolicy() helper that allows admin users OR AccessPolicy identities
- AccessPolicy identities (ST->MT flow) are trusted internal callers without org roles
- Regular users must have admin role (matching frontend navtree restriction)

Used in: authorizeSettings, authorizeStats, authorizeJobs, listFolderFiles
This commit is contained in:
Roberto Jimenez Sanchez committed 2025-12-17 18:05:25 +01:00
1 parent 307783ae06
commit cff098e552
2 files changed
+37 -10

No files matched your search

+12 -2
View File
@@ -15,6 +15,7 @@ import (
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
"github.com/grafana/grafana/apps/provisioning/pkg/safepath"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
)
@@ -235,8 +236,17 @@ func (c *filesConnector) Connect(ctx context.Context, name string, opts runtime.
// listFolderFiles returns a list of files in a folder
func (c *filesConnector) listFolderFiles(ctx context.Context, filePath string, ref string, readWriter repository.ReaderWriter) (*provisioning.FileList, error) {
// Authorization is handled at the route level - any authenticated user who can access
// the files endpoint can list files. The AccessClient controls per-file access.
id, err := identity.GetRequester(ctx)
if err != nil {
return nil, apierrors.NewUnauthorized("missing auth info in context")
}
// Check admin access - the frontend provisioning pages require admin access (controlled by navtree).
// AccessPolicy identities (ST->MT flow) are trusted internal callers.
if !isAdminOrAccessPolicy(id) {
return nil, apierrors.NewForbidden(resources.DashboardResource.GroupResource(), "",
fmt.Errorf("admin role is required"))
}
// TODO: Implement folder navigation
if len(filePath) > 0 {
+25 -8
View File
@@ -422,25 +422,42 @@ func (b *APIBuilder) authorizeRepositorySubresource(a authorizer.Attributes, id
}
}
// isAdminOrAccessPolicy checks if the requester is either an admin user or an AccessPolicy identity.
// AccessPolicy identities are used in trusted internal flows (e.g., ST->MT) and don't have org roles,
// so we allow them through. Regular users must have admin role.
func isAdminOrAccessPolicy(id identity.Requester) bool {
// AccessPolicy identities are trusted internal callers (ST->MT flow)
if authlib.IsIdentityType(id.GetIdentityType(), authlib.TypeAccessPolicy) {
return true
}
// Regular users need admin role
return id.GetOrgRole().Includes(identity.RoleAdmin)
}
// authorizeStats handles authorization for stats resource.
func (b *APIBuilder) authorizeStats(_ identity.Requester) (authorizer.Decision, string, error) {
func (b *APIBuilder) authorizeStats(id identity.Requester) (authorizer.Decision, string, error) {
// Stats is a read-only endpoint that returns resource counts.
// Any authenticated user can access it - authentication is verified before this point.
return authorizer.DecisionAllow, "", nil
// The frontend provisioning pages require admin access (controlled by navtree).
if isAdminOrAccessPolicy(id) {
return authorizer.DecisionAllow, "", nil
}
return authorizer.DecisionDeny, "admin role is required", nil
}
// authorizeSettings handles authorization for settings resource.
func (b *APIBuilder) authorizeSettings(_ identity.Requester) (authorizer.Decision, string, error) {
func (b *APIBuilder) authorizeSettings(id identity.Requester) (authorizer.Decision, string, error) {
// Settings is a read-only endpoint that returns available repository types and configuration.
// Any authenticated user can access it - authentication is verified before this point.
// The frontend needs this to display the provisioning wizard.
return authorizer.DecisionAllow, "", nil
// The frontend provisioning pages require admin access (controlled by navtree).
if isAdminOrAccessPolicy(id) {
return authorizer.DecisionAllow, "", nil
}
return authorizer.DecisionDeny, "admin role is required", nil
}
// authorizeJobs handles authorization for job resources.
func (b *APIBuilder) authorizeJobs(id identity.Requester) (authorizer.Decision, string, error) {
// Jobs are shown on the configuration page.
if id.GetOrgRole().Includes(identity.RoleAdmin) {
if isAdminOrAccessPolicy(id) {
return authorizer.DecisionAllow, "", nil
}
return authorizer.DecisionDeny, "admin role is required", nil