mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
RBAC: allow listing permissions on the root folder (#82184)
* allow returning AC metadata for the root folder * add a test * share the reserved root folder UID with frontend
This commit is contained in:
@@ -225,6 +225,7 @@ export interface GrafanaConfig {
|
|||||||
rudderstackIntegrationsUrl: string | undefined;
|
rudderstackIntegrationsUrl: string | undefined;
|
||||||
sqlConnectionLimits: SqlConnectionLimits;
|
sqlConnectionLimits: SqlConnectionLimits;
|
||||||
sharedWithMeFolderUID?: string;
|
sharedWithMeFolderUID?: string;
|
||||||
|
rootFolderUID?: string;
|
||||||
|
|
||||||
// The namespace to use for kubernetes apiserver requests
|
// The namespace to use for kubernetes apiserver requests
|
||||||
namespace: string;
|
namespace: string;
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
|||||||
tokenExpirationDayLimit: undefined;
|
tokenExpirationDayLimit: undefined;
|
||||||
disableFrontendSandboxForPlugins: string[] = [];
|
disableFrontendSandboxForPlugins: string[] = [];
|
||||||
sharedWithMeFolderUID: string | undefined;
|
sharedWithMeFolderUID: string | undefined;
|
||||||
|
rootFolderUID: string | undefined;
|
||||||
|
|
||||||
constructor(options: GrafanaBootConfig) {
|
constructor(options: GrafanaBootConfig) {
|
||||||
this.bootData = options.bootData;
|
this.bootData = options.bootData;
|
||||||
|
|||||||
@@ -457,6 +457,21 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Grants: []string{"Admin"},
|
Grants: []string{"Admin"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed to be able to list permissions on the general folder for viewers, doesn't actually grant access to any resources
|
||||||
|
generalFolderReaderRole := ac.RoleRegistration{
|
||||||
|
Role: ac.RoleDTO{
|
||||||
|
Name: "fixed:folders.general:reader",
|
||||||
|
DisplayName: "General folder reader",
|
||||||
|
Description: "Access the general (root) folder.",
|
||||||
|
Group: "Folders",
|
||||||
|
Hidden: true,
|
||||||
|
Permissions: []ac.Permission{
|
||||||
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.GeneralFolderUID)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Grants: []string{string(org.RoleViewer)},
|
||||||
|
}
|
||||||
|
|
||||||
foldersWriterRole := ac.RoleRegistration{
|
foldersWriterRole := ac.RoleRegistration{
|
||||||
Role: ac.RoleDTO{
|
Role: ac.RoleDTO{
|
||||||
Name: "fixed:folders:writer",
|
Name: "fixed:folders:writer",
|
||||||
@@ -593,7 +608,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
orgMaintainerRole, teamsCreatorRole, teamsWriterRole, teamsReaderRole, datasourcesExplorerRole,
|
orgMaintainerRole, teamsCreatorRole, teamsWriterRole, teamsReaderRole, datasourcesExplorerRole,
|
||||||
annotationsReaderRole, dashboardAnnotationsWriterRole, annotationsWriterRole,
|
annotationsReaderRole, dashboardAnnotationsWriterRole, annotationsWriterRole,
|
||||||
dashboardsCreatorRole, dashboardsReaderRole, dashboardsWriterRole,
|
dashboardsCreatorRole, dashboardsReaderRole, dashboardsWriterRole,
|
||||||
foldersCreatorRole, foldersReaderRole, foldersWriterRole, apikeyReaderRole, apikeyWriterRole,
|
foldersCreatorRole, foldersReaderRole, generalFolderReaderRole, foldersWriterRole, apikeyReaderRole, apikeyWriterRole,
|
||||||
publicDashboardsWriterRole, featuremgmtReaderRole, featuremgmtWriterRole, libraryPanelsCreatorRole,
|
publicDashboardsWriterRole, featuremgmtReaderRole, featuremgmtWriterRole, libraryPanelsCreatorRole,
|
||||||
libraryPanelsReaderRole, libraryPanelsWriterRole, libraryPanelsGeneralReaderRole, libraryPanelsGeneralWriterRole}
|
libraryPanelsReaderRole, libraryPanelsWriterRole, libraryPanelsGeneralReaderRole, libraryPanelsGeneralWriterRole}
|
||||||
|
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ type FrontendSettingsDTO struct {
|
|||||||
SamlName string `json:"samlName"`
|
SamlName string `json:"samlName"`
|
||||||
TokenExpirationDayLimit int `json:"tokenExpirationDayLimit"`
|
TokenExpirationDayLimit int `json:"tokenExpirationDayLimit"`
|
||||||
SharedWithMeFolderUID string `json:"sharedWithMeFolderUID"`
|
SharedWithMeFolderUID string `json:"sharedWithMeFolderUID"`
|
||||||
|
RootFolderUID string `json:"rootFolderUID"`
|
||||||
|
|
||||||
GeomapDefaultBaseLayerConfig *map[string]any `json:"geomapDefaultBaseLayerConfig,omitempty"`
|
GeomapDefaultBaseLayerConfig *map[string]any `json:"geomapDefaultBaseLayerConfig,omitempty"`
|
||||||
GeomapDisableCustomBaseLayer bool `json:"geomapDisableCustomBaseLayer"`
|
GeomapDisableCustomBaseLayer bool `json:"geomapDisableCustomBaseLayer"`
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
|||||||
PublicDashboardAccessToken: c.PublicDashboardAccessToken,
|
PublicDashboardAccessToken: c.PublicDashboardAccessToken,
|
||||||
PublicDashboardsEnabled: hs.Cfg.PublicDashboardsEnabled,
|
PublicDashboardsEnabled: hs.Cfg.PublicDashboardsEnabled,
|
||||||
SharedWithMeFolderUID: folder.SharedWithMeFolderUID,
|
SharedWithMeFolderUID: folder.SharedWithMeFolderUID,
|
||||||
|
RootFolderUID: accesscontrol.GeneralFolderUID,
|
||||||
|
|
||||||
BuildInfo: dtos.FrontendSettingsBuildInfoDTO{
|
BuildInfo: dtos.FrontendSettingsBuildInfoDTO{
|
||||||
HideVersion: hideVersion,
|
HideVersion: hideVersion,
|
||||||
|
|||||||
@@ -179,6 +179,10 @@ func (s *Service) Get(ctx context.Context, q *folder.GetFolderQuery) (*folder.Fo
|
|||||||
return nil, folder.ErrBadRequest.Errorf("missing signed in user")
|
return nil, folder.ErrBadRequest.Errorf("missing signed in user")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if q.UID != nil && *q.UID == accesscontrol.GeneralFolderUID {
|
||||||
|
return folder.RootFolder, nil
|
||||||
|
}
|
||||||
|
|
||||||
if s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) && q.UID != nil && *q.UID == folder.SharedWithMeFolderUID {
|
if s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) && q.UID != nil && *q.UID == folder.SharedWithMeFolderUID {
|
||||||
return folder.SharedWithMeFolder.WithURL(), nil
|
return folder.SharedWithMeFolder.WithURL(), nil
|
||||||
}
|
}
|
||||||
@@ -478,7 +482,7 @@ func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetParents(ctx context.Context, q folder.GetParentsQuery) ([]*folder.Folder, error) {
|
func (s *Service) GetParents(ctx context.Context, q folder.GetParentsQuery) ([]*folder.Folder, error) {
|
||||||
if !s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) {
|
if !s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) || q.UID == accesscontrol.GeneralFolderUID {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if q.UID == folder.SharedWithMeFolderUID {
|
if q.UID == folder.SharedWithMeFolderUID {
|
||||||
|
|||||||
@@ -299,6 +299,17 @@ func TestIntegrationFolderService(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("When get folder by uid and uid is general should return the root folder object", func(t *testing.T) {
|
||||||
|
uid := accesscontrol.GeneralFolderUID
|
||||||
|
query := &folder.GetFolderQuery{
|
||||||
|
UID: &uid,
|
||||||
|
SignedInUser: usr,
|
||||||
|
}
|
||||||
|
actual, err := service.Get(context.Background(), query)
|
||||||
|
require.Equal(t, folder.RootFolder, actual)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("When get folder by title should return folder", func(t *testing.T) {
|
t.Run("When get folder by title should return folder", func(t *testing.T) {
|
||||||
expected := folder.NewFolder("TEST-"+util.GenerateShortUID(), "")
|
expected := folder.NewFolder("TEST-"+util.GenerateShortUID(), "")
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ type Folder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var GeneralFolder = Folder{ID: 0, Title: "General"}
|
var GeneralFolder = Folder{ID: 0, Title: "General"}
|
||||||
|
var RootFolder = &Folder{ID: 0, Title: "Root", UID: GeneralFolderUID, ParentUID: ""}
|
||||||
var SharedWithMeFolder = Folder{
|
var SharedWithMeFolder = Folder{
|
||||||
Title: "Shared with me",
|
Title: "Shared with me",
|
||||||
Description: "Dashboards and folders shared with me",
|
Description: "Dashboards and folders shared with me",
|
||||||
|
|||||||
Reference in New Issue
Block a user