RBAC: Remove dashboard and folder guardians (#104646)
* replace usage of folder guardians with access control evaluators * remove NewByFolderUID guardian * bring up to date * fix test * more test fixes, and don't fetch the folder before evaluating lib element access * change what error is returned * fix alerting test * try to fix linter errors * replace the use of newByFolder guardian with direct access control evaluator checks * remove newByFolder guardian * get rid of dashboard and folder guardians * undo unwanted change * undo unwanted change * undo unwanted change * update code owners
This commit is contained in:
@@ -704,7 +704,6 @@ playwright.config.ts @grafana/plugins-platform-frontend
|
||||
/pkg/services/signingkeys/ @grafana/identity-squad
|
||||
/pkg/services/dashboards/accesscontrol.go @grafana/access-squad
|
||||
/pkg/services/datasources/guardian/ @grafana/access-squad
|
||||
/pkg/services/guardian/ @grafana/access-squad
|
||||
/pkg/services/ldap/ @grafana/identity-squad
|
||||
/pkg/services/login/ @grafana/identity-squad
|
||||
/pkg/services/loginattempt/ @grafana/identity-squad
|
||||
|
||||
@@ -46,7 +46,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
libraryelementsfake "github.com/grafana/grafana/pkg/services/libraryelements/fake"
|
||||
"github.com/grafana/grafana/pkg/services/librarypanels"
|
||||
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
||||
@@ -161,8 +160,6 @@ func TestHTTPServer_GetDashboard_AccessControl(t *testing.T) {
|
||||
hs.AccessControl = acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
|
||||
hs.starService = startest.NewStarServiceFake()
|
||||
hs.dashboardProvisioningService = mockDashboardProvisioningService{}
|
||||
|
||||
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService, hs.folderService, log.NewNopLogger())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -287,8 +284,6 @@ func TestHTTPServer_DeleteDashboardByUID_AccessControl(t *testing.T) {
|
||||
license := licensingtest.NewFakeLicensing()
|
||||
license.On("FeatureEnabled", publicdashboardModels.FeaturePublicDashboardsEmailSharing).Return(false)
|
||||
hs.PublicDashboardsApi = api.ProvideApi(nil, nil, hs.AccessControl, featuremgmt.WithFeatures(), middleware, hs.Cfg, license)
|
||||
|
||||
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService, hs.folderService, log.NewNopLogger())
|
||||
})
|
||||
}
|
||||
deleteDashboard := func(server *webtest.Server, permissions []accesscontrol.Permission) (*http.Response, error) {
|
||||
|
||||
@@ -39,7 +39,6 @@ import (
|
||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
@@ -504,7 +503,6 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
|
||||
}
|
||||
|
||||
hs.AccessControl = acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
|
||||
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService, hs.folderService, log.NewNopLogger())
|
||||
|
||||
m.Get("/api/folders", hs.GetFolders)
|
||||
m.Get("/api/search", hs.Search)
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
"github.com/grafana/grafana/pkg/services/grpcserver"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
ldapapi "github.com/grafana/grafana/pkg/services/ldap/api"
|
||||
"github.com/grafana/grafana/pkg/services/live"
|
||||
"github.com/grafana/grafana/pkg/services/live/pushhttp"
|
||||
@@ -73,7 +72,7 @@ func ProvideBackgroundServiceRegistry(
|
||||
dashboardServiceImpl *service.DashboardServiceImpl,
|
||||
// Need to make sure these are initialized, is there a better place to put them?
|
||||
_ dashboardsnapshots.Service,
|
||||
_ serviceaccounts.Service, _ *guardian.Provider,
|
||||
_ serviceaccounts.Service,
|
||||
_ *sanitizer.Provider,
|
||||
_ *grpcserver.HealthService, _ *grpcserver.ReflectionService,
|
||||
_ *ldapapi.Service, _ *apiregistry.Service, _ auth.IDService, _ *teamapi.TeamAPI, _ ssosettings.Service,
|
||||
|
||||
@@ -86,7 +86,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/grpcserver"
|
||||
grpccontext "github.com/grafana/grafana/pkg/services/grpcserver/context"
|
||||
"github.com/grafana/grafana/pkg/services/grpcserver/interceptors"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
ldapapi "github.com/grafana/grafana/pkg/services/ldap/api"
|
||||
ldapservice "github.com/grafana/grafana/pkg/services/ldap/service"
|
||||
@@ -338,7 +337,6 @@ var wireBasicSet = wire.NewSet(
|
||||
plugindashboardsservice.ProvideService,
|
||||
wire.Bind(new(plugindashboards.Service), new(*plugindashboardsservice.Service)),
|
||||
plugindashboardsservice.ProvideDashboardUpdater,
|
||||
guardian.ProvideService,
|
||||
sanitizer.ProvideService,
|
||||
secretsStore.ProvideService,
|
||||
avatar.ProvideAvatarCacheServer,
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
alertingStore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/search/sort"
|
||||
@@ -242,12 +241,6 @@ func TestIntegrationAnnotationListingWithInheritedRBAC(t *testing.T) {
|
||||
dashStore, err := database.ProvideDashboardStore(sql, cfg, features, tagService)
|
||||
require.NoError(t, err)
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
ac := actest.FakeAccessControl{ExpectedEvaluate: true}
|
||||
fStore := folderimpl.ProvideStore(sql)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sql)
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
@@ -299,12 +298,6 @@ func TestIntegrationDashboardInheritedFolderRBAC(t *testing.T) {
|
||||
}
|
||||
require.NotEqual(t, viewer.UserID, admin.UserID)
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
folderStore := folderimpl.ProvideStore(sqlStore)
|
||||
folderSvc := folderimpl.ProvideService(
|
||||
folderStore, mock.New(), bus.ProvideBus(tracer), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(sqlStore),
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/search/sort"
|
||||
@@ -863,17 +862,6 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanViewValue: true,
|
||||
// CanEditValue is required to create library elements
|
||||
CanEditValue: true,
|
||||
})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
f0, err := folderServiceWithFlagOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
Title: "f0",
|
||||
@@ -983,17 +971,6 @@ func TestIntegrationFindDashboardsByFolder(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanViewValue: true,
|
||||
// CanEditValue is required to create library elements
|
||||
CanEditValue: true,
|
||||
})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
f0, err := folderServiceWithFlagOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
Title: "f0",
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
package guardian
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var _ DashboardGuardian = new(accessControlDashboardGuardian)
|
||||
|
||||
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboardId.
|
||||
func NewAccessControlDashboardGuardian(
|
||||
ctx context.Context, cfg *setting.Cfg, dashboardId int64, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
foldersService folder.Service, logger log.Logger,
|
||||
) (DashboardGuardian, error) {
|
||||
var dashboard *dashboards.Dashboard
|
||||
if dashboardId != 0 {
|
||||
q := &dashboards.GetDashboardQuery{
|
||||
ID: dashboardId,
|
||||
OrgID: user.GetOrgID(),
|
||||
}
|
||||
|
||||
qResult, err := dashboardService.GetDashboard(ctx, q)
|
||||
if err != nil {
|
||||
if errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return nil, ErrGuardianDashboardNotFound.Errorf("failed to get dashboard by UID: %w", err)
|
||||
}
|
||||
return nil, ErrGuardianGetDashboardFailure.Errorf("failed to get dashboard by UID: %w", err)
|
||||
}
|
||||
dashboard = qResult
|
||||
}
|
||||
|
||||
if dashboard != nil && dashboard.IsFolder {
|
||||
logger.Info("using dashboard guardian for folder", "folder", dashboard.UID)
|
||||
return &accessControlFolderGuardian{
|
||||
accessControlBaseGuardian: accessControlBaseGuardian{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
log: log.New("folder.permissions"),
|
||||
user: user,
|
||||
ac: ac,
|
||||
dashboardService: dashboardService,
|
||||
},
|
||||
folder: dashboards.FromDashboard(dashboard),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &accessControlDashboardGuardian{
|
||||
accessControlBaseGuardian: accessControlBaseGuardian{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
log: log.New("dashboard.permissions"),
|
||||
user: user,
|
||||
ac: ac,
|
||||
dashboardService: dashboardService,
|
||||
folderService: foldersService,
|
||||
},
|
||||
dashboard: dashboard,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewAccessControlDashboardGuardianByDashboard creates a dashboard guardian by the provided dashboard.
|
||||
// This constructor should be preferred over the other two if the dashboard is available
|
||||
// since it avoids querying the database for fetching the dashboard.
|
||||
func NewAccessControlDashboardGuardianByDashboard(
|
||||
ctx context.Context, cfg *setting.Cfg, dashboard *dashboards.Dashboard, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, folderService folder.Service,
|
||||
logger log.Logger,
|
||||
) (DashboardGuardian, error) {
|
||||
if dashboard != nil && dashboard.IsFolder {
|
||||
logger.Info("using by dashboard guardian for folder", "folder", dashboard.UID)
|
||||
return &accessControlFolderGuardian{
|
||||
accessControlBaseGuardian: accessControlBaseGuardian{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
log: log.New("folder.permissions"),
|
||||
user: user,
|
||||
ac: ac,
|
||||
dashboardService: dashboardService,
|
||||
folderService: folderService,
|
||||
},
|
||||
folder: dashboards.FromDashboard(dashboard),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &accessControlDashboardGuardian{
|
||||
accessControlBaseGuardian: accessControlBaseGuardian{
|
||||
cfg: cfg,
|
||||
ctx: ctx,
|
||||
log: log.New("dashboard.permissions"),
|
||||
user: user,
|
||||
ac: ac,
|
||||
dashboardService: dashboardService,
|
||||
folderService: folderService,
|
||||
},
|
||||
dashboard: dashboard,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewAccessControlFolderGuardianByUID creates a folder guardian by the provided folderUID.
|
||||
func NewAccessControlFolderGuardianByUID(
|
||||
ctx context.Context, cfg *setting.Cfg, folderUID string, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, foldersService folder.Service,
|
||||
) (DashboardGuardian, error) {
|
||||
if folderUID == "" {
|
||||
return nil, ErrGuardianFolderNotFound.Errorf("failed to get folder by UID: folder UID is empty")
|
||||
}
|
||||
|
||||
q := &folder.GetFolderQuery{
|
||||
UID: &folderUID,
|
||||
OrgID: user.GetOrgID(),
|
||||
SignedInUser: user,
|
||||
}
|
||||
|
||||
f, err := foldersService.Get(ctx, q)
|
||||
if err != nil {
|
||||
if errors.Is(err, dashboards.ErrFolderNotFound) {
|
||||
return nil, ErrGuardianFolderNotFound.Errorf("failed to get folder by UID: %w", err)
|
||||
}
|
||||
return nil, ErrGuardianGetFolderFailure.Errorf("failed to get folder by UID: %w", err)
|
||||
}
|
||||
|
||||
return &accessControlFolderGuardian{
|
||||
accessControlBaseGuardian: accessControlBaseGuardian{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
log: log.New("folder.permissions"),
|
||||
user: user,
|
||||
ac: ac,
|
||||
dashboardService: dashboardService,
|
||||
folderService: foldersService,
|
||||
},
|
||||
folder: f,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewAccessControlFolderGuardian creates a folder guardian by the provided folder.
|
||||
func NewAccessControlFolderGuardian(
|
||||
ctx context.Context, cfg *setting.Cfg, f *folder.Folder, user identity.Requester,
|
||||
ac accesscontrol.AccessControl, orgID int64, dashboardService dashboards.DashboardService,
|
||||
folderService folder.Service,
|
||||
) (DashboardGuardian, error) {
|
||||
if f.UID == "" { // nolint:staticcheck
|
||||
query := &folder.GetFolderQuery{
|
||||
ID: &f.ID, // nolint:staticcheck
|
||||
OrgID: orgID,
|
||||
SignedInUser: user,
|
||||
}
|
||||
|
||||
folder, err := folderService.Get(ctx, query)
|
||||
if err != nil {
|
||||
if errors.Is(err, dashboards.ErrFolderNotFound) {
|
||||
return nil, ErrGuardianFolderNotFound.Errorf("failed to get folder: %w", err)
|
||||
}
|
||||
return nil, ErrGuardianGetFolderFailure.Errorf("failed to get folder: %w", err)
|
||||
}
|
||||
f = folder
|
||||
}
|
||||
|
||||
return &accessControlFolderGuardian{
|
||||
accessControlBaseGuardian: accessControlBaseGuardian{
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
log: log.New("folder.permissions"),
|
||||
user: user,
|
||||
ac: ac,
|
||||
dashboardService: dashboardService,
|
||||
folderService: folderService,
|
||||
},
|
||||
folder: f,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type accessControlBaseGuardian struct {
|
||||
cfg *setting.Cfg
|
||||
ctx context.Context
|
||||
log log.Logger
|
||||
user identity.Requester
|
||||
ac accesscontrol.AccessControl
|
||||
dashboardService dashboards.DashboardService
|
||||
folderService folder.Service
|
||||
}
|
||||
|
||||
type accessControlDashboardGuardian struct {
|
||||
accessControlBaseGuardian
|
||||
dashboard *dashboards.Dashboard
|
||||
}
|
||||
|
||||
type accessControlFolderGuardian struct {
|
||||
accessControlBaseGuardian
|
||||
folder *folder.Folder
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) CanSave() (bool, error) {
|
||||
if a.dashboard == nil {
|
||||
return false, ErrGuardianDashboardNotFound.Errorf("failed to check save permissions for dashboard")
|
||||
}
|
||||
|
||||
return a.evaluate(
|
||||
accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)),
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) CanSave() (bool, error) {
|
||||
if a.folder == nil {
|
||||
return false, ErrGuardianFolderNotFound.Errorf("failed to check save permissions for folder")
|
||||
}
|
||||
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID)))
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) CanEdit() (bool, error) {
|
||||
if a.dashboard == nil {
|
||||
return false, ErrGuardianDashboardNotFound.Errorf("failed to check edit permissions for dashboard")
|
||||
}
|
||||
|
||||
return a.evaluate(
|
||||
accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)),
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) CanEdit() (bool, error) {
|
||||
if a.folder == nil {
|
||||
return false, ErrGuardianFolderNotFound.Errorf("failed to check edit permissions for folder")
|
||||
}
|
||||
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID)))
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) CanView() (bool, error) {
|
||||
if a.dashboard == nil {
|
||||
return false, ErrGuardianDashboardNotFound.Errorf("failed to check view permissions for dashboard")
|
||||
}
|
||||
|
||||
return a.evaluate(
|
||||
accesscontrol.EvalPermission(dashboards.ActionDashboardsRead, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)),
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) CanView() (bool, error) {
|
||||
if a.folder == nil {
|
||||
return false, ErrGuardianFolderNotFound.Errorf("failed to check view permissions for folder")
|
||||
}
|
||||
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersRead, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID)))
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) CanAdmin() (bool, error) {
|
||||
if a.dashboard == nil {
|
||||
return false, ErrGuardianDashboardNotFound.Errorf("failed to check admin permissions for dashboard")
|
||||
}
|
||||
|
||||
return a.evaluate(accesscontrol.EvalAll(
|
||||
accesscontrol.EvalPermission(dashboards.ActionDashboardsPermissionsRead, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)),
|
||||
accesscontrol.EvalPermission(dashboards.ActionDashboardsPermissionsWrite, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)),
|
||||
))
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) CanAdmin() (bool, error) {
|
||||
if a.folder == nil {
|
||||
return false, ErrGuardianFolderNotFound.Errorf("failed to check admin permissions for folder")
|
||||
}
|
||||
|
||||
return a.evaluate(accesscontrol.EvalAll(
|
||||
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsRead, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID)),
|
||||
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID)),
|
||||
))
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) CanDelete() (bool, error) {
|
||||
if a.dashboard == nil {
|
||||
return false, ErrGuardianDashboardNotFound.Errorf("failed to check delete permissions for dashboard")
|
||||
}
|
||||
|
||||
return a.evaluate(
|
||||
accesscontrol.EvalPermission(dashboards.ActionDashboardsDelete, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)),
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) CanDelete() (bool, error) {
|
||||
if a.folder == nil {
|
||||
return false, ErrGuardianFolderNotFound.Errorf("failed to check delete permissions for folder")
|
||||
}
|
||||
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID)))
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) CanCreate(folderID int64, isFolder bool) (bool, error) {
|
||||
if isFolder {
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersCreate))
|
||||
}
|
||||
folder, err := a.loadParentFolder(folderID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionDashboardsCreate, dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.UID)))
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) CanCreate(folderID int64, isFolder bool) (bool, error) {
|
||||
if isFolder {
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersCreate))
|
||||
}
|
||||
folder, err := a.loadParentFolder(folderID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionDashboardsCreate, dashboards.ScopeFoldersProvider.GetResourceScopeUID(folder.UID)))
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
|
||||
if err != nil {
|
||||
id := 0
|
||||
if a.dashboard != nil {
|
||||
id = int(a.dashboard.ID)
|
||||
}
|
||||
a.log.Debug("Failed to evaluate access control to dashboard", "error", err, "identity", a.user.GetID(), "id", id)
|
||||
}
|
||||
|
||||
if !ok && err == nil {
|
||||
id := 0
|
||||
if a.dashboard != nil {
|
||||
id = int(a.dashboard.ID)
|
||||
}
|
||||
a.log.Debug("Access denied to dashboard", "identity", a.user.GetID(), "id", id, "permissions", evaluator.GoString())
|
||||
}
|
||||
|
||||
return ok, err
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) evaluate(evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
ok, err := a.ac.Evaluate(a.ctx, a.user, evaluator)
|
||||
if err != nil {
|
||||
uid := ""
|
||||
orgID := 0
|
||||
if a.folder != nil {
|
||||
uid = a.folder.UID
|
||||
orgID = int(a.folder.OrgID)
|
||||
}
|
||||
a.log.Debug("Failed to evaluate access control to folder", "error", err, "identity", a.user.GetID(), "orgID", orgID, "uid", uid)
|
||||
}
|
||||
|
||||
if !ok && err == nil {
|
||||
uid := ""
|
||||
orgID := 0
|
||||
if a.folder != nil {
|
||||
uid = a.folder.UID
|
||||
orgID = int(a.folder.OrgID)
|
||||
}
|
||||
a.log.Debug("Access denied to folder", "identity", a.user.GetID(), "identity", a.user.GetID(), "orgID", orgID, "uid", uid, "permissions", evaluator.GoString())
|
||||
}
|
||||
|
||||
return ok, err
|
||||
}
|
||||
|
||||
func (a *accessControlDashboardGuardian) loadParentFolder(folderID int64) (*folder.Folder, error) {
|
||||
if folderID == 0 {
|
||||
return &folder.Folder{UID: accesscontrol.GeneralFolderUID, OrgID: a.user.GetOrgID()}, nil
|
||||
}
|
||||
folderQuery := &folder.GetFolderQuery{ID: &folderID, OrgID: a.user.GetOrgID(), SignedInUser: a.user}
|
||||
folderQueryResult, err := a.folderService.Get(a.ctx, folderQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return folderQueryResult, nil
|
||||
}
|
||||
|
||||
func (a *accessControlFolderGuardian) loadParentFolder(folderID int64) (*folder.Folder, error) {
|
||||
if folderID == 0 {
|
||||
return &folder.Folder{UID: accesscontrol.GeneralFolderUID, OrgID: a.user.GetOrgID()}, nil
|
||||
}
|
||||
folderQuery := &folder.GetFolderQuery{ID: &folderID, OrgID: a.user.GetOrgID(), SignedInUser: a.user}
|
||||
folderQueryResult, err := a.folderService.Get(a.ctx, folderQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return folderQueryResult, nil
|
||||
}
|
||||
@@ -1,957 +0,0 @@
|
||||
package guardian
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const (
|
||||
orgID = 1
|
||||
dashUID = "1"
|
||||
folderID = 42
|
||||
folderUID = "42"
|
||||
invalidFolderUID = "142"
|
||||
)
|
||||
|
||||
var (
|
||||
folderUIDScope = fmt.Sprintf("folders:uid:%s", folderUID)
|
||||
invalidFolderUIDScope = fmt.Sprintf("folders:uid:%s", invalidFolderUID)
|
||||
dashboard = &dashboards.Dashboard{OrgID: orgID, UID: dashUID, IsFolder: false, FolderUID: folderUID}
|
||||
fldr = &dashboards.Dashboard{OrgID: orgID, UID: folderUID, IsFolder: true}
|
||||
)
|
||||
|
||||
type accessControlGuardianTestCase struct {
|
||||
desc string
|
||||
dashboard *dashboards.Dashboard
|
||||
permissions []accesscontrol.Permission
|
||||
expected bool
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanSave(t *testing.T) {
|
||||
tests := []accessControlGuardianTestCase{
|
||||
{
|
||||
desc: "should be able to save dashboard with dashboard wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to save dashboard with folder wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to save dashboard with dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to save dashboard under root with general folder scope",
|
||||
dashboard: &dashboards.Dashboard{OrgID: orgID, UID: dashUID, IsFolder: false},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "folders:uid:general",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to save dashboard with incorrect dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to save dashboard with incorrect folder scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to save folder with folder write and dashboard wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to save folder with folder write and folder wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to save folder with folder write and dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to save folder with folder write and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to save folder with folder write and incorrect dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to save folder with folder write and incorrect folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: invalidFolderUID,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian := setupAccessControlGuardianTest(t, tt.dashboard, tt.permissions, nil)
|
||||
can, err := guardian.CanSave()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanEdit(t *testing.T) {
|
||||
tests := []accessControlGuardianTestCase{
|
||||
{
|
||||
desc: "should be able to edit dashboard with dashboard wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to edit dashboard with folder wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to edit dashboard with dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to edit dashboard under root with general folder scope",
|
||||
dashboard: &dashboards.Dashboard{OrgID: orgID, UID: dashUID, IsFolder: false},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "folders:uid:general",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to edit dashboard with incorrect dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to edit dashboard with incorrect folder scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsWrite,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to edit folder with folder write and dashboard wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to edit folder with folder write and folder wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to edit folder with folder write and dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to edit folder with folder write and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to edit folder with folder write and incorrect folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
guardian := setupAccessControlGuardianTest(t, tt.dashboard, tt.permissions, cfg)
|
||||
|
||||
can, err := guardian.CanEdit()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanView(t *testing.T) {
|
||||
tests := []accessControlGuardianTestCase{
|
||||
{
|
||||
desc: "should be able to view dashboard with dashboard wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to view dashboard with folder wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to view dashboard with dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to view dashboard under root with general folder scope",
|
||||
dashboard: &dashboards.Dashboard{OrgID: orgID, UID: dashUID, IsFolder: false},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "folders:uid:general",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to view dashboard with incorrect dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to view dashboard with incorrect folder scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to view folder with folders read and dashboard wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to view folder with folders read and folder wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to folder view with folders read and dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to view folder with folders read and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to view folder with folders read incorrect dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to view folder with folders read and incorrect folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian := setupAccessControlGuardianTest(t, tt.dashboard, tt.permissions, nil)
|
||||
|
||||
can, err := guardian.CanView()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanAdmin(t *testing.T) {
|
||||
tests := []accessControlGuardianTestCase{
|
||||
{
|
||||
desc: "should be able to admin dashboard with dashboard wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsRead,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsWrite,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to admin dashboard with folder wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsRead,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to admin dashboard with dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsRead,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsWrite,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to admin dashboard under root with general folder scope",
|
||||
dashboard: &dashboards.Dashboard{OrgID: orgID, UID: dashUID, IsFolder: false},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsRead,
|
||||
Scope: "folders:uid:general",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsWrite,
|
||||
Scope: "folders:uid:general",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin dashboard with incorrect dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsRead,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsWrite,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin dashboard with incorrect folder scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsRead,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionDashboardsPermissionsWrite,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder read and write and dashboard wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to admin folder with folder read and write and wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder read and wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder write and wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder read and write and dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to admin folder with folder read and write and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder read and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder write and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder read and write and incorrect dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to admin folder with folder read and write and incorrect folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsRead,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
{
|
||||
Action: dashboards.ActionFoldersPermissionsWrite,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian := setupAccessControlGuardianTest(t, tt.dashboard, tt.permissions, nil)
|
||||
|
||||
can, err := guardian.CanAdmin()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanDelete(t *testing.T) {
|
||||
tests := []accessControlGuardianTestCase{
|
||||
{
|
||||
desc: "should be able to delete dashboard with dashboard wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsDelete,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to delete dashboard with folder wildcard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsDelete,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to delete dashboard with dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsDelete,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to delete dashboard under root with general folder scope",
|
||||
dashboard: &dashboards.Dashboard{OrgID: orgID, UID: dashUID, IsFolder: false},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsDelete,
|
||||
Scope: "folders:uid:general",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete dashboard with incorrect dashboard scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsDelete,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete dashboard with incorrect folder scope",
|
||||
dashboard: dashboard,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionDashboardsDelete,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete folder with folder delete and dashboard wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersDelete,
|
||||
Scope: "dashboards:*",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to delete folder with folder deletea and folder wildcard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersDelete,
|
||||
Scope: "folders:*",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete folder with folder delete and dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersDelete,
|
||||
Scope: "dashboards:uid:1",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to delete folder with folder delete and folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersDelete,
|
||||
Scope: folderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete folder with folder delete and incorrect dashboard scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersDelete,
|
||||
Scope: "dashboards:uid:10",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete folder with folder delete and incorrect folder scope",
|
||||
dashboard: fldr,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersDelete,
|
||||
Scope: invalidFolderUIDScope,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian := setupAccessControlGuardianTest(t, tt.dashboard, tt.permissions, nil)
|
||||
|
||||
can, err := guardian.CanDelete()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type accessControlGuardianCanCreateTestCase struct {
|
||||
desc string
|
||||
isFolder bool
|
||||
folderID int64
|
||||
permissions []accesscontrol.Permission
|
||||
expected bool
|
||||
}
|
||||
|
||||
func TestAccessControlDashboardGuardian_CanCreate(t *testing.T) {
|
||||
tests := []accessControlGuardianCanCreateTestCase{
|
||||
{
|
||||
desc: "should be able to create dashboard in general folder",
|
||||
isFolder: false,
|
||||
folderID: 0,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsCreate, Scope: "folders:uid:general"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should be able to create dashboard in any folder",
|
||||
isFolder: false,
|
||||
folderID: 0,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsCreate, Scope: "folders:*"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to create dashboard without permissions",
|
||||
isFolder: false,
|
||||
folderID: 0,
|
||||
permissions: []accesscontrol.Permission{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should be able to create folder with correct permissions",
|
||||
isFolder: true,
|
||||
folderID: 0,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionFoldersCreate},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be able to create folders without permissions",
|
||||
isFolder: true,
|
||||
folderID: 0,
|
||||
permissions: []accesscontrol.Permission{},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
guardian := setupAccessControlGuardianTest(t, &dashboards.Dashboard{OrgID: orgID, UID: "0", IsFolder: tt.isFolder}, tt.permissions, nil)
|
||||
|
||||
can, err := guardian.CanCreate(tt.folderID, tt.isFolder)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, can)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setupAccessControlGuardianTest(
|
||||
t *testing.T, d *dashboards.Dashboard,
|
||||
permissions []accesscontrol.Permission, cfg *setting.Cfg,
|
||||
) DashboardGuardian {
|
||||
t.Helper()
|
||||
|
||||
fakeDashboardService := dashboards.NewFakeDashboardService(t)
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Maybe().Return(d, nil)
|
||||
|
||||
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(fakeDashboardService, folderSvc))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(folderSvc))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, folderSvc))
|
||||
|
||||
license := licensingtest.NewFakeLicensing()
|
||||
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
||||
|
||||
userPermissions := map[int64]map[string][]string{}
|
||||
for _, p := range permissions {
|
||||
if _, ok := userPermissions[orgID]; !ok {
|
||||
userPermissions[orgID] = map[string][]string{}
|
||||
}
|
||||
userPermissions[orgID][p.Action] = append(userPermissions[orgID][p.Action], p.Scope)
|
||||
}
|
||||
|
||||
g, err := NewAccessControlDashboardGuardianByDashboard(context.Background(), cfg, d, &user.SignedInUser{OrgID: orgID, Permissions: userPermissions}, ac, fakeDashboardService, folderSvc, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
return g
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package guardian
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrGuardianGetDashboardFailure = errutil.Internal("guardian.getDashboardFailure", errutil.WithPublicMessage("Failed to get dashboard"))
|
||||
ErrGuardianDashboardNotFound = errutil.NotFound("guardian.dashboardNotFound")
|
||||
ErrGuardianFolderNotFound = errutil.NotFound("guardian.folderNotFound")
|
||||
ErrGuardianGetFolderFailure = errutil.Internal("guardian.getFolderFailure", errutil.WithPublicMessage("Failed to get folder"))
|
||||
)
|
||||
|
||||
// DashboardGuardian to be used for guard against operations without access on dashboard and acl
|
||||
type DashboardGuardian interface {
|
||||
CanSave() (bool, error)
|
||||
CanEdit() (bool, error)
|
||||
CanView() (bool, error)
|
||||
CanAdmin() (bool, error)
|
||||
CanDelete() (bool, error)
|
||||
CanCreate(folderID int64, isFolder bool) (bool, error)
|
||||
}
|
||||
|
||||
// New factory for creating a new dashboard guardian instance
|
||||
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
||||
var New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
panic("no guardian factory implementation provided")
|
||||
}
|
||||
|
||||
// NewByFolder factory for creating a new folder guardian instance
|
||||
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
||||
var NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
panic("no guardian factory implementation provided")
|
||||
}
|
||||
|
||||
// nolint:unused
|
||||
type FakeDashboardGuardian struct {
|
||||
DashID int64
|
||||
DashUID string
|
||||
OrgID int64
|
||||
User identity.Requester
|
||||
CanSaveValue bool
|
||||
CanEditValue bool
|
||||
CanViewValue bool
|
||||
CanAdminValue bool
|
||||
CanViewUIDs []string
|
||||
CanEditUIDs []string
|
||||
CanSaveUIDs []string
|
||||
}
|
||||
|
||||
func (g *FakeDashboardGuardian) CanSave() (bool, error) {
|
||||
if g.CanSaveUIDs != nil {
|
||||
return slices.Contains(g.CanSaveUIDs, g.DashUID), nil
|
||||
}
|
||||
return g.CanSaveValue, nil
|
||||
}
|
||||
|
||||
func (g *FakeDashboardGuardian) CanEdit() (bool, error) {
|
||||
if g.CanEditUIDs != nil {
|
||||
return slices.Contains(g.CanEditUIDs, g.DashUID), nil
|
||||
}
|
||||
return g.CanEditValue, nil
|
||||
}
|
||||
|
||||
func (g *FakeDashboardGuardian) CanView() (bool, error) {
|
||||
if g.CanViewUIDs != nil {
|
||||
return slices.Contains(g.CanViewUIDs, g.DashUID), nil
|
||||
}
|
||||
return g.CanViewValue, nil
|
||||
}
|
||||
|
||||
func (g *FakeDashboardGuardian) CanAdmin() (bool, error) {
|
||||
return g.CanAdminValue, nil
|
||||
}
|
||||
|
||||
func (g *FakeDashboardGuardian) CanDelete() (bool, error) {
|
||||
return g.CanSaveValue, nil
|
||||
}
|
||||
|
||||
func (g *FakeDashboardGuardian) CanCreate(_ int64, _ bool) (bool, error) {
|
||||
return g.CanSaveValue, nil
|
||||
}
|
||||
|
||||
// nolint:unused
|
||||
func MockDashboardGuardian(mock *FakeDashboardGuardian) {
|
||||
New = func(_ context.Context, dashID int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
mock.OrgID = orgId
|
||||
mock.DashID = dashID
|
||||
mock.User = user
|
||||
return mock, nil
|
||||
}
|
||||
|
||||
NewByFolder = func(_ context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
mock.OrgID = orgId
|
||||
mock.DashUID = f.UID
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Guardian).Inc()
|
||||
// nolint:staticcheck
|
||||
mock.DashID = f.ID
|
||||
mock.User = user
|
||||
return mock, nil
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package guardian
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
type Provider struct{}
|
||||
|
||||
func ProvideService(
|
||||
cfg *setting.Cfg, ac accesscontrol.AccessControl,
|
||||
dashboardService dashboards.DashboardService, teamService team.Service,
|
||||
folderService folder.Service,
|
||||
) *Provider {
|
||||
// TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935
|
||||
InitAccessControlGuardian(cfg, ac, dashboardService, folderService, log.New("guardian"))
|
||||
return &Provider{}
|
||||
}
|
||||
|
||||
func InitAccessControlGuardian(
|
||||
cfg *setting.Cfg, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService, folderService folder.Service, logger log.Logger,
|
||||
) {
|
||||
New = func(ctx context.Context, dashId int64, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return NewAccessControlDashboardGuardian(ctx, cfg, dashId, user, ac, dashboardService, folderService, logger)
|
||||
}
|
||||
|
||||
NewByFolder = func(ctx context.Context, f *folder.Folder, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
||||
return NewAccessControlFolderGuardian(ctx, cfg, f, user, ac, orgId, dashboardService, folderService)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/serverlock"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@@ -33,7 +32,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements/model"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@@ -843,7 +841,6 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
kvstore.NewFakeKVStore())
|
||||
require.NoError(t, err)
|
||||
dashService.RegisterDashboardPermissions(dashPermissionService)
|
||||
guardian.InitAccessControlGuardian(cfg, ac, dashService, folderSvc, log.NewNopLogger())
|
||||
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore))
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -35,7 +35,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
ac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/accesscontrol/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
@@ -2021,11 +2020,6 @@ func createTestEnv(t *testing.T, testConfig string) testEnvironment {
|
||||
},
|
||||
*/
|
||||
}
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
parent, err := folderService.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: 1,
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
@@ -44,16 +43,6 @@ func SetupFolderService(tb testing.TB, cfg *setting.Cfg, db db.DB, dashboardStor
|
||||
func SetupDashboardService(tb testing.TB, sqlStore db.DB, fs *folderimpl.DashboardFolderStoreImpl, cfg *setting.Cfg) (*dashboardservice.DashboardServiceImpl, dashboards.Store) {
|
||||
tb.Helper()
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanViewValue: true,
|
||||
CanAdminValue: true,
|
||||
})
|
||||
tb.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
ac := acmock.New()
|
||||
dashboardPermissions := acmock.NewMockedPermissionsService()
|
||||
folderPermissions := acmock.NewMockedPermissionsService()
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/search/sort"
|
||||
@@ -448,11 +447,6 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) {
|
||||
if db.IsTestDBSpanner() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
var orgID int64 = 1
|
||||
|
||||
@@ -563,11 +557,6 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission
|
||||
if db.IsTestDBSpanner() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
var orgID int64 = 1
|
||||
|
||||
@@ -680,12 +669,6 @@ func TestIntegration_DashboardNestedPermissionFilter_WithActionSets(t *testing.T
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
var orgID int64 = 1
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/search/sort"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
@@ -86,12 +85,6 @@ func setupBenchMark(b *testing.B, usr user.SignedInUser, features featuremgmt.Fe
|
||||
fStore, mock.New(), bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(store),
|
||||
nil, store, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest(), nil, dualwrite.ProvideTestService(), sort.ProvideService(), apiserver.WithoutRestConfig)
|
||||
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
|
||||
b.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
rootFolders := make([]*folder.Folder, 0, numFolders)
|
||||
dashes := make([]dashboards.Dashboard, 0, numDashboards)
|
||||
parentUID := ""
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
ngalertstore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/search/sort"
|
||||
@@ -45,13 +44,6 @@ func TestDirectSQLStats(t *testing.T) {
|
||||
|
||||
dashStore, err := database.ProvideDashboardStore(db, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db))
|
||||
require.NoError(t, err)
|
||||
fakeGuardian := &guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanEditUIDs: []string{},
|
||||
CanViewUIDs: []string{},
|
||||
}
|
||||
guardian.MockDashboardGuardian(fakeGuardian)
|
||||
require.NoError(t, err)
|
||||
fStore := folderimpl.ProvideStore(db)
|
||||
folderSvc := folderimpl.ProvideService(
|
||||
fStore, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderimpl.ProvideDashboardFolderStore(db),
|
||||
|
||||
Reference in New Issue
Block a user