grafana/pkg/api/org_test.go
Jeff Levin cfe8317d45
Add auth spans and remove deduplication code for scopes (#89804)
Adds more spans for timing in accesscontrol and remove permission deduplicating code after benchmarking

---------

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>
Co-authored-by: Dave Henderson <dave.henderson@grafana.com>
Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
2024-07-02 22:08:57 -08:00

306 lines
9.7 KiB
Go

package api
import (
"context"
"net/http"
"strings"
"testing"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgtest"
"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/webtest"
)
func TestAPIEndpoint_GetCurrentOrg(t *testing.T) {
type testCase struct {
desc string
expectedCode int
permission []accesscontrol.Permission
}
tests := []testCase{
{
desc: "should be able to view current org with correct permission",
expectedCode: http.StatusOK,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsRead}},
},
{
desc: "should not be able to view current org without correct permission",
expectedCode: http.StatusForbidden,
permission: []accesscontrol.Permission{},
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.Cfg = setting.NewCfg()
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
})
req := webtest.RequestWithSignedInUser(server.NewGetRequest("/api/org/"), userWithPermissions(1, tt.permission))
res, err := server.Send(req)
require.NoError(t, err)
assert.Equal(t, tt.expectedCode, res.StatusCode)
require.NoError(t, res.Body.Close())
})
}
}
func TestAPIEndpoint_UpdateOrg(t *testing.T) {
type testCase struct {
desc string
path string
body string
targetOrgID int64
permission []accesscontrol.Permission
expectedCode int
}
tests := []testCase{
{
desc: "should be able to update current org with correct permissions",
path: "/api/org",
body: `{"name": "test"}`,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsWrite}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to update current org without correct permissions",
path: "/api/org",
body: `{"name": "test"}`,
permission: []accesscontrol.Permission{},
expectedCode: http.StatusForbidden,
},
{
desc: "should be able to update address of current org with correct permissions",
path: "/api/org/address",
body: `{}`,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsWrite}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to update address of current org without correct permissions",
path: "/api/org/address",
body: `{}`,
permission: []accesscontrol.Permission{},
expectedCode: http.StatusForbidden,
},
{
desc: "should be able to update target org with correct permissions",
path: "/api/orgs/1",
body: `{"name": "test"}`,
targetOrgID: 1,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsWrite}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to update target org without correct permissions",
path: "/api/orgs/2",
targetOrgID: 2,
body: `{"name": "test"}`,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsWrite}},
expectedCode: http.StatusForbidden,
},
{
desc: "should be able to update address of target org with correct permissions",
path: "/api/orgs/1/address",
body: `{}`,
targetOrgID: 1,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsWrite}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to update address of target org without correct permissions",
path: "/api/orgs/2/address",
body: `{}`,
targetOrgID: 2,
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsWrite}},
expectedCode: http.StatusForbidden,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.Cfg = setting.NewCfg()
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
hs.userService = &usertest.FakeUserService{
ExpectedSignedInUser: &user.SignedInUser{OrgID: tt.targetOrgID},
}
hs.accesscontrolService = actest.FakeService{}
hs.authnService = &authntest.FakeService{
ExpectedIdentity: &authn.Identity{
OrgID: tt.targetOrgID,
},
}
})
req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPut, tt.path, strings.NewReader(tt.body)), userWithPermissions(1, tt.permission))
res, err := server.SendJSON(req)
require.NoError(t, err)
assert.Equal(t, tt.expectedCode, res.StatusCode)
require.NoError(t, res.Body.Close())
})
}
}
func TestAPIEndpoint_CreateOrgs(t *testing.T) {
type testCase struct {
desc string
permission []accesscontrol.Permission
expectedCode int
}
tests := []testCase{
{
desc: "should be able to create org with correct permission",
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsCreate}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to create org without correct permission",
permission: []accesscontrol.Permission{},
expectedCode: http.StatusForbidden,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.Cfg = setting.NewCfg()
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
hs.accesscontrolService = actest.FakeService{}
hs.userService = &usertest.FakeUserService{
ExpectedSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 0},
}
})
req := webtest.RequestWithSignedInUser(server.NewPostRequest("/api/orgs", strings.NewReader(`{"name": "test"}`)), authedUserWithPermissions(1, 0, tt.permission))
res, err := server.SendJSON(req)
require.NoError(t, err)
assert.Equal(t, tt.expectedCode, res.StatusCode)
require.NoError(t, res.Body.Close())
})
}
}
func TestAPIEndpoint_DeleteOrgs(t *testing.T) {
type testCase struct {
desc string
permission []accesscontrol.Permission
expectedCode int
}
tests := []testCase{
{
desc: "should be able to delete org with correct permission",
permission: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsDelete}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to delete org without correct permission",
permission: []accesscontrol.Permission{},
expectedCode: http.StatusForbidden,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
expectedIdentity := &authn.Identity{
OrgID: 1,
Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permission),
},
}
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.Cfg = setting.NewCfg()
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: &user.SignedInUser{OrgID: 1}}
hs.accesscontrolService = actest.FakeService{ExpectedPermissions: tt.permission}
hs.authnService = &authntest.FakeService{}
hs.authnService = &authntest.FakeService{
ExpectedIdentity: expectedIdentity,
}
})
req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodDelete, "/api/orgs/1", nil), userWithPermissions(2, nil))
res, err := server.Send(req)
require.NoError(t, err)
assert.Equal(t, tt.expectedCode, res.StatusCode)
require.NoError(t, res.Body.Close())
})
}
}
func TestAPIEndpoint_GetOrg(t *testing.T) {
type testCase struct {
desc string
permissions []accesscontrol.Permission
expectedCode int
}
tests := []testCase{
{
desc: "should be able to fetch org with correct permissions",
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsRead}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to fetch org without correct permissions",
expectedCode: http.StatusForbidden,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
expectedIdentity := &authn.Identity{
ID: authn.MustParseNamespaceID("user:1"),
OrgID: 1,
Permissions: map[int64]map[string][]string{
0: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions),
1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions),
},
}
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.Cfg = setting.NewCfg()
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: &user.SignedInUser{OrgID: 1}}
hs.accesscontrolService = &actest.FakeService{ExpectedPermissions: tt.permissions}
hs.authnService = &authntest.FakeService{
ExpectedIdentity: expectedIdentity,
}
})
verify := func(path string) {
req := webtest.RequestWithSignedInUser(server.NewGetRequest(path), authedUserWithPermissions(1, 1, tt.permissions))
res, err := server.Send(req)
require.NoError(t, err)
assert.Equal(t, tt.expectedCode, res.StatusCode)
if tt.expectedCode != res.StatusCode {
t.Log("Failed on path", path)
}
require.NoError(t, res.Body.Close())
}
// search orgs
verify("/api/orgs")
// fetch by id
verify("/api/orgs/1")
// fetch by name
verify("/api/orgs/name/test")
})
}
}