mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
RBAC: protect folder creation and moving (#64636)
* protect moving folders to a subfolder and creating folders in a subfolder * folder update endpoint isn't used for folder parent update * lint * move permission check logic to services, fix tests * linting
This commit is contained in:
@@ -186,7 +186,7 @@ func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int
|
||||
})
|
||||
}
|
||||
|
||||
if !isNested {
|
||||
if !isNested || !hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
|
||||
permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{
|
||||
{BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()},
|
||||
{BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()},
|
||||
@@ -209,9 +209,11 @@ func (hs *HTTPServer) MoveFolder(c *contextmodel.ReqContext) response.Response {
|
||||
}
|
||||
var theFolder *folder.Folder
|
||||
var err error
|
||||
|
||||
if cmd.NewParentUID != "" {
|
||||
cmd.OrgID = c.OrgID
|
||||
cmd.UID = web.Params(c.Req)[":uid"]
|
||||
cmd.SignedInUser = c.SignedInUser
|
||||
theFolder, err = hs.folderService.Move(c.Req.Context(), &cmd)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "update folder uid failed", err)
|
||||
@@ -228,9 +230,6 @@ func (hs *HTTPServer) MoveFolder(c *contextmodel.ReqContext) response.Response {
|
||||
//
|
||||
// Update folder.
|
||||
//
|
||||
// If nested folders are enabled then it optionally expects a new parent folder UID that moves the folder and
|
||||
// includes it into the response.
|
||||
//
|
||||
// Responses:
|
||||
// 200: folderResponse
|
||||
// 400: badRequestError
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -11,142 +12,270 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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/infra/db/dbtest"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web/webtest"
|
||||
)
|
||||
|
||||
func TestFoldersAPIEndpoint(t *testing.T) {
|
||||
func TestFoldersCreateAPIEndpoint(t *testing.T) {
|
||||
folderService := &foldertest.FakeService{}
|
||||
setUpRBACGuardian(t)
|
||||
|
||||
t.Run("Given a correct request for creating a folder", func(t *testing.T) {
|
||||
cmd := folder.CreateFolderCommand{
|
||||
UID: "uid",
|
||||
Title: "Folder",
|
||||
}
|
||||
folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}"
|
||||
|
||||
folderService.ExpectedFolder = &folder.Folder{ID: 1, UID: "uid", Title: "Folder"}
|
||||
type testCase struct {
|
||||
description string
|
||||
expectedCode int
|
||||
expectedFolder *folder.Folder
|
||||
expectedFolderSvcError error
|
||||
permissions []accesscontrol.Permission
|
||||
withNestedFolders bool
|
||||
input string
|
||||
}
|
||||
tcs := []testCase{
|
||||
{
|
||||
description: "folder creation succeeds given the correct request for creating a folder",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusOK,
|
||||
expectedFolder: &folder.Folder{ID: 1, UID: "uid", Title: "Folder"},
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails without permissions to create a folder",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []accesscontrol.Permission{},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusConflict,
|
||||
expectedFolderSvcError: dashboards.ErrFolderWithSameUIDExists,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedFolderSvcError: dashboards.ErrFolderTitleEmpty,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedFolderSvcError: dashboards.ErrDashboardInvalidUid,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedFolderSvcError: dashboards.ErrDashboardUidTooLong,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusConflict,
|
||||
expectedFolderSvcError: dashboards.ErrFolderSameNameExists,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusForbidden,
|
||||
expectedFolderSvcError: dashboards.ErrFolderAccessDenied,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusNotFound,
|
||||
expectedFolderSvcError: dashboards.ErrFolderNotFound,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
{
|
||||
description: "folder creation fails given folder service error %s",
|
||||
input: folderWithoutParentInput,
|
||||
expectedCode: http.StatusPreconditionFailed,
|
||||
expectedFolderSvcError: dashboards.ErrFolderVersionMismatch,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
||||
},
|
||||
}
|
||||
|
||||
createFolderScenario(t, "When calling POST on", "/api/folders", "/api/folders", folderService, cmd,
|
||||
func(sc *scenarioContext) {
|
||||
callCreateFolder(sc)
|
||||
for _, tc := range tcs {
|
||||
folderService.ExpectedFolder = tc.expectedFolder
|
||||
folderService.ExpectedError = tc.expectedFolderSvcError
|
||||
folderPermService := acmock.NewMockedPermissionsService()
|
||||
folderPermService.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
|
||||
folder := dtos.Folder{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
|
||||
require.NoError(t, err)
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = &setting.Cfg{
|
||||
RBACEnabled: true,
|
||||
}
|
||||
|
||||
if tc.withNestedFolders {
|
||||
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
||||
}
|
||||
hs.folderService = folderService
|
||||
hs.folderPermissionsService = folderPermService
|
||||
hs.accesscontrolService = actest.FakeService{}
|
||||
})
|
||||
|
||||
t.Run(testDescription(tc.description, tc.expectedFolderSvcError), func(t *testing.T) {
|
||||
input := strings.NewReader(tc.input)
|
||||
req := srv.NewPostRequest("/api/folders", input)
|
||||
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
||||
resp, err := srv.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
||||
|
||||
folder := dtos.Folder{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&folder)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
if tc.expectedCode == http.StatusOK {
|
||||
assert.Equal(t, int64(1), folder.Id)
|
||||
assert.Equal(t, "uid", folder.Uid)
|
||||
assert.Equal(t, "Folder", folder.Title)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Given incorrect requests for creating a folder", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
folderService.ExpectedError = nil
|
||||
}
|
||||
})
|
||||
testCases := []struct {
|
||||
Error error
|
||||
ExpectedStatusCode int
|
||||
}{
|
||||
{Error: dashboards.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
|
||||
{Error: dashboards.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
|
||||
{Error: dashboards.ErrFolderSameNameExists, ExpectedStatusCode: 409},
|
||||
{Error: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
|
||||
{Error: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
|
||||
{Error: dashboards.ErrFolderAccessDenied, ExpectedStatusCode: 403},
|
||||
{Error: dashboards.ErrFolderNotFound, ExpectedStatusCode: 404},
|
||||
{Error: dashboards.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd := folder.CreateFolderCommand{
|
||||
UID: "uid",
|
||||
Title: "Folder",
|
||||
}
|
||||
func TestFoldersUpdateAPIEndpoint(t *testing.T) {
|
||||
folderService := &foldertest.FakeService{}
|
||||
setUpRBACGuardian(t)
|
||||
|
||||
for _, tc := range testCases {
|
||||
folderService.ExpectedError = tc.Error
|
||||
type testCase struct {
|
||||
description string
|
||||
expectedCode int
|
||||
expectedFolder *folder.Folder
|
||||
expectedFolderSvcError error
|
||||
permissions []accesscontrol.Permission
|
||||
}
|
||||
tcs := []testCase{
|
||||
{
|
||||
description: "folder updating succeeds given the correct request and permissions to update a folder",
|
||||
expectedCode: http.StatusOK,
|
||||
expectedFolder: &folder.Folder{ID: 1, UID: "uid", Title: "Folder upd"},
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails without permissions to update a folder",
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []accesscontrol.Permission{},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusConflict,
|
||||
expectedFolderSvcError: dashboards.ErrFolderWithSameUIDExists,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedFolderSvcError: dashboards.ErrFolderTitleEmpty,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedFolderSvcError: dashboards.ErrDashboardInvalidUid,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedFolderSvcError: dashboards.ErrDashboardUidTooLong,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusConflict,
|
||||
expectedFolderSvcError: dashboards.ErrFolderSameNameExists,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusForbidden,
|
||||
expectedFolderSvcError: dashboards.ErrFolderAccessDenied,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusNotFound,
|
||||
expectedFolderSvcError: dashboards.ErrFolderNotFound,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
{
|
||||
description: "folder updating fails given folder service error %s",
|
||||
expectedCode: http.StatusPreconditionFailed,
|
||||
expectedFolderSvcError: dashboards.ErrFolderVersionMismatch,
|
||||
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
||||
},
|
||||
}
|
||||
|
||||
createFolderScenario(t, fmt.Sprintf("Expect '%s' error when calling POST on", tc.Error.Error()),
|
||||
"/api/folders", "/api/folders", folderService, cmd, func(sc *scenarioContext) {
|
||||
callCreateFolder(sc)
|
||||
assert.Equalf(t, tc.ExpectedStatusCode, sc.resp.Code, "Wrong status code for error %s", tc.Error)
|
||||
})
|
||||
}
|
||||
})
|
||||
for _, tc := range tcs {
|
||||
folderService.ExpectedFolder = tc.expectedFolder
|
||||
folderService.ExpectedError = tc.expectedFolderSvcError
|
||||
|
||||
t.Run("Given a correct request for updating a folder", func(t *testing.T) {
|
||||
title := "Folder upd"
|
||||
cmd := folder.UpdateFolderCommand{
|
||||
NewTitle: &title,
|
||||
}
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = &setting.Cfg{
|
||||
RBACEnabled: true,
|
||||
}
|
||||
hs.folderService = folderService
|
||||
})
|
||||
|
||||
folderService.ExpectedFolder = &folder.Folder{ID: 1, UID: "uid", Title: "Folder upd"}
|
||||
t.Run(testDescription(tc.description, tc.expectedFolderSvcError), func(t *testing.T) {
|
||||
input := strings.NewReader("{ \"uid\": \"uid\", \"title\": \"Folder upd\" }")
|
||||
req := srv.NewRequest(http.MethodPut, "/api/folders/uid", input)
|
||||
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
||||
resp, err := srv.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
||||
|
||||
updateFolderScenario(t, "When calling PUT on", "/api/folders/uid", "/api/folders/:uid", folderService, cmd,
|
||||
func(sc *scenarioContext) {
|
||||
callUpdateFolder(sc)
|
||||
folder := dtos.Folder{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&folder)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
folder := dtos.Folder{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
|
||||
require.NoError(t, err)
|
||||
if tc.expectedCode == http.StatusOK {
|
||||
assert.Equal(t, int64(1), folder.Id)
|
||||
assert.Equal(t, "uid", folder.Uid)
|
||||
assert.Equal(t, "Folder upd", folder.Title)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("Given incorrect requests for updating a folder", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Error error
|
||||
ExpectedStatusCode int
|
||||
}{
|
||||
{Error: dashboards.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
|
||||
{Error: dashboards.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
|
||||
{Error: dashboards.ErrFolderSameNameExists, ExpectedStatusCode: 409},
|
||||
{Error: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
|
||||
{Error: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
|
||||
{Error: dashboards.ErrFolderAccessDenied, ExpectedStatusCode: 403},
|
||||
{Error: dashboards.ErrFolderNotFound, ExpectedStatusCode: 404},
|
||||
{Error: dashboards.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
|
||||
}
|
||||
|
||||
title := "Folder upd"
|
||||
cmd := folder.UpdateFolderCommand{
|
||||
NewTitle: &title,
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
folderService.ExpectedError = tc.Error
|
||||
updateFolderScenario(t, fmt.Sprintf("Expect '%s' error when calling PUT on", tc.Error.Error()),
|
||||
"/api/folders/uid", "/api/folders/:uid", folderService, cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolder(sc)
|
||||
assert.Equalf(t, tc.ExpectedStatusCode, sc.resp.Code, "Wrong status code for %s", tc.Error)
|
||||
})
|
||||
}
|
||||
})
|
||||
func testDescription(description string, expectedErr error) string {
|
||||
if expectedErr != nil {
|
||||
return fmt.Sprintf(description, expectedErr.Error())
|
||||
} else {
|
||||
return description
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPServer_FolderMetadata(t *testing.T) {
|
||||
setUpRBACGuardian(t)
|
||||
folderService := &foldertest.FakeService{}
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = &setting.Cfg{
|
||||
RBACEnabled: true,
|
||||
}
|
||||
hs.folderService = folderService
|
||||
hs.AccessControl = acmock.New()
|
||||
hs.QuotaService = quotatest.New(false, nil)
|
||||
hs.SearchService = &mockSearchService{
|
||||
ExpectedResult: model.HitList{},
|
||||
@@ -229,76 +358,53 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func callCreateFolder(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func createFolderScenario(t *testing.T, desc string, url string, routePattern string, folderService folder.Service,
|
||||
cmd folder.CreateFolderCommand, fn scenarioFunc) {
|
||||
func TestFolderMoveAPIEndpoint(t *testing.T) {
|
||||
folderService := &foldertest.FakeService{}
|
||||
setUpRBACGuardian(t)
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
aclMockResp := []*dashboards.DashboardACLInfoDTO{}
|
||||
teamSvc := &teamtest.FakeService{}
|
||||
dashSvc := &dashboards.FakeDashboardService{}
|
||||
qResult1 := aclMockResp
|
||||
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Return(qResult1, nil)
|
||||
qResult := &dashboards.Dashboard{}
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
|
||||
store := dbtest.NewFakeDB()
|
||||
guardian.InitLegacyGuardian(setting.NewCfg(), store, dashSvc, teamSvc)
|
||||
folderPermissions := acmock.NewMockedPermissionsService()
|
||||
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
hs := HTTPServer{
|
||||
AccessControl: acmock.New(),
|
||||
folderService: folderService,
|
||||
Cfg: setting.NewCfg(),
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
accesscontrolService: actest.FakeService{},
|
||||
folderPermissionsService: folderPermissions,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
|
||||
c.Req.Body = mockRequestBody(cmd)
|
||||
c.Req.Header.Add("Content-Type", "application/json")
|
||||
sc.context = c
|
||||
sc.context.SignedInUser = &user.SignedInUser{OrgID: testOrgID, UserID: testUserID}
|
||||
type testCase struct {
|
||||
description string
|
||||
expectedCode int
|
||||
permissions []accesscontrol.Permission
|
||||
newParentUid string
|
||||
}
|
||||
tcs := []testCase{
|
||||
{
|
||||
description: "can move folder to another folder with specific permissions",
|
||||
newParentUid: "newParentUid",
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")},
|
||||
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("newParentUid")},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "forbidden to move folder to another folder without the write access on the folder being moved",
|
||||
newParentUid: "newParentUid",
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("newParentUid")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return hs.CreateFolder(c)
|
||||
for _, tc := range tcs {
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = &setting.Cfg{
|
||||
RBACEnabled: true,
|
||||
}
|
||||
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
||||
hs.folderService = folderService
|
||||
})
|
||||
|
||||
sc.m.Post(routePattern, sc.defaultHandler)
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
||||
|
||||
func callUpdateFolder(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func updateFolderScenario(t *testing.T, desc string, url string, routePattern string, folderService folder.Service,
|
||||
cmd folder.UpdateFolderCommand, fn scenarioFunc) {
|
||||
setUpRBACGuardian(t)
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
hs := HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
AccessControl: acmock.New(),
|
||||
folderService: folderService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
|
||||
c.Req.Body = mockRequestBody(cmd)
|
||||
c.Req.Header.Add("Content-Type", "application/json")
|
||||
sc.context = c
|
||||
sc.context.SignedInUser = &user.SignedInUser{OrgID: testOrgID, UserID: testUserID}
|
||||
|
||||
return hs.UpdateFolder(c)
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
input := strings.NewReader(fmt.Sprintf("{ \"parentUid\": \"%s\"}", tc.newParentUid))
|
||||
req := srv.NewRequest(http.MethodPost, "/api/folders/uid/move", input)
|
||||
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
||||
resp, err := srv.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
})
|
||||
|
||||
sc.m.Put(routePattern, sc.defaultHandler)
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user