Guardian: Introduce additional constructors (#59577)

* Guardian: Use dashboard UID instead of ID

* Apply suggestions from code review

Introduce several guardian constructors and each time use
the most appropriate one.
This commit is contained in:
Sofia Papagiannaki
2022-12-15 16:34:17 +02:00
committed by GitHub
parent 6478d0a5ef
commit 11d8bcbea9
30 changed files with 678 additions and 193 deletions

View File

@@ -693,7 +693,10 @@ func (hs *HTTPServer) PauseAlert(legacyAlertingEnabled *bool) func(c *models.Req
return response.Error(500, "Get Alert failed", err)
}
guardian := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgID, c.SignedInUser)
guardian, err := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgID, c.SignedInUser)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "Error while creating permission guardian", err)
}
if canEdit, err := guardian.CanEdit(); err != nil || !canEdit {
if err != nil {
return response.Error(500, "Error while checking permissions for Alert", err)

View File

@@ -504,7 +504,11 @@ func (hs *HTTPServer) canSaveAnnotation(c *models.ReqContext, annotation *annota
}
func canEditDashboard(c *models.ReqContext, dashboardID int64) (bool, error) {
guard := guardian.New(c.Req.Context(), dashboardID, c.OrgID, c.SignedInUser)
guard, err := guardian.New(c.Req.Context(), dashboardID, c.OrgID, c.SignedInUser)
if err != nil {
return false, err
}
if canEdit, err := guard.CanEdit(); err != nil || !canEdit {
return false, err
}
@@ -606,6 +610,7 @@ func (hs *HTTPServer) canCreateAnnotation(c *models.ReqContext, dashboardId int6
return canSave, err
}
}
return canEditDashboard(c, dashboardId)
} else { // organization annotations
if !hs.AccessControl.IsDisabled() {

View File

@@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
@@ -24,6 +25,7 @@ import (
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/team/teamtest"
"github.com/grafana/grafana/pkg/services/user"
)
func TestAnnotationsAPIEndpoint(t *testing.T) {
@@ -154,8 +156,9 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Viewer", func(t *testing.T) {
role := org.RoleViewer
dashSvc := dashboards.NewFakeDashboardService(t)
t.Run("Should not be allowed to save an annotation", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, dashSvc, func(sc *scenarioContext) {
setUpACL()
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
@@ -186,7 +189,8 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Editor", func(t *testing.T) {
role := org.RoleEditor
t.Run("Should be able to save an annotation", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) {
dashSvc := dashboards.NewFakeDashboardService(t)
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, dashSvc, func(sc *scenarioContext) {
setUpACL()
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
@@ -220,12 +224,6 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
mockStore := mockstore.NewSQLStoreMock()
t.Run("Should be able to do anything", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) {
setUpACL()
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
@@ -234,6 +232,12 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
Uid: q.Uid,
}
}).Return(nil)
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, dashSvc, func(sc *scenarioContext) {
setUpACL()
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, dashboardUIDCmd, mockStore, dashSvc, func(sc *scenarioContext) {
setUpACL()
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
@@ -387,7 +391,31 @@ func TestAPI_Annotations_AccessControl(t *testing.T) {
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
require.NoError(t, err)
dashboardAnnotation := &annotations.Item{Id: 1, DashboardId: 1}
origNewGuardian := guardian.New
t.Cleanup(func() {
guardian.New = origNewGuardian
})
// Create a dashboard
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
sc.dashboardPermissionsService.On("SetPermissions", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string"), mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
cmd := &dashboards.SaveDashboardDTO{
OrgId: testOrgID,
User: &user.SignedInUser{UserID: testUserID, OrgID: testOrgID},
Dashboard: &models.Dashboard{
OrgId: testOrgID,
Title: "1 test dash",
Data: simplejson.NewFromAny(map[string]interface{}{}),
}}
dashboard, err := sc.hs.DashboardService.SaveDashboard(context.Background(), cmd, false)
require.NoError(t, err)
require.NotNil(t, dashboard)
t.Cleanup(func() {
err := sc.hs.DashboardService.DeleteDashboard(context.Background(), dashboard.Id, dashboard.OrgId)
require.NoError(t, err)
})
dashboardAnnotation := &annotations.Item{Id: 1, DashboardId: dashboard.Id}
organizationAnnotation := &annotations.Item{Id: 2, DashboardId: 0}
_ = sc.hs.annotationsRepo.Save(context.Background(), dashboardAnnotation)
@@ -796,6 +824,30 @@ func TestAPI_MassDeleteAnnotations_AccessControl(t *testing.T) {
method string
}
origNewGuardian := guardian.New
t.Cleanup(func() {
guardian.New = origNewGuardian
})
// Create a dashboard
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
sc.dashboardPermissionsService.On("SetPermissions", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string"), mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
cmd := &dashboards.SaveDashboardDTO{
OrgId: testOrgID,
User: &user.SignedInUser{UserID: testUserID, OrgID: testOrgID},
Dashboard: &models.Dashboard{
OrgId: testOrgID,
Title: "1 test dash",
Data: simplejson.NewFromAny(map[string]interface{}{}),
}}
dashboard, err := sc.hs.DashboardService.SaveDashboard(context.Background(), cmd, false)
require.NoError(t, err)
require.NotNil(t, dashboard)
t.Cleanup(func() {
err := sc.hs.DashboardService.DeleteDashboard(context.Background(), dashboard.Id, dashboard.OrgId)
require.NoError(t, err)
})
tests := []struct {
name string
args args
@@ -834,7 +886,7 @@ func TestAPI_MassDeleteAnnotations_AccessControl(t *testing.T) {
url: "/api/annotations/mass-delete",
method: http.MethodPost,
body: mockRequestBody(dtos.MassDeleteAnnotationsCmd{
DashboardId: 1,
DashboardId: dashboard.Id,
PanelId: 1,
}),
},
@@ -932,6 +984,13 @@ func setUpACL() {
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
}
}).Return(nil)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
q.Result = &models.Dashboard{
Id: q.Id,
Uid: q.Uid,
}
}).Return(nil)
guardian.InitLegacyGuardian(store, dashSvc, teamSvc)
}

View File

@@ -305,9 +305,11 @@ type accessControlScenarioContext struct {
// cfg is the setting provider
cfg *setting.Cfg
dashboardsStore dashboards.Store
teamService team.Service
userService user.Service
dashboardsStore dashboards.Store
teamService team.Service
userService user.Service
folderPermissionsService *accesscontrolmock.MockPermissionsService
dashboardPermissionsService *accesscontrolmock.MockPermissionsService
}
func setAccessControlPermissions(acmock *accesscontrolmock.Mock, perms []accesscontrol.Permission, org int64) {
@@ -417,6 +419,9 @@ func setupHTTPServerWithCfgDb(
teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, license, acService, teamService, userSvc)
require.NoError(t, err)
folderPermissionsService := accesscontrolmock.NewMockedPermissionsService()
dashboardPermissionsService := accesscontrolmock.NewMockedPermissionsService()
// Create minimal HTTP Server
hs := &HTTPServer{
Cfg: cfg,
@@ -432,7 +437,7 @@ func setupHTTPServerWithCfgDb(
searchUsersService: searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), usertest.NewUserServiceFake()),
DashboardService: dashboardservice.ProvideDashboardService(
cfg, dashboardsStore, nil, features,
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), ac,
folderPermissionsService, dashboardPermissionsService, ac,
),
preferenceService: preftest.NewPreferenceServiceFake(),
userService: userSvc,
@@ -469,15 +474,17 @@ func setupHTTPServerWithCfgDb(
hs.RouteRegister.Register(m.Router)
return accessControlScenarioContext{
server: m,
initCtx: initCtx,
hs: hs,
acmock: acmock,
db: db,
cfg: cfg,
dashboardsStore: dashboardsStore,
teamService: teamService,
userService: userSvc,
server: m,
initCtx: initCtx,
hs: hs,
acmock: acmock,
db: db,
cfg: cfg,
dashboardsStore: dashboardsStore,
teamService: teamService,
userService: userSvc,
dashboardPermissionsService: dashboardPermissionsService,
folderPermissionsService: folderPermissionsService,
}
}

View File

@@ -133,7 +133,11 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
return response.Error(500, "Error while loading dashboard, dashboard data is invalid", nil)
}
}
guardian := guardian.New(c.Req.Context(), dash.Id, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canView, err := guardian.CanView(); err != nil || !canView {
return dashboardGuardianResponse(err)
}
@@ -308,13 +312,17 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response {
if rsp != nil {
return rsp
}
guardian := guardian.New(c.Req.Context(), dash.Id, c.OrgID, c.SignedInUser)
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canDelete, err := guardian.CanDelete(); err != nil || !canDelete {
return dashboardGuardianResponse(err)
}
// disconnect all library elements for this dashboard
err := hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.Id)
err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.Id)
if err != nil {
hs.log.Error("Failed to disconnect library elements", "dashboard", dash.Id, "user", c.SignedInUser.UserID, "error", err)
}
@@ -630,32 +638,32 @@ func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Respon
if err != nil {
return response.Error(http.StatusBadRequest, "dashboardId is invalid", err)
}
} else {
q := models.GetDashboardQuery{
OrgId: c.SignedInUser.OrgID,
Uid: dashUID,
}
if err := hs.DashboardService.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
}
dashID = q.Result.Id
}
guardian := guardian.New(c.Req.Context(), dashID, c.OrgID, c.SignedInUser)
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
if rsp != nil {
return rsp
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
query := dashver.ListDashboardVersionsQuery{
OrgID: c.OrgID,
DashboardID: dashID,
DashboardUID: dashUID,
DashboardID: dash.Id,
DashboardUID: dash.Uid,
Limit: c.QueryInt("limit"),
Start: c.QueryInt("start"),
}
res, err := hs.dashboardVersionService.List(c.Req.Context(), &query)
if err != nil {
return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dashID), err)
return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dash.Id), err)
}
for _, version := range res {
@@ -708,23 +716,24 @@ func (hs *HTTPServer) GetDashboardVersion(c *models.ReqContext) response.Respons
var err error
dashUID := web.Params(c.Req)[":uid"]
var dash *models.Dashboard
if dashUID == "" {
dashID, err = strconv.ParseInt(web.Params(c.Req)[":dashboardId"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "dashboardId is invalid", err)
}
} else {
q := models.GetDashboardQuery{
OrgId: c.SignedInUser.OrgID,
Uid: dashUID,
}
if err := hs.DashboardService.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
}
dashID = q.Result.Id
}
guardian := guardian.New(c.Req.Context(), dashID, c.OrgID, c.SignedInUser)
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.OrgID, dashID, dashUID)
if rsp != nil {
return rsp
}
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@@ -732,13 +741,13 @@ func (hs *HTTPServer) GetDashboardVersion(c *models.ReqContext) response.Respons
version, _ := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 32)
query := dashver.GetDashboardVersionQuery{
OrgID: c.OrgID,
DashboardID: dashID,
DashboardID: dash.Id,
Version: int(version),
}
res, err := hs.dashboardVersionService.Get(c.Req.Context(), &query)
if err != nil {
return response.Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashID), err)
return response.Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dash.Id), err)
}
creator := anonString
@@ -843,13 +852,21 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *models.ReqContext) response.Resp
if err := web.Bind(c.Req, &apiOptions); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
guardianBase := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgID, c.SignedInUser)
guardianBase, err := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canSave, err := guardianBase.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
if apiOptions.Base.DashboardId != apiOptions.New.DashboardId {
guardianNew := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.OrgID, c.SignedInUser)
guardianNew, err := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canSave, err := guardianNew.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@@ -964,11 +981,11 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext) response.Res
return rsp
}
if dash != nil && dash.Id != 0 {
dashID = dash.Id
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
guardian := guardian.New(c.Req.Context(), dashID, c.OrgID, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}

View File

@@ -56,12 +56,11 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.
return rsp
}
if dashID == 0 {
dashID = dash.Id
g, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
g := guardian.New(c.Req.Context(), dashID, c.OrgID, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return dashboardGuardianResponse(err)
}
@@ -147,11 +146,11 @@ func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext) response.
return rsp
}
if dashUID != "" {
dashID = dash.Id
g, err := guardian.NewByDashboard(c.Req.Context(), dash, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
g := guardian.New(c.Req.Context(), dashID, c.OrgID, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return dashboardGuardianResponse(err)
}

View File

@@ -27,7 +27,13 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
t.Run("Dashboard permissions test", func(t *testing.T) {
settings := setting.NewCfg()
dashboardStore := &dashboards.FakeDashboardStore{}
dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(nil, nil)
dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
q.Result = &models.Dashboard{
Id: q.Id,
Uid: q.Uid,
}
}).Return(nil, nil)
defer dashboardStore.AssertExpectations(t)
features := featuremgmt.WithFeatures()

View File

@@ -342,7 +342,11 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *models.ReqContext) response.Res
dashboardID := query.Result.Dashboard.Get("id").MustInt64()
if dashboardID != 0 {
guardian := guardian.New(c.Req.Context(), dashboardID, c.OrgID, c.SignedInUser)
guardian, err := guardian.New(c.Req.Context(), dashboardID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
canEdit, err := guardian.CanEdit()
// check for permissions only if the dashboard is found
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {

View File

@@ -73,7 +73,15 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
teamSvc := &teamtest.FakeService{}
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
q.Result = &models.Dashboard{
Id: q.Id,
Uid: q.Uid,
}
}).Return(nil).Maybe()
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Return(nil).Maybe()
hs.DashboardService = dashSvc
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
@@ -121,13 +129,28 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE",
"/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
var externalRequest *http.Request
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(200)
externalRequest = req
})
hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, ts.URL)}
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
q.Result = &models.Dashboard{
Id: q.Id,
OrgId: q.OrgId,
}
}).Return(nil).Maybe()
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardACLInfoListQuery)
q.Result = []*models.DashboardACLInfoDTO{
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
}
}).Return(nil)
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc)
hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, ts.URL), DashboardService: dashSvc}
sc.handlerFunc = hs.DeleteDashboardSnapshot
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
@@ -146,8 +169,9 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t, testUserID, "")
hs := &HTTPServer{dashboardsnapshotsService: d}
dashSvc := dashboards.NewFakeDashboardService(t)
hs := &HTTPServer{dashboardsnapshotsService: d, DashboardService: dashSvc}
sc.handlerFunc = hs.DeleteDashboardSnapshot
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
@@ -169,7 +193,9 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
rw.WriteHeader(500)
_, writeErr = rw.Write([]byte(`{"message":"Failed to get dashboard snapshot"}`))
})
hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, testUserID, ts.URL)}
dashSvc := dashboards.NewFakeDashboardService(t)
hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, testUserID, ts.URL), DashboardService: dashSvc}
sc.handlerFunc = hs.DeleteDashboardSnapshot
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()

View File

@@ -808,6 +808,13 @@ func TestDashboardAPIEndpoint(t *testing.T) {
teamSvc := &teamtest.FakeService{}
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Return(nil)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
q.Result = &models.Dashboard{
OrgId: q.OrgId,
Id: q.Id,
}
}).Return(nil)
guardian.InitLegacyGuardian(&sqlmock, dashSvc, teamSvc)
}
@@ -1152,6 +1159,8 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
role org.RoleType, fn scenarioFunc, sqlmock db.DB, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
cfg := setting.NewCfg()
dashSvc := dashboards.NewFakeDashboardService(t)
hs := HTTPServer{
Cfg: cfg,
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
@@ -1163,6 +1172,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
dashboardVersionService: fakeDashboardVersionService,
Features: featuremgmt.WithFeatures(),
Kinds: corekind.NewBase(nil),
DashboardService: dashSvc,
}
sc := setupScenarioContext(t, url)

View File

@@ -73,7 +73,11 @@ func (hs *HTTPServer) GetFolderByUID(c *models.ReqContext) response.Response {
return apierrors.ToFolderErrorResponse(err)
}
g := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
g, err := guardian.NewByUID(c.Req.Context(), folder.UID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
return response.JSON(http.StatusOK, hs.newToFolderDto(c, g, folder))
}
@@ -99,7 +103,10 @@ func (hs *HTTPServer) GetFolderByID(c *models.ReqContext) response.Response {
return apierrors.ToFolderErrorResponse(err)
}
g := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
g, err := guardian.NewByUID(c.Req.Context(), folder.UID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
return response.JSON(http.StatusOK, hs.newToFolderDto(c, g, folder))
}
@@ -135,7 +142,11 @@ func (hs *HTTPServer) CreateFolder(c *models.ReqContext) response.Response {
hs.accesscontrolService.ClearUserPermissionCache(c.SignedInUser)
}
g := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
g, err := guardian.NewByUID(c.Req.Context(), folder.UID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
// TODO set ParentUID if nested folders are enabled
return response.JSON(http.StatusOK, hs.newToFolderDto(c, g, folder))
}
@@ -190,7 +201,11 @@ func (hs *HTTPServer) UpdateFolder(c *models.ReqContext) response.Response {
if err != nil {
return apierrors.ToFolderErrorResponse(err)
}
g := guardian.New(c.Req.Context(), result.ID, c.OrgID, c.SignedInUser)
g, err := guardian.NewByUID(c.Req.Context(), result.UID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
return response.JSON(http.StatusOK, hs.newToFolderDto(c, g, result))
}

View File

@@ -34,7 +34,10 @@ func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Res
return apierrors.ToFolderErrorResponse(err)
}
g := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
g, err := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return apierrors.ToFolderErrorResponse(dashboards.ErrFolderAccessDenied)
@@ -95,7 +98,11 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext) response.Res
return apierrors.ToFolderErrorResponse(err)
}
g := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
g, err := guardian.New(c.Req.Context(), folder.ID, c.OrgID, c.SignedInUser)
if err != nil {
return response.Err(err)
}
canAdmin, err := g.CanAdmin()
if err != nil {
return apierrors.ToFolderErrorResponse(err)

View File

@@ -240,6 +240,13 @@ func createFolderScenario(t *testing.T, desc string, url string, routePattern st
q := args.Get(1).(*models.GetDashboardACLInfoListQuery)
q.Result = aclMockResp
}).Return(nil)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardQuery)
q.Result = &models.Dashboard{
Id: q.Id,
Uid: q.Uid,
}
}).Return(nil)
store := mockstore.NewSQLStoreMock()
guardian.InitLegacyGuardian(store, dashSvc, teamSvc)
hs := HTTPServer{