API: Remove usage of legacy dashboard guardian in tests (#73937)

This commit is contained in:
Karl Persson 2023-08-29 15:09:09 +02:00 committed by GitHub
parent 0884f40c8d
commit 127473f4a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -27,6 +27,7 @@ import (
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
"github.com/grafana/grafana/pkg/registry/corekind"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
@ -54,11 +55,11 @@ import (
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/star/startest"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
"github.com/grafana/grafana/pkg/services/team/teamtest"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/grafana/grafana/pkg/web/webtest"
)
func TestGetHomeDashboard(t *testing.T) {
@ -131,424 +132,247 @@ func newTestLive(t *testing.T, store db.DB) *live.GrafanaLive {
return gLive
}
// This tests three main scenarios.
// If a user has access to execute an action on a dashboard:
// 1. and the dashboard is in a folder which does not have an acl
// 2. and the dashboard is in a folder which does have an acl
// 3. Post dashboard response tests
func TestHTTPServer_GetDashboard_AccessControl(t *testing.T) {
setup := func() *webtest.Server {
return SetupAPITestServer(t, func(hs *HTTPServer) {
dash := dashboards.NewDashboard("some dash")
dash.ID = 1
dash.UID = "1"
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dash, nil).Maybe()
hs.DashboardService = dashSvc
hs.Cfg = setting.NewCfg()
hs.AccessControl = acimpl.ProvideAccessControl(hs.Cfg)
hs.starService = startest.NewStarServiceFake()
hs.dashboardProvisioningService = mockDashboardProvisioningService{}
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService)
})
}
getDashboard := func(server *webtest.Server, permissions []accesscontrol.Permission) (*http.Response, error) {
return server.Send(webtest.RequestWithSignedInUser(server.NewGetRequest("/api/dashboards/uid/1"), userWithPermissions(1, permissions)))
}
t.Run("Should not be able to get dashboard without correct permission", func(t *testing.T) {
server := setup()
res, err := getDashboard(server, nil)
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, res.StatusCode)
require.NoError(t, res.Body.Close())
})
t.Run("Should be able to get when user has permission to read dashboard", func(t *testing.T) {
server := setup()
permissions := []accesscontrol.Permission{{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:1"}}
res, err := getDashboard(server, permissions)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
var data dtos.DashboardFullWithMeta
require.NoError(t, json.NewDecoder(res.Body).Decode(&data))
assert.Equal(t, data.Meta.CanSave, false)
assert.Equal(t, data.Meta.CanEdit, false)
assert.Equal(t, data.Meta.CanDelete, false)
assert.Equal(t, data.Meta.CanAdmin, false)
require.NoError(t, res.Body.Close())
})
t.Run("Should set CanSave and CanEdit with correct permissions", func(t *testing.T) {
server := setup()
res, err := getDashboard(server, []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:1"},
{Action: dashboards.ActionDashboardsWrite, Scope: "dashboards:uid:1"},
})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
var data dtos.DashboardFullWithMeta
require.NoError(t, json.NewDecoder(res.Body).Decode(&data))
assert.Equal(t, data.Meta.CanSave, true)
assert.Equal(t, data.Meta.CanEdit, true)
assert.Equal(t, data.Meta.CanDelete, false)
assert.Equal(t, data.Meta.CanAdmin, false)
require.NoError(t, res.Body.Close())
})
t.Run("Should set canDelete with correct permissions", func(t *testing.T) {
server := setup()
res, err := getDashboard(server, []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:1"},
{Action: dashboards.ActionDashboardsDelete, Scope: "dashboards:uid:1"},
})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
var data dtos.DashboardFullWithMeta
require.NoError(t, json.NewDecoder(res.Body).Decode(&data))
assert.Equal(t, data.Meta.CanSave, false)
assert.Equal(t, data.Meta.CanEdit, false)
assert.Equal(t, data.Meta.CanDelete, true)
assert.Equal(t, data.Meta.CanAdmin, false)
require.NoError(t, res.Body.Close())
})
t.Run("Should set canAdmin with correct permissions", func(t *testing.T) {
server := setup()
res, err := getDashboard(server, []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:1"},
{Action: dashboards.ActionDashboardsPermissionsRead, Scope: "dashboards:uid:1"},
{Action: dashboards.ActionDashboardsPermissionsWrite, Scope: "dashboards:uid:1"},
})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
var data dtos.DashboardFullWithMeta
require.NoError(t, json.NewDecoder(res.Body).Decode(&data))
assert.Equal(t, data.Meta.CanSave, false)
assert.Equal(t, data.Meta.CanEdit, false)
assert.Equal(t, data.Meta.CanDelete, false)
assert.Equal(t, data.Meta.CanAdmin, true)
require.NoError(t, res.Body.Close())
})
}
func TestHTTPServer_DeleteDashboardByUID_AccessControl(t *testing.T) {
setup := func() *webtest.Server {
return SetupAPITestServer(t, func(hs *HTTPServer) {
dash := dashboards.NewDashboard("some dash")
dash.ID = 1
dash.UID = "1"
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dash, nil).Maybe()
dashSvc.On("DeleteDashboard", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
hs.DashboardService = dashSvc
hs.Cfg = setting.NewCfg()
hs.AccessControl = acimpl.ProvideAccessControl(hs.Cfg)
hs.starService = startest.NewStarServiceFake()
hs.LibraryPanelService = &mockLibraryPanelService{}
hs.LibraryElementService = &mockLibraryElementService{}
pubDashService := publicdashboards.NewFakePublicDashboardService(t)
pubDashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil).Maybe()
hs.PublicDashboardsApi = api.ProvideApi(pubDashService, nil, hs.AccessControl, featuremgmt.WithFeatures())
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService)
})
}
deleteDashboard := func(server *webtest.Server, permissions []accesscontrol.Permission) (*http.Response, error) {
return server.Send(webtest.RequestWithSignedInUser(server.NewRequest(http.MethodDelete, "/api/dashboards/uid/1", nil), userWithPermissions(1, permissions)))
}
t.Run("Should not be able to delete dashboard without correct permission", func(t *testing.T) {
server := setup()
res, err := deleteDashboard(server, []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsDelete, Scope: "dashboards:uid:2"},
})
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, res.StatusCode)
require.NoError(t, res.Body.Close())
})
t.Run("Should be able to delete dashboard with correct permission", func(t *testing.T) {
server := setup()
res, err := deleteDashboard(server, []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsDelete, Scope: "dashboards:uid:1"},
})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
require.NoError(t, res.Body.Close())
})
}
func TestHTTPServer_GetDashboardVersions_AccessControl(t *testing.T) {
setup := func() *webtest.Server {
return SetupAPITestServer(t, func(hs *HTTPServer) {
dash := dashboards.NewDashboard("some dash")
dash.ID = 1
dash.UID = "1"
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dash, nil).Maybe()
dashSvc.On("DeleteDashboard", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
hs.DashboardService = dashSvc
hs.Cfg = setting.NewCfg()
hs.AccessControl = acimpl.ProvideAccessControl(hs.Cfg)
hs.starService = startest.NewStarServiceFake()
hs.dashboardVersionService = &dashvertest.FakeDashboardVersionService{
ExpectedListDashboarVersions: []*dashver.DashboardVersionDTO{},
ExpectedDashboardVersion: &dashver.DashboardVersionDTO{},
}
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService)
})
}
getVersion := func(server *webtest.Server, permissions []accesscontrol.Permission) (*http.Response, error) {
return server.Send(webtest.RequestWithSignedInUser(server.NewGetRequest("/api/dashboards/uid/1/versions/1"), userWithPermissions(1, permissions)))
}
getVersions := func(server *webtest.Server, permissions []accesscontrol.Permission) (*http.Response, error) {
return server.Send(webtest.RequestWithSignedInUser(server.NewGetRequest("/api/dashboards/uid/1/versions"), userWithPermissions(1, permissions)))
}
t.Run("Should not be able to list dashboard versions without correct permission", func(t *testing.T) {
server := setup()
res, err := getVersions(server, []accesscontrol.Permission{})
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, res.StatusCode)
require.NoError(t, res.Body.Close())
res, err = getVersion(server, []accesscontrol.Permission{})
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, res.StatusCode)
require.NoError(t, res.Body.Close())
})
t.Run("Should be able to list dashboard versions with correct permission", func(t *testing.T) {
server := setup()
permissions := []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:1"},
{Action: dashboards.ActionDashboardsWrite, Scope: "dashboards:uid:1"},
}
res, err := getVersions(server, permissions)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
require.NoError(t, res.Body.Close())
res, err = getVersion(server, permissions)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
require.NoError(t, res.Body.Close())
})
}
func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("Given a dashboard with a parent folder which does not have an ACL", func(t *testing.T) {
fakeDash := dashboards.NewDashboard("Child dash")
fakeDash.SetID(1)
fakeDash.SetUID("test-uid-one")
fakeDash.FolderID = 1
fakeDash.HasACL = false
fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake()
fakeDashboardVersionService.ExpectedDashboardVersion = &dashver.DashboardVersionDTO{CreatedBy: 1}
teamService := &teamtest.FakeService{}
dashboardService := dashboards.NewFakeDashboardService(t)
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(fakeDash, nil)
mockSQLStore := dbtest.NewFakeDB()
hs := &HTTPServer{
Cfg: setting.NewCfg(),
pluginStore: &fakes.FakePluginStore{},
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
Features: featuremgmt.WithFeatures(),
DashboardService: dashboardService,
dashboardVersionService: fakeDashboardVersionService,
Kinds: corekind.NewBase(nil),
QuotaService: quotatest.New(false, nil),
starService: startest.NewStarServiceFake(),
userService: &usertest.FakeUserService{
ExpectedUser: &user.User{ID: 1, Login: "test-user"},
},
}
setUp := func() {
viewerRole := org.RoleViewer
editorRole := org.RoleEditor
qResult := []*dashboards.DashboardACLInfoDTO{
{Role: &viewerRole, Permission: dashboards.PERMISSION_VIEW},
{Role: &editorRole, Permission: dashboards.PERMISSION_EDIT},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(hs.Cfg, mockSQLStore, dashboardService, teamService)
}
// This tests two scenarios:
// 1. user is an org viewer
// 2. user is an org editor
t.Run("When user is an Org Viewer", func(t *testing.T) {
role := org.RoleViewer
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
assert.Equal(t, fakeDash.UID, dash.Dashboard.Get("uid").MustString())
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
})
t.Run("When user is an Org Editor", func(t *testing.T) {
role := org.RoleEditor
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
var version *dashver.DashboardVersionMeta
err := json.NewDecoder(sc.resp.Body).Decode(&version)
require.NoError(t, err)
assert.NotEqual(t, anonString, version.CreatedBy)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUp()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore)
})
})
t.Run("Given a dashboard with a parent folder which has an ACL", func(t *testing.T) {
fakeDash := dashboards.NewDashboard("Child dash")
fakeDash.ID = 1
fakeDash.FolderID = 1
fakeDash.HasACL = true
fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake()
fakeDashboardVersionService.ExpectedDashboardVersion = &dashver.DashboardVersionDTO{}
teamService := &teamtest.FakeService{}
dashboardService := dashboards.NewFakeDashboardService(t)
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(fakeDash, nil)
qResult := []*dashboards.DashboardACLInfoDTO{
{
DashboardID: 1,
Permission: dashboards.PERMISSION_EDIT,
UserID: 200,
},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
mockSQLStore := dbtest.NewFakeDB()
cfg := setting.NewCfg()
sql := db.InitTestDB(t)
hs := &HTTPServer{
Cfg: cfg,
Live: newTestLive(t, sql),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
DashboardService: dashboardService,
dashboardVersionService: fakeDashboardVersionService,
Features: featuremgmt.WithFeatures(),
Kinds: corekind.NewBase(nil),
}
setUp := func() {
cfg.ViewersCanEdit = false
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
}
// This tests six scenarios:
// 1. user is an org viewer AND has no permissions for this dashboard
// 2. user is an org editor AND has no permissions for this dashboard
// 3. user is an org viewer AND has been granted edit permission for the dashboard
// 4. user is an org viewer AND all viewers have edit permission for this dashboard
// 5. user is an org viewer AND has been granted an admin permission
// 6. user is an org editor AND has been granted a view permission
t.Run("When user is an Org Viewer and has no permissions for this dashboard", func(t *testing.T) {
role := org.RoleViewer
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUp()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
})
t.Run("When user is an Org Editor and has no permissions for this dashboard", func(t *testing.T) {
role := org.RoleEditor
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUp()
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUp()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
})
t.Run("When user is an Org Viewer but has an edit permission", func(t *testing.T) {
role := org.RoleViewer
setUpInner := func() {
cfg.ViewersCanEdit = false
dashboardService := dashboards.NewFakeDashboardService(t)
qResult := []*dashboards.DashboardACLInfoDTO{
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_EDIT},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
dashboardService := dashboards.NewFakeDashboardService(t)
qResult := dashboards.NewDashboard("test")
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
dashboardService.On("DeleteDashboard", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(nil)
pubdashService := publicdashboards.NewFakePublicDashboardService(t)
pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService)
assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore)
})
t.Run("When user is an Org Viewer and viewers can edit", func(t *testing.T) {
role := org.RoleViewer
setUpInner := func() {
cfg.ViewersCanEdit = true
dashboardService := dashboards.NewFakeDashboardService(t)
qResult := []*dashboards.DashboardACLInfoDTO{
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_VIEW},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
require.True(t, cfg.ViewersCanEdit)
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
assert.True(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
})
t.Run("When user is an Org Viewer but has an admin permission", func(t *testing.T) {
role := org.RoleViewer
setUpInner := func() {
cfg.ViewersCanEdit = true
dashboardService := dashboards.NewFakeDashboardService(t)
qResult := []*dashboards.DashboardACLInfoDTO{
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_ADMIN},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.True(t, dash.Meta.CanAdmin)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dashboardService := dashboards.NewFakeDashboardService(t)
qResult := dashboards.NewDashboard("test")
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
dashboardService.On("DeleteDashboard", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(nil)
pubdashService := publicdashboards.NewFakePublicDashboardService(t)
pubdashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService, pubdashService)
assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
}, mockSQLStore)
})
t.Run("When user is an Org Editor but has a view permission", func(t *testing.T) {
role := org.RoleEditor
setUpInner := func() {
cfg := setting.NewCfg()
dashboardService := dashboards.NewFakeDashboardService(t)
qResult := []*dashboards.DashboardACLInfoDTO{
{OrgID: 1, DashboardID: 2, UserID: 1, Permission: dashboards.PERMISSION_VIEW},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService, nil)
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
hs.callDeleteDashboardByUID(t, sc, dashboardService, nil)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
hs.callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
})
})
t.Run("Given two dashboards with the same title in different folders", func(t *testing.T) {
dashOne := dashboards.NewDashboard("dash")
dashOne.ID = 2
@ -776,15 +600,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
},
}
sqlmock := dbtest.NewFakeDB()
setUp := func() {
teamSvc := &teamtest.FakeService{}
dashSvc := dashboards.NewFakeDashboardService(t)
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(nil, nil)
qResult := &dashboards.Dashboard{}
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(setting.NewCfg(), sqlmock, dashSvc, teamSvc)
}
cmd := dtos.CalculateDiffOptions{
Base: dtos.CalculateDiffTarget{
DashboardId: 1,
@ -800,7 +615,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("when user does not have permission", func(t *testing.T) {
role := org.RoleViewer
postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
setUp()
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: false})
callPostDashboard(sc)
assert.Equal(t, 403, sc.resp.Code)
@ -810,6 +625,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("when user does have permission", func(t *testing.T) {
role := org.RoleAdmin
postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
// This test shouldn't hit GetDashboardACLInfoList, so no setup needed
sc.dashboardVersionService = fakeDashboardVersionService
callPostDashboard(sc)
@ -892,16 +708,13 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dashboardStore := dashboards.NewFakeDashboardStore(t)
dashboardStore.On("GetProvisionedDataByDashboardID", mock.Anything, mock.AnythingOfType("int64")).Return(&dashboards.DashboardProvisioning{ExternalID: "/dashboard1.json"}, nil).Once()
teamService := &teamtest.FakeService{}
dashboardService := dashboards.NewFakeDashboardService(t)
dataValue, err := simplejson.NewJson([]byte(`{"id": 1, "editable": true, "style": "dark"}`))
require.NoError(t, err)
qResult := &dashboards.Dashboard{ID: 1, Data: dataValue}
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
qResult2 := []*dashboards.DashboardACLInfoDTO{{OrgID: testOrgID, DashboardID: 1, UserID: testUserID, Permission: dashboards.PERMISSION_EDIT}}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult2, nil)
guardian.InitLegacyGuardian(setting.NewCfg(), mockSQLStore, dashboardService, teamService)
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) {
fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background())
@ -954,14 +767,11 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
fakeDash := dashboards.NewDashboard("Child dash")
fakeDash.ID = 1
fakeDash.FolderID = 1
fakeDash.HasACL = false
fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake()
dashboardService := dashboards.NewFakeDashboardService(t)
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(fakeDash, nil)
teamService := &teamtest.FakeService{}
mockSQLStore := dbtest.NewFakeDB()
cfg := setting.NewCfg()
@ -984,14 +794,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
}
setUp := func() {
viewerRole := org.RoleViewer
editorRole := org.RoleEditor
qResult := []*dashboards.DashboardACLInfoDTO{
{Role: &viewerRole, Permission: dashboards.PERMISSION_VIEW},
{Role: &editorRole, Permission: dashboards.PERMISSION_EDIT},
}
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult, nil)
guardian.InitLegacyGuardian(cfg, mockSQLStore, dashboardService, teamService)
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
}
loggedInUserScenarioWithRole(t, "When user exists and calling GET on", "GET", "/api/dashboards/id/2/versions",
@ -1143,25 +946,11 @@ func (hs *HTTPServer) callGetDashboard(sc *scenarioContext) {
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
}
func (hs *HTTPServer) callGetDashboardVersion(sc *scenarioContext) {
sc.handlerFunc = hs.GetDashboardVersion
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
}
func (hs *HTTPServer) callGetDashboardVersions(sc *scenarioContext) {
sc.handlerFunc = hs.GetDashboardVersions
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
}
func (hs *HTTPServer) callDeleteDashboardByUID(t *testing.T,
sc *scenarioContext, mockDashboard *dashboards.FakeDashboardService, mockPubdashService *publicdashboards.FakePublicDashboardService) {
hs.DashboardService = mockDashboard
pubdashApi := api.ProvideApi(mockPubdashService, nil, nil, featuremgmt.WithFeatures())
hs.PublicDashboardsApi = pubdashApi
sc.handlerFunc = hs.DeleteDashboardByUID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
}
func callPostDashboard(sc *scenarioContext) {
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
}