mirror of
https://github.com/grafana/grafana.git
synced 2024-12-01 13:09:22 -06:00
1208888bb6
* Folders: Allow listing folders with write permission * Check for subfolder access if parent does not have * Add test * GetFolders: fix ordering * Apply suggestion from code review
136 lines
4.5 KiB
Go
136 lines
4.5 KiB
Go
package guardian
|
|
|
|
import (
|
|
"context"
|
|
"slices"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
|
"github.com/grafana/grafana/pkg/services/auth/identity"
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/folder"
|
|
"github.com/grafana/grafana/pkg/util/errutil"
|
|
)
|
|
|
|
var (
|
|
ErrGuardianGetDashboardFailure = errutil.Internal("guardian.getDashboardFailure", errutil.WithPublicMessage("Failed to get dashboard"))
|
|
ErrGuardianDashboardNotFound = errutil.NotFound("guardian.dashboardNotFound")
|
|
ErrGuardianFolderNotFound = errutil.NotFound("guardian.folderNotFound")
|
|
)
|
|
|
|
// 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")
|
|
}
|
|
|
|
// NewByUID factory for creating a new dashboard guardian instance
|
|
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
|
var NewByUID = func(ctx context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
|
panic("no guardian factory implementation provided")
|
|
}
|
|
|
|
// NewByDashboard factory for creating a new dashboard guardian instance
|
|
// When using access control this function is replaced on startup and the AccessControlDashboardGuardian is returned
|
|
var NewByDashboard = func(ctx context.Context, dash *dashboards.Dashboard, 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
|
|
}
|
|
|
|
NewByUID = func(_ context.Context, dashUID string, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
|
mock.OrgID = orgId
|
|
mock.DashUID = dashUID
|
|
mock.User = user
|
|
return mock, nil
|
|
}
|
|
|
|
NewByDashboard = func(_ context.Context, dash *dashboards.Dashboard, orgId int64, user identity.Requester) (DashboardGuardian, error) {
|
|
mock.OrgID = orgId
|
|
mock.DashUID = dash.UID
|
|
mock.DashID = dash.ID
|
|
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
|
|
}
|
|
}
|