Access control: Move call to create default permissions into folder and dashboard service (#46186)
* Move call to create permissions into folder service * Inject cfg, feature toggles and permissions services into dashboard service * Move logic to set default permissions on create dashboard from api to service * Move call to set default permissions on import dashboard to dashboard service * Set permissions for provisioned dashboard and folders in service
This commit is contained in:
@@ -378,7 +378,7 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
|
||||
RouteRegister: routeRegister,
|
||||
SQLStore: store,
|
||||
searchUsersService: searchusers.ProvideUsersService(db, filters.ProvideOSSSearchUserFilter()),
|
||||
dashboardService: dashboardservice.ProvideDashboardService(dashboardsStore, nil),
|
||||
dashboardService: dashboardservice.ProvideDashboardService(cfg, dashboardsStore, nil, features, accesscontrolmock.NewPermissionsServicesMock()),
|
||||
}
|
||||
|
||||
// Defining the accesscontrol service has to be done before registering routes
|
||||
|
||||
@@ -17,10 +17,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@@ -360,12 +358,6 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
|
||||
return apierrors.ToDashboardErrorResponse(ctx, hs.pluginStore, err)
|
||||
}
|
||||
|
||||
if newDashboard {
|
||||
if err := hs.setDashboardPermissions(c, cmd, dashboard); err != nil {
|
||||
hs.log.Error("Could not make user admin", "dashboard", dashboard.Title, "user", c.SignedInUser.UserId, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// connect library panels for this dashboard after the dashboard is stored and has an ID
|
||||
err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(ctx, c.SignedInUser, dashboard)
|
||||
if err != nil {
|
||||
@@ -383,35 +375,6 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
|
||||
})
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) setDashboardPermissions(c *models.ReqContext, cmd models.SaveDashboardCommand, dash *models.Dashboard) error {
|
||||
inFolder := dash.FolderId > 0
|
||||
if hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
|
||||
resourceID := strconv.FormatInt(dash.Id, 10)
|
||||
svc := hs.permissionServices.GetDashboardService()
|
||||
|
||||
permissions := []accesscontrol.SetResourcePermissionCommand{
|
||||
{UserID: c.UserId, Permission: models.PERMISSION_ADMIN.String()},
|
||||
}
|
||||
|
||||
if !inFolder {
|
||||
permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{
|
||||
{BuiltinRole: string(models.ROLE_EDITOR), Permission: models.PERMISSION_EDIT.String()},
|
||||
{BuiltinRole: string(models.ROLE_VIEWER), Permission: models.PERMISSION_VIEW.String()},
|
||||
}...)
|
||||
}
|
||||
_, err := svc.SetPermissions(c.Req.Context(), c.OrgId, resourceID, permissions...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if hs.Cfg.EditorsCanAdmin {
|
||||
if err := hs.dashboardService.MakeUserAdmin(c.Req.Context(), cmd.OrgId, cmd.UserId, dash.Id, !inFolder); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetHomeDashboard returns the home dashboard.
|
||||
func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) response.Response {
|
||||
prefsQuery := models.GetPreferencesWithDefaultsQuery{User: c.SignedInUser}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -26,13 +27,16 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
|
||||
dashboardStore := &database.FakeDashboardStore{}
|
||||
defer dashboardStore.AssertExpectations(t)
|
||||
|
||||
features := featuremgmt.WithFeatures()
|
||||
mockSQLStore := mockstore.NewSQLStoreMock()
|
||||
|
||||
hs := &HTTPServer{
|
||||
Cfg: settings,
|
||||
dashboardService: dashboardservice.ProvideDashboardService(dashboardStore, nil),
|
||||
SQLStore: mockSQLStore,
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
Cfg: settings,
|
||||
SQLStore: mockSQLStore,
|
||||
Features: features,
|
||||
dashboardService: dashboardservice.ProvideDashboardService(
|
||||
settings, dashboardStore, nil, features, accesscontrolmock.NewPermissionsServicesMock(),
|
||||
),
|
||||
}
|
||||
|
||||
t.Run("Given user has no admin permissions", func(t *testing.T) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
@@ -214,14 +215,18 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
mockSQLStore := mockstore.NewSQLStoreMock()
|
||||
mockSQLStore.ExpectedDashboard = fakeDash
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
features := featuremgmt.WithFeatures()
|
||||
dashboardStore := database.ProvideDashboardStore(sqlstore.InitTestDB(t))
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
Cfg: cfg,
|
||||
Live: newTestLive(t),
|
||||
LibraryPanelService: &mockLibraryPanelService{},
|
||||
LibraryElementService: &mockLibraryElementService{},
|
||||
dashboardService: service.ProvideDashboardService(dashboardStore, nil),
|
||||
SQLStore: mockSQLStore,
|
||||
dashboardService: service.ProvideDashboardService(
|
||||
cfg, dashboardStore, nil, features, accesscontrolmock.NewPermissionsServicesMock(),
|
||||
),
|
||||
}
|
||||
hs.SQLStore = mockSQLStore
|
||||
|
||||
@@ -934,14 +939,18 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
||||
|
||||
libraryPanelsService := mockLibraryPanelService{}
|
||||
libraryElementsService := mockLibraryElementService{}
|
||||
cfg := setting.NewCfg()
|
||||
features := featuremgmt.WithFeatures()
|
||||
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
LibraryPanelService: &libraryPanelsService,
|
||||
LibraryElementService: &libraryElementsService,
|
||||
ProvisioningService: provisioningService,
|
||||
dashboardProvisioningService: service.ProvideDashboardService(dashboardStore, nil),
|
||||
SQLStore: sc.sqlStore,
|
||||
Cfg: cfg,
|
||||
LibraryPanelService: &libraryPanelsService,
|
||||
LibraryElementService: &libraryElementsService,
|
||||
SQLStore: sc.sqlStore,
|
||||
ProvisioningService: provisioningService,
|
||||
dashboardProvisioningService: service.ProvideDashboardService(
|
||||
cfg, dashboardStore, nil, features, accesscontrolmock.NewPermissionsServicesMock(),
|
||||
),
|
||||
}
|
||||
|
||||
hs.callGetDashboard(sc)
|
||||
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -73,36 +71,10 @@ func (hs *HTTPServer) CreateFolder(c *models.ReqContext) response.Response {
|
||||
return apierrors.ToFolderErrorResponse(err)
|
||||
}
|
||||
|
||||
if err := hs.setFolderPermission(c, folder.Id); err != nil {
|
||||
hs.log.Error("Could not make user admin", "folder", folder.Title, "user",
|
||||
c.SignedInUser.UserId, "error", err)
|
||||
}
|
||||
|
||||
g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
|
||||
return response.JSON(200, hs.toFolderDto(c.Req.Context(), g, folder))
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) setFolderPermission(c *models.ReqContext, folderID int64) error {
|
||||
if hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
|
||||
resourceID := strconv.FormatInt(folderID, 10)
|
||||
svc := hs.permissionServices.GetFolderService()
|
||||
|
||||
_, err := svc.SetPermissions(c.Req.Context(), c.OrgId, resourceID, []accesscontrol.SetResourcePermissionCommand{
|
||||
{UserID: c.UserId, Permission: models.PERMISSION_ADMIN.String()},
|
||||
{BuiltinRole: string(models.ROLE_EDITOR), Permission: models.PERMISSION_EDIT.String()},
|
||||
{BuiltinRole: string(models.ROLE_VIEWER), Permission: models.PERMISSION_VIEW.String()},
|
||||
}...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if hs.Cfg.EditorsCanAdmin {
|
||||
if err := hs.folderService.MakeUserAdmin(c.Req.Context(), c.OrgId, c.UserId, folderID, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) UpdateFolder(c *models.ReqContext) response.Response {
|
||||
cmd := models.UpdateFolderCommand{}
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -32,7 +34,18 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
|
||||
dashboardStore := &database.FakeDashboardStore{}
|
||||
defer dashboardStore.AssertExpectations(t)
|
||||
|
||||
hs := &HTTPServer{Cfg: settings, folderService: folderService, dashboardService: service.ProvideDashboardService(dashboardStore, nil), Features: featuremgmt.WithFeatures()}
|
||||
features := featuremgmt.WithFeatures()
|
||||
permissionsServices := accesscontrolmock.NewPermissionsServicesMock()
|
||||
|
||||
hs := &HTTPServer{
|
||||
Cfg: settings,
|
||||
Features: features,
|
||||
folderService: folderService,
|
||||
permissionServices: permissionsServices,
|
||||
dashboardService: service.ProvideDashboardService(
|
||||
settings, dashboardStore, nil, features, permissionsServices,
|
||||
),
|
||||
}
|
||||
|
||||
t.Run("Given folder not exists", func(t *testing.T) {
|
||||
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, models.ErrFolderNotFound).Twice()
|
||||
|
||||
Reference in New Issue
Block a user