Access Control: move features to Enterprise (#32640)
* Move db package WIP * Implement OSS access control * Register OSS access control * Fix linter error in tests * Fix linter error in evaluator * Simplify OSS tests * Optimize builtin roles * Chore: add comments to the exported functions * Remove init from ossaccesscontrol package (moved to ext) * Add access control as a dependency for http server * Modify middleware to receive fallback function * Middleware: refactor fallback function call * Move unused models to enterprise * Simplify AccessControl type * Chore: use bool IsDisabled() method instead of CanBeDisabled interface
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package ossaccesscontrol
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
)
|
||||
|
||||
var builtInRolesMap = map[string]accesscontrol.RoleDTO{
|
||||
"grafana:builtin:users:read:self": {
|
||||
Name: "grafana:builtin:users:read:self",
|
||||
Version: 1,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Permission: "users:read",
|
||||
Scope: "users:self",
|
||||
},
|
||||
{
|
||||
Permission: "users.tokens:list",
|
||||
Scope: "users:self",
|
||||
},
|
||||
{
|
||||
Permission: "users.teams:read",
|
||||
Scope: "users:self",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var builtInRoleGrants = map[string][]string{
|
||||
"Viewer": {
|
||||
"grafana:builtin:users:read:self",
|
||||
},
|
||||
}
|
||||
|
||||
func getBuiltInRole(role string) *accesscontrol.RoleDTO {
|
||||
var builtInRole accesscontrol.RoleDTO
|
||||
if r, ok := builtInRolesMap[role]; ok {
|
||||
// Do not modify builtInRoles
|
||||
builtInRole = r
|
||||
return &builtInRole
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package ossaccesscontrol
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/evaluator"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
// OSSAccessControlService is the service implementing role based access control.
|
||||
type OSSAccessControlService struct {
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
// Init initializes the OSSAccessControlService.
|
||||
func (ac *OSSAccessControlService) Init() error {
|
||||
ac.Log = log.New("accesscontrol")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ac *OSSAccessControlService) IsDisabled() bool {
|
||||
if ac.Cfg == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
_, exists := ac.Cfg.FeatureToggles["accesscontrol"]
|
||||
return !exists
|
||||
}
|
||||
|
||||
// Evaluate evaluates access to the given resource
|
||||
func (ac *OSSAccessControlService) Evaluate(ctx context.Context, user *models.SignedInUser, permission string, scope ...string) (bool, error) {
|
||||
return evaluator.Evaluate(ctx, ac, user, permission, scope...)
|
||||
}
|
||||
|
||||
// GetUserPermissions returns user permissions based on built-in roles
|
||||
func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user *models.SignedInUser, roles []string) ([]*accesscontrol.Permission, error) {
|
||||
permissions := make([]*accesscontrol.Permission, 0)
|
||||
for _, legacyRole := range roles {
|
||||
if builtInRoleNames, ok := builtInRoleGrants[legacyRole]; ok {
|
||||
for _, builtInRoleName := range builtInRoleNames {
|
||||
builtInRole := getBuiltInRole(builtInRoleName)
|
||||
if builtInRole == nil {
|
||||
continue
|
||||
}
|
||||
for _, p := range builtInRole.Permissions {
|
||||
permission := p
|
||||
permissions = append(permissions, &permission)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package ossaccesscontrol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func setupTestEnv(t testing.TB) *OSSAccessControlService {
|
||||
t.Helper()
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
cfg.FeatureToggles = map[string]bool{"accesscontrol": true}
|
||||
|
||||
ac := OSSAccessControlService{
|
||||
Cfg: cfg,
|
||||
Log: log.New("accesscontrol-test"),
|
||||
}
|
||||
|
||||
err := ac.Init()
|
||||
require.NoError(t, err)
|
||||
return &ac
|
||||
}
|
||||
|
||||
type evaluatingPermissionsTestCase struct {
|
||||
desc string
|
||||
user userTestCase
|
||||
endpoints []endpointTestCase
|
||||
evalResult bool
|
||||
}
|
||||
|
||||
type userTestCase struct {
|
||||
name string
|
||||
orgRole models.RoleType
|
||||
isGrafanaAdmin bool
|
||||
}
|
||||
|
||||
type endpointTestCase struct {
|
||||
permission string
|
||||
scope []string
|
||||
}
|
||||
|
||||
func TestEvaluatingPermissions(t *testing.T) {
|
||||
testCases := []evaluatingPermissionsTestCase{
|
||||
{
|
||||
desc: "should successfully evaluate access to the endpoint",
|
||||
user: userTestCase{
|
||||
name: "testuser",
|
||||
orgRole: models.ROLE_EDITOR,
|
||||
isGrafanaAdmin: false,
|
||||
},
|
||||
endpoints: []endpointTestCase{
|
||||
{permission: "users.teams:read", scope: []string{"users:self"}},
|
||||
{permission: "users:read", scope: []string{"users:self"}},
|
||||
},
|
||||
evalResult: true,
|
||||
},
|
||||
{
|
||||
desc: "should restrict access to the unauthorized endpoints",
|
||||
user: userTestCase{
|
||||
name: "testuser",
|
||||
orgRole: models.ROLE_VIEWER,
|
||||
isGrafanaAdmin: false,
|
||||
},
|
||||
endpoints: []endpointTestCase{
|
||||
{permission: "users:create", scope: []string{"users"}},
|
||||
},
|
||||
evalResult: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
ac := setupTestEnv(t)
|
||||
t.Cleanup(registry.ClearOverrides)
|
||||
|
||||
user := &models.SignedInUser{
|
||||
UserId: 1,
|
||||
OrgId: 1,
|
||||
Name: tc.user.name,
|
||||
OrgRole: tc.user.orgRole,
|
||||
IsGrafanaAdmin: tc.user.isGrafanaAdmin,
|
||||
}
|
||||
|
||||
for _, endpoint := range tc.endpoints {
|
||||
result, err := ac.Evaluate(context.Background(), user, endpoint.permission, endpoint.scope...)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.evalResult, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user