mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AccessControl: Add a mock (#38515)
This commit is contained in:
parent
14a0519338
commit
f9273d0d37
@ -1,7 +1,6 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -16,6 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/auth/jwt"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
@ -229,33 +229,6 @@ func (s *fakeRenderService) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ accesscontrol.AccessControl = new(fakeAccessControl)
|
||||
|
||||
type fakeAccessControl struct {
|
||||
isDisabled bool
|
||||
permissions []*accesscontrol.Permission
|
||||
}
|
||||
|
||||
func (f *fakeAccessControl) Evaluate(ctx context.Context, user *models.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
permissions, err := f.GetUserPermissions(ctx, user)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return evaluator.Evaluate(accesscontrol.GroupScopesByAction(permissions))
|
||||
}
|
||||
|
||||
func (f *fakeAccessControl) GetUserPermissions(ctx context.Context, user *models.SignedInUser) ([]*accesscontrol.Permission, error) {
|
||||
return f.permissions, nil
|
||||
}
|
||||
|
||||
func (f *fakeAccessControl) IsDisabled() bool {
|
||||
return f.isDisabled
|
||||
}
|
||||
|
||||
func (f *fakeAccessControl) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupAccessControlScenarioContext(t *testing.T, cfg *setting.Cfg, url string, permissions []*accesscontrol.Permission) (*scenarioContext, *HTTPServer) {
|
||||
cfg.FeatureToggles = make(map[string]bool)
|
||||
cfg.FeatureToggles["accesscontrol"] = true
|
||||
@ -263,7 +236,7 @@ func setupAccessControlScenarioContext(t *testing.T, cfg *setting.Cfg, url strin
|
||||
hs := &HTTPServer{
|
||||
Cfg: cfg,
|
||||
RouteRegister: routing.NewRouteRegister(),
|
||||
AccessControl: &fakeAccessControl{permissions: permissions},
|
||||
AccessControl: accesscontrolmock.New().WithPermissions(permissions),
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
@ -13,6 +12,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
)
|
||||
|
||||
type middlewareTestCase struct {
|
||||
@ -27,26 +27,24 @@ func TestMiddleware(t *testing.T) {
|
||||
tests := []middlewareTestCase{
|
||||
{
|
||||
desc: "should use fallback if access control is disabled",
|
||||
ac: fakeAccessControl{isDisabled: true},
|
||||
ac: mock.New().WithDisabled(),
|
||||
expectFallback: true,
|
||||
expectEndpoint: true,
|
||||
},
|
||||
{
|
||||
desc: "should pass middleware for correct permissions",
|
||||
ac: fakeAccessControl{
|
||||
isDisabled: false,
|
||||
permissions: []*accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}},
|
||||
},
|
||||
ac: mock.New().WithPermissions(
|
||||
[]*accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}},
|
||||
),
|
||||
evaluator: accesscontrol.EvalPermission("users:read", "users:*"),
|
||||
expectFallback: false,
|
||||
expectEndpoint: true,
|
||||
},
|
||||
{
|
||||
desc: "should not reach endpoint when missing permissions",
|
||||
ac: fakeAccessControl{
|
||||
isDisabled: false,
|
||||
permissions: []*accesscontrol.Permission{{Action: "users:read", Scope: "users:1"}},
|
||||
},
|
||||
ac: mock.New().WithPermissions(
|
||||
[]*accesscontrol.Permission{{Action: "users:read", Scope: "users:1"}},
|
||||
),
|
||||
evaluator: accesscontrol.EvalPermission("users:read", "users:*"),
|
||||
expectFallback: false,
|
||||
expectEndpoint: false,
|
||||
@ -95,27 +93,3 @@ func contextProvider() macaron.Handler {
|
||||
c.Map(reqCtx)
|
||||
}
|
||||
}
|
||||
|
||||
var _ accesscontrol.AccessControl = new(fakeAccessControl)
|
||||
|
||||
type fakeAccessControl struct {
|
||||
isDisabled bool
|
||||
permissions []*accesscontrol.Permission
|
||||
}
|
||||
|
||||
func (f fakeAccessControl) Evaluate(ctx context.Context, user *models.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
permissions, _ := f.GetUserPermissions(ctx, user)
|
||||
return evaluator.Evaluate(accesscontrol.GroupScopesByAction(permissions))
|
||||
}
|
||||
|
||||
func (f fakeAccessControl) GetUserPermissions(ctx context.Context, user *models.SignedInUser) ([]*accesscontrol.Permission, error) {
|
||||
return f.permissions, nil
|
||||
}
|
||||
|
||||
func (f fakeAccessControl) IsDisabled() bool {
|
||||
return f.isDisabled
|
||||
}
|
||||
|
||||
func (f fakeAccessControl) DeclareFixedRoles(registration ...accesscontrol.RoleRegistration) error {
|
||||
return nil
|
||||
}
|
||||
|
152
pkg/services/accesscontrol/mock/mock.go
Normal file
152
pkg/services/accesscontrol/mock/mock.go
Normal file
@ -0,0 +1,152 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
)
|
||||
|
||||
type fullAccessControl interface {
|
||||
accesscontrol.AccessControl
|
||||
GetUserBuiltInRoles(user *models.SignedInUser) []string
|
||||
RegisterFixedRoles() error
|
||||
}
|
||||
|
||||
type Calls struct {
|
||||
Evaluate []interface{}
|
||||
GetUserPermissions []interface{}
|
||||
IsDisabled []interface{}
|
||||
DeclareFixedRoles []interface{}
|
||||
GetUserBuiltInRoles []interface{}
|
||||
RegisterFixedRoles []interface{}
|
||||
}
|
||||
|
||||
type Mock struct {
|
||||
// Unless an override is provided, permissions will be returned by GetUserPermissions
|
||||
permissions []*accesscontrol.Permission
|
||||
// Unless an override is provided, disabled will be returned by IsDisabled
|
||||
disabled bool
|
||||
// Unless an override is provided, builtInRoles will be returned by GetUserBuiltInRoles
|
||||
builtInRoles []string
|
||||
|
||||
// Track the list of calls
|
||||
Calls Calls
|
||||
|
||||
// Override functions
|
||||
EvaluateFunc func(context.Context, *models.SignedInUser, accesscontrol.Evaluator) (bool, error)
|
||||
GetUserPermissionsFunc func(context.Context, *models.SignedInUser) ([]*accesscontrol.Permission, error)
|
||||
IsDisabledFunc func() bool
|
||||
DeclareFixedRolesFunc func(...accesscontrol.RoleRegistration) error
|
||||
GetUserBuiltInRolesFunc func(user *models.SignedInUser) []string
|
||||
RegisterFixedRolesFunc func() error
|
||||
}
|
||||
|
||||
type MockOptions func(*Mock)
|
||||
|
||||
// Ensure the mock stays in line with the interface
|
||||
var _ fullAccessControl = New()
|
||||
|
||||
func New() *Mock {
|
||||
mock := &Mock{
|
||||
Calls: Calls{},
|
||||
disabled: false,
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
builtInRoles: []string{},
|
||||
}
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
func (m Mock) WithPermissions(permissions []*accesscontrol.Permission) *Mock {
|
||||
m.permissions = permissions
|
||||
return &m
|
||||
}
|
||||
|
||||
func (m Mock) WithDisabled() *Mock {
|
||||
m.disabled = true
|
||||
return &m
|
||||
}
|
||||
|
||||
func (m Mock) WithBuiltInRoles(builtInRoles []string) *Mock {
|
||||
m.builtInRoles = builtInRoles
|
||||
return &m
|
||||
}
|
||||
|
||||
// Evaluate evaluates access to the given resource.
|
||||
// This mock uses GetUserPermissions to then call the evaluator Evaluate function.
|
||||
func (m *Mock) Evaluate(ctx context.Context, user *models.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
m.Calls.Evaluate = append(m.Calls.Evaluate, []interface{}{ctx, user, evaluator})
|
||||
// Use override if provided
|
||||
if m.EvaluateFunc != nil {
|
||||
return m.EvaluateFunc(ctx, user, evaluator)
|
||||
}
|
||||
// Otherwise perform an actual evaluation of the permissions
|
||||
permissions, err := m.GetUserPermissions(ctx, user)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return evaluator.Evaluate(accesscontrol.GroupScopesByAction(permissions))
|
||||
}
|
||||
|
||||
// GetUserPermissions returns user permissions.
|
||||
// This mock return m.permissions unless an override is provided.
|
||||
func (m *Mock) GetUserPermissions(ctx context.Context, user *models.SignedInUser) ([]*accesscontrol.Permission, error) {
|
||||
m.Calls.GetUserPermissions = append(m.Calls.GetUserPermissions, []interface{}{ctx, user})
|
||||
// Use override if provided
|
||||
if m.GetUserPermissionsFunc != nil {
|
||||
return m.GetUserPermissionsFunc(ctx, user)
|
||||
}
|
||||
// Otherwise return the Permissions list
|
||||
return m.permissions, nil
|
||||
}
|
||||
|
||||
// Middleware checks if service disabled or not to switch to fallback authorization.
|
||||
// This mock return m.disabled unless an override is provided.
|
||||
func (m *Mock) IsDisabled() bool {
|
||||
m.Calls.IsDisabled = append(m.Calls.IsDisabled, struct{}{})
|
||||
// Use override if provided
|
||||
if m.IsDisabledFunc != nil {
|
||||
return m.IsDisabledFunc()
|
||||
}
|
||||
// Otherwise return the Disabled bool
|
||||
return m.disabled
|
||||
}
|
||||
|
||||
// DeclareFixedRoles allow the caller to declare, to the service, fixed roles and their
|
||||
// assignments to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin"
|
||||
// This mock returns no error unless an override is provided.
|
||||
func (m *Mock) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistration) error {
|
||||
m.Calls.DeclareFixedRoles = append(m.Calls.DeclareFixedRoles, []interface{}{registrations})
|
||||
// Use override if provided
|
||||
if m.DeclareFixedRolesFunc != nil {
|
||||
return m.DeclareFixedRolesFunc(registrations...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserBuiltInRoles returns the list of organizational roles ("Viewer", "Editor", "Admin")
|
||||
// or "Grafana Admin" associated to a user
|
||||
// This mock returns m.builtInRoles unless an override is provided.
|
||||
func (m *Mock) GetUserBuiltInRoles(user *models.SignedInUser) []string {
|
||||
m.Calls.GetUserBuiltInRoles = append(m.Calls.GetUserBuiltInRoles, []interface{}{user})
|
||||
|
||||
// Use override if provided
|
||||
if m.GetUserBuiltInRolesFunc != nil {
|
||||
return m.GetUserBuiltInRolesFunc(user)
|
||||
}
|
||||
|
||||
// Otherwise return the BuiltInRoles list
|
||||
return m.builtInRoles
|
||||
}
|
||||
|
||||
// RegisterFixedRoles registers all roles declared to AccessControl
|
||||
// This mock returns no error unless an override is provided.
|
||||
func (m *Mock) RegisterFixedRoles() error {
|
||||
m.Calls.RegisterFixedRoles = append(m.Calls.RegisterFixedRoles, []struct{}{})
|
||||
// Use override if provided
|
||||
if m.RegisterFixedRolesFunc != nil {
|
||||
return m.RegisterFixedRolesFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user