mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
parent
eb4c3a4485
commit
0ace9695a6
@ -14,13 +14,9 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol/database"
|
|
||||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
@ -110,7 +106,9 @@ func TestApi_getDescription(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
_, server, _ := setupTestEnvironment(t, &models.SignedInUser{}, tt.permissions, tt.options)
|
service, _ := setupTestEnvironment(t, tt.permissions, tt.options)
|
||||||
|
server := setupTestServer(t, &models.SignedInUser{OrgId: 1}, service)
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/description", tt.options.Resource), nil)
|
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/description", tt.options.Resource), nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
@ -151,7 +149,8 @@ func TestApi_getPermissions(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
service, server, sql := setupTestEnvironment(t, &models.SignedInUser{OrgId: 1}, tt.permissions, testOptions)
|
service, sql := setupTestEnvironment(t, tt.permissions, testOptions)
|
||||||
|
server := setupTestServer(t, &models.SignedInUser{OrgId: 1}, service)
|
||||||
|
|
||||||
// seed team 1 with "Edit" permission on dashboard 1
|
// seed team 1 with "Edit" permission on dashboard 1
|
||||||
team, err := sql.CreateTeam("test", "test@test.com", 1)
|
team, err := sql.CreateTeam("test", "test@test.com", 1)
|
||||||
@ -245,7 +244,8 @@ func TestApi_setBuiltinRolePermission(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
_, server, _ := setupTestEnvironment(t, &models.SignedInUser{OrgId: 1}, tt.permissions, testOptions)
|
service, _ := setupTestEnvironment(t, tt.permissions, testOptions)
|
||||||
|
server := setupTestServer(t, &models.SignedInUser{OrgId: 1}, service)
|
||||||
|
|
||||||
recorder := setPermission(t, server, testOptions.Resource, tt.resourceID, tt.permission, "builtInRoles", tt.builtInRole)
|
recorder := setPermission(t, server, testOptions.Resource, tt.resourceID, tt.permission, "builtInRoles", tt.builtInRole)
|
||||||
assert.Equal(t, tt.expectedStatus, recorder.Code)
|
assert.Equal(t, tt.expectedStatus, recorder.Code)
|
||||||
@ -318,7 +318,8 @@ func TestApi_setTeamPermission(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
_, server, sql := setupTestEnvironment(t, &models.SignedInUser{OrgId: 1}, tt.permissions, testOptions)
|
service, sql := setupTestEnvironment(t, tt.permissions, testOptions)
|
||||||
|
server := setupTestServer(t, &models.SignedInUser{OrgId: 1}, service)
|
||||||
|
|
||||||
// seed team
|
// seed team
|
||||||
_, err := sql.CreateTeam("test", "test@test.com", 1)
|
_, err := sql.CreateTeam("test", "test@test.com", 1)
|
||||||
@ -396,9 +397,10 @@ func TestApi_setUserPermission(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
_, server, sql := setupTestEnvironment(t, &models.SignedInUser{OrgId: 1}, tt.permissions, testOptions)
|
service, sql := setupTestEnvironment(t, tt.permissions, testOptions)
|
||||||
|
server := setupTestServer(t, &models.SignedInUser{OrgId: 1}, service)
|
||||||
|
|
||||||
// seed team
|
// seed user
|
||||||
_, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "test", OrgId: 1})
|
_, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "test", OrgId: 1})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -416,19 +418,12 @@ func TestApi_setUserPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupTestEnvironment(t *testing.T, user *models.SignedInUser, permissions []*accesscontrol.Permission, ops Options) (*Service, *web.Mux, *sqlstore.SQLStore) {
|
func setupTestServer(t *testing.T, user *models.SignedInUser, service *Service) *web.Mux {
|
||||||
sql := sqlstore.InitTestDB(t)
|
|
||||||
store := database.ProvideService(sql)
|
|
||||||
|
|
||||||
service, err := New(ops, routing.NewRouteRegister(), accesscontrolmock.New().WithPermissions(permissions), store)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
server := web.New()
|
server := web.New()
|
||||||
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
|
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
|
||||||
server.Use(contextProvider(&testContext{user}))
|
server.Use(contextProvider(&testContext{user}))
|
||||||
service.api.router.Register(server)
|
service.api.router.Register(server)
|
||||||
|
return server
|
||||||
return service, server, sql
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type testContext struct {
|
type testContext struct {
|
||||||
|
@ -19,11 +19,16 @@ type Options struct {
|
|||||||
// PermissionsToAction is a map of friendly named permissions and what access control actions they should generate.
|
// PermissionsToAction is a map of friendly named permissions and what access control actions they should generate.
|
||||||
// E.g. Edit permissions should generate dashboards:read, dashboards:write and dashboards:delete
|
// E.g. Edit permissions should generate dashboards:read, dashboards:write and dashboards:delete
|
||||||
PermissionsToActions map[string][]string
|
PermissionsToActions map[string][]string
|
||||||
|
|
||||||
// ReaderRoleName is the display name for the generated fixed reader role
|
// ReaderRoleName is the display name for the generated fixed reader role
|
||||||
ReaderRoleName string
|
ReaderRoleName string
|
||||||
// WriterRoleName is the display name for the generated fixed writer role
|
// WriterRoleName is the display name for the generated fixed writer role
|
||||||
WriterRoleName string
|
WriterRoleName string
|
||||||
// RoleGroup is the group name for the generated fixed roles
|
// RoleGroup is the group name for the generated fixed roles
|
||||||
RoleGroup string
|
RoleGroup string
|
||||||
|
// OnSetUser if configured will be called each time a permission is set for a user
|
||||||
|
OnSetUser func(ctx context.Context, orgID, userID int64, resourceID, permission string) error
|
||||||
|
// OnSetTeam if configured will be called each time a permission is set for a team
|
||||||
|
OnSetTeam func(ctx context.Context, orgID, teamID int64, resourceID, permission string) error
|
||||||
|
// OnSetBuiltInRole if configured will be called each time a permission is set for a built-in role
|
||||||
|
OnSetBuiltInRole func(ctx context.Context, orgID int64, builtInRole, resourceID, permission string) error
|
||||||
}
|
}
|
||||||
|
@ -90,11 +90,21 @@ func (s *Service) SetUserPermission(ctx context.Context, orgID, userID int64, re
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.store.SetUserResourcePermission(ctx, orgID, userID, accesscontrol.SetResourcePermissionCommand{
|
permission, err := s.store.SetUserResourcePermission(ctx, orgID, userID, accesscontrol.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
Resource: s.options.Resource,
|
Resource: s.options.Resource,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.options.OnSetUser != nil {
|
||||||
|
if err := s.options.OnSetUser(ctx, orgID, userID, resourceID, s.MapActions(*permission)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
|
func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
|
||||||
@ -113,11 +123,21 @@ func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, re
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.store.SetTeamResourcePermission(ctx, orgID, teamID, accesscontrol.SetResourcePermissionCommand{
|
permission, err := s.store.SetTeamResourcePermission(ctx, orgID, teamID, accesscontrol.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
Resource: s.options.Resource,
|
Resource: s.options.Resource,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.options.OnSetTeam != nil {
|
||||||
|
if err := s.options.OnSetTeam(ctx, orgID, teamID, resourceID, s.MapActions(*permission)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole string, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
|
func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole string, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
|
||||||
@ -137,11 +157,21 @@ func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, bui
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.store.SetBuiltInResourcePermission(ctx, orgID, builtInRole, accesscontrol.SetResourcePermissionCommand{
|
permission, err := s.store.SetBuiltInResourcePermission(ctx, orgID, builtInRole, accesscontrol.SetResourcePermissionCommand{
|
||||||
Actions: actions,
|
Actions: actions,
|
||||||
ResourceID: resourceID,
|
ResourceID: resourceID,
|
||||||
Resource: s.options.Resource,
|
Resource: s.options.Resource,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.options.OnSetBuiltInRole != nil {
|
||||||
|
if err := s.options.OnSetBuiltInRole(ctx, orgID, builtInRole, resourceID, s.MapActions(*permission)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permission, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) MapActions(permission accesscontrol.ResourcePermission) string {
|
func (s *Service) MapActions(permission accesscontrol.ResourcePermission) string {
|
||||||
|
155
pkg/services/accesscontrol/resourcepermissions/service_test.go
Normal file
155
pkg/services/accesscontrol/resourcepermissions/service_test.go
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package resourcepermissions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol/database"
|
||||||
|
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type setUserPermissionTest struct {
|
||||||
|
desc string
|
||||||
|
callHook bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SetUserPermission(t *testing.T) {
|
||||||
|
tests := []setUserPermissionTest{
|
||||||
|
{
|
||||||
|
desc: "should call hook when updating user permissions",
|
||||||
|
callHook: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "should not call hook when updating user permissions",
|
||||||
|
callHook: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
service, sql := setupTestEnvironment(t, []*accesscontrol.Permission{}, Options{
|
||||||
|
Resource: "dashboards",
|
||||||
|
Assignments: Assignments{Users: true},
|
||||||
|
PermissionsToActions: nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
// seed user
|
||||||
|
user, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "test", OrgId: 1})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var hookCalled bool
|
||||||
|
if tt.callHook {
|
||||||
|
service.options.OnSetUser = func(ctx context.Context, orgID, userID int64, resourceID, permission string) error {
|
||||||
|
hookCalled = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = service.SetUserPermission(context.Background(), user.OrgId, user.Id, "1", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.callHook, hookCalled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type setTeamPermissionTest struct {
|
||||||
|
desc string
|
||||||
|
callHook bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SetTeamPermission(t *testing.T) {
|
||||||
|
tests := []setTeamPermissionTest{
|
||||||
|
{
|
||||||
|
desc: "should call hook when updating user permissions",
|
||||||
|
callHook: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "should not call hook when updating user permissions",
|
||||||
|
callHook: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
service, sql := setupTestEnvironment(t, []*accesscontrol.Permission{}, Options{
|
||||||
|
Resource: "dashboards",
|
||||||
|
Assignments: Assignments{Teams: true},
|
||||||
|
PermissionsToActions: nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
// seed team
|
||||||
|
team, err := sql.CreateTeam("test", "test@test.com", 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var hookCalled bool
|
||||||
|
if tt.callHook {
|
||||||
|
service.options.OnSetTeam = func(ctx context.Context, orgID, teamID int64, resourceID, permission string) error {
|
||||||
|
hookCalled = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = service.SetTeamPermission(context.Background(), team.OrgId, team.Id, "1", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.callHook, hookCalled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type setBuiltInRolePermissionTest struct {
|
||||||
|
desc string
|
||||||
|
callHook bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SetBuiltInRolePermission(t *testing.T) {
|
||||||
|
tests := []setBuiltInRolePermissionTest{
|
||||||
|
{
|
||||||
|
desc: "should call hook when updating user permissions",
|
||||||
|
callHook: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "should not call hook when updating user permissions",
|
||||||
|
callHook: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
service, _ := setupTestEnvironment(t, []*accesscontrol.Permission{}, Options{
|
||||||
|
Resource: "dashboards",
|
||||||
|
Assignments: Assignments{BuiltInRoles: true},
|
||||||
|
PermissionsToActions: nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
var hookCalled bool
|
||||||
|
if tt.callHook {
|
||||||
|
service.options.OnSetBuiltInRole = func(ctx context.Context, orgID int64, builtInRole, resourceID, permission string) error {
|
||||||
|
hookCalled = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := service.SetBuiltInRolePermission(context.Background(), 1, "Viewer", "1", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.callHook, hookCalled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTestEnvironment(t *testing.T, permissions []*accesscontrol.Permission, ops Options) (*Service, *sqlstore.SQLStore) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
sql := sqlstore.InitTestDB(t)
|
||||||
|
store := database.ProvideService(sql)
|
||||||
|
service, err := New(ops, routing.NewRouteRegister(), accesscontrolmock.New().WithPermissions(permissions), store)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return service, sql
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user