mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 20:12:22 +08:00

* add action set resolver * rename variables * some fixes and some tests * more tests * more tests, and put action set storing behind a feature toggle * undo change from cfg to feature mgmt - will cover it in a separate PR due to the amount of test changes * fix dependency cycle, update some tests * add one more test * fix for feature toggle check not being set on test configs * linting fixes * check that action set name can be split nicely * clean up tests by turning GetActionSetNames into a function * undo accidental change * test fix * more test fixes
197 lines
7.3 KiB
Go
197 lines
7.3 KiB
Go
package acimpl_test
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
func TestAccessControl_Evaluate(t *testing.T) {
|
|
type testCase struct {
|
|
desc string
|
|
user user.SignedInUser
|
|
evaluator accesscontrol.Evaluator
|
|
resolverPrefix string
|
|
expected bool
|
|
expectedErr error
|
|
scopeResolver accesscontrol.ScopeAttributeResolver
|
|
actionSets map[string][]string
|
|
}
|
|
|
|
tests := []testCase{
|
|
{
|
|
desc: "expect user to have access when correct permission is stored on user",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {accesscontrol.ActionTeamsWrite: {"teams:*"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalPermission(accesscontrol.ActionTeamsWrite, "teams:id:1"),
|
|
expected: true,
|
|
},
|
|
{
|
|
desc: "expect user to not have access without required permissions",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {accesscontrol.ActionTeamsWrite: {"teams:*"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalPermission(accesscontrol.ActionOrgUsersWrite, "users:id:1"),
|
|
expected: false,
|
|
},
|
|
{
|
|
desc: "expect user to have access when resolver translate scope",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {accesscontrol.ActionTeamsWrite: {"another:scope"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalPermission(accesscontrol.ActionTeamsWrite, "teams:id:1"),
|
|
resolverPrefix: "teams:id:",
|
|
scopeResolver: accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
|
return []string{"another:scope"}, nil
|
|
}),
|
|
expected: true,
|
|
},
|
|
{
|
|
desc: "expect user to have access when resolver translates actions to action sets",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {"folders:edit": {"folders:uid:test_folder"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, "folders:uid:test_folder"),
|
|
actionSets: map[string][]string{
|
|
"folders:edit": {dashboards.ActionFoldersWrite, dashboards.ActionFoldersRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsRead},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
desc: "expect user to have access when resolver translates scopes, as well as expands actions to action sets",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {"folders:edit": {"folders:uid:test_folder"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalPermission(dashboards.ActionDashboardsRead, "dashboards:uid:test_dashboard"),
|
|
actionSets: map[string][]string{
|
|
"folders:edit": {dashboards.ActionFoldersWrite, dashboards.ActionFoldersRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsRead},
|
|
},
|
|
resolverPrefix: "dashboards:uid:",
|
|
scopeResolver: accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
|
return []string{"folders:uid:test_folder"}, nil
|
|
}),
|
|
expected: true,
|
|
},
|
|
{
|
|
desc: "expect user to have access with eval all evaluator when resolver translates scopes, as well as expands actions to action sets",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {"folders:edit": {"folders:uid:test_folder"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalAll(
|
|
accesscontrol.EvalPermission(dashboards.ActionFoldersRead, "folders:uid:test_folder"),
|
|
accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, "dashboards:uid:test_dashboard"),
|
|
),
|
|
actionSets: map[string][]string{
|
|
"folders:edit": {dashboards.ActionFoldersWrite, dashboards.ActionFoldersRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsRead},
|
|
},
|
|
resolverPrefix: "dashboards:uid:",
|
|
scopeResolver: accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
|
return []string{"folders:uid:test_folder"}, nil
|
|
}),
|
|
expected: true,
|
|
},
|
|
{
|
|
desc: "expect user to not have access with eval all evaluator with resolvers when not all permissions resolve to permissions that the user has",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {"folders:edit": {"folders:uid:test_folder"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalAll(
|
|
accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, "datasources:uid:test_ds"),
|
|
accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, "dashboards:uid:test_dashboard"),
|
|
),
|
|
actionSets: map[string][]string{
|
|
"folders:edit": {dashboards.ActionFoldersWrite, dashboards.ActionFoldersRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsRead},
|
|
},
|
|
resolverPrefix: "dashboards:uid:",
|
|
scopeResolver: accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
|
return []string{"folders:uid:test_folder"}, nil
|
|
}),
|
|
expected: false,
|
|
},
|
|
{
|
|
desc: "expect user to have access with eval any evaluator when resolver translates scopes, as well as expands actions to action sets",
|
|
user: user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {"folders:edit": {"folders:uid:test_folder"}},
|
|
},
|
|
},
|
|
evaluator: accesscontrol.EvalAny(
|
|
accesscontrol.EvalPermission(dashboards.ActionDashboardsDelete, "dashboards:uid:test_dashboard"),
|
|
accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, "dashboards:uid:test_dashboard"),
|
|
),
|
|
actionSets: map[string][]string{
|
|
"folders:edit": {dashboards.ActionFoldersWrite, dashboards.ActionFoldersRead, dashboards.ActionDashboardsWrite, dashboards.ActionDashboardsRead},
|
|
},
|
|
resolverPrefix: "dashboards:uid:",
|
|
scopeResolver: accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
|
return []string{"folders:uid:test_folder"}, nil
|
|
}),
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
cfg := setting.NewCfg()
|
|
cfg.IsFeatureToggleEnabled = func(ft string) bool {
|
|
return ft == featuremgmt.FlagAccessActionSets
|
|
}
|
|
ac := acimpl.ProvideAccessControl(cfg)
|
|
|
|
if tt.scopeResolver != nil {
|
|
ac.RegisterScopeAttributeResolver(tt.resolverPrefix, tt.scopeResolver)
|
|
}
|
|
|
|
if tt.actionSets != nil {
|
|
actionSetResolver := resourcepermissions.NewActionSetService(ac)
|
|
for actionSet, actions := range tt.actionSets {
|
|
splitActionSet := strings.Split(actionSet, ":")
|
|
actionSetResolver.StoreActionSet(splitActionSet[0], splitActionSet[1], actions)
|
|
}
|
|
ac.RegisterActionResolver(actionSetResolver)
|
|
}
|
|
|
|
hasAccess, err := ac.Evaluate(context.Background(), &tt.user, tt.evaluator)
|
|
assert.Equal(t, tt.expected, hasAccess)
|
|
if tt.expectedErr != nil {
|
|
assert.Equal(t, tt.expectedErr, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|