mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Access control: Update evaluator to authorize when at least one of the scopes is a match (#33393)
This commit is contained in:
parent
43bfa2801c
commit
5bf6d7dad8
@ -9,18 +9,24 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Evaluate evaluates access to the given resource, using provided AccessControl instance
|
// Evaluate evaluates access to the given resource, using provided AccessControl instance.
|
||||||
func Evaluate(ctx context.Context, ac accesscontrol.AccessControl, user *models.SignedInUser, permission string, scope ...string) (bool, error) {
|
// Scopes are evaluated with an `OR` relationship.
|
||||||
res, err := ac.GetUserPermissions(ctx, user)
|
func Evaluate(ctx context.Context, ac accesscontrol.AccessControl, user *models.SignedInUser, action string, scope ...string) (bool, error) {
|
||||||
|
userPermissions, err := ac.GetUserPermissions(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, dbScopes := extractPermission(res, permission)
|
ok, dbScopes := extractScopes(userPermissions, action)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
for _, s := range scope {
|
|
||||||
|
return evaluateScope(dbScopes, scope...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func evaluateScope(dbScopes map[string]struct{}, targetScopes ...string) (bool, error) {
|
||||||
|
for _, s := range targetScopes {
|
||||||
var match bool
|
var match bool
|
||||||
for dbScope := range dbScopes {
|
for dbScope := range dbScopes {
|
||||||
rule, err := glob.Compile(dbScope, ':', '/')
|
rule, err := glob.Compile(dbScope, ':', '/')
|
||||||
@ -30,19 +36,15 @@ func Evaluate(ctx context.Context, ac accesscontrol.AccessControl, user *models.
|
|||||||
|
|
||||||
match = rule.Match(s)
|
match = rule.Match(s)
|
||||||
if match {
|
if match {
|
||||||
break
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !match {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractPermission(permissions []*accesscontrol.Permission, permission string) (bool, map[string]struct{}) {
|
func extractScopes(permissions []*accesscontrol.Permission, targetAction string) (bool, map[string]struct{}) {
|
||||||
scopes := map[string]struct{}{}
|
scopes := map[string]struct{}{}
|
||||||
ok := false
|
ok := false
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ func extractPermission(permissions []*accesscontrol.Permission, permission strin
|
|||||||
if p == nil {
|
if p == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.Action == permission {
|
if p.Action == targetAction {
|
||||||
ok = true
|
ok = true
|
||||||
scopes[p.Scope] = struct{}{}
|
scopes[p.Scope] = struct{}{}
|
||||||
}
|
}
|
||||||
|
65
pkg/services/accesscontrol/evaluator/evaluator_test.go
Normal file
65
pkg/services/accesscontrol/evaluator/evaluator_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package evaluator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtractPermission(t *testing.T) {
|
||||||
|
const targetPermission = "permissions:create"
|
||||||
|
userPermissions := []*accesscontrol.Permission{
|
||||||
|
{
|
||||||
|
Action: "permissions:create",
|
||||||
|
Scope: "teams:*/permissions:*",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: "permissions:remove",
|
||||||
|
Scope: "permissions:*",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expectedScopes := map[string]struct{}{
|
||||||
|
"teams:*/permissions:*": {},
|
||||||
|
}
|
||||||
|
ok, scopes := extractScopes(userPermissions, targetPermission)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, expectedScopes, scopes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEvaluatePermissions(t *testing.T) {
|
||||||
|
scopes := map[string]struct{}{
|
||||||
|
"teams:*/permissions:*": {},
|
||||||
|
"users:*": {},
|
||||||
|
"permissions:delegate": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := evaluateScope(scopes, "teams:1/permissions:delegate")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEvaluatePermissions_WhenAtLeastOneScopeIsMatched_ReturnsTrue(t *testing.T) {
|
||||||
|
scopes := map[string]struct{}{
|
||||||
|
"teams:*/permissions:*": {},
|
||||||
|
"users:*": {},
|
||||||
|
"permissions:delegate": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := evaluateScope(scopes, "global:admin", "permissions:delegate")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEvaluatePermissions_WhenNoMatchFound_ReturnsFalse(t *testing.T) {
|
||||||
|
scopes := map[string]struct{}{
|
||||||
|
"teams:*/permissions:*": {},
|
||||||
|
"users:*": {},
|
||||||
|
"permissions:delegate": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := evaluateScope(scopes, "teams1/permissions:delegate")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, ok)
|
||||||
|
}
|
@ -18,7 +18,7 @@ var ldapAdminReadRole = RoleDTO{
|
|||||||
var ldapAdminEditRole = RoleDTO{
|
var ldapAdminEditRole = RoleDTO{
|
||||||
Name: ldapAdminEdit,
|
Name: ldapAdminEdit,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Permissions: concat(ldapAdminReadRole.Permissions, []Permission{
|
Permissions: ConcatPermissions(ldapAdminReadRole.Permissions, []Permission{
|
||||||
{
|
{
|
||||||
Action: ActionLDAPUsersSync,
|
Action: ActionLDAPUsersSync,
|
||||||
},
|
},
|
||||||
@ -39,7 +39,7 @@ var orgsAdminReadRole = RoleDTO{
|
|||||||
var orgsAdminEditRole = RoleDTO{
|
var orgsAdminEditRole = RoleDTO{
|
||||||
Name: orgsAdminEdit,
|
Name: orgsAdminEdit,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Permissions: concat(orgsAdminReadRole.Permissions, []Permission{
|
Permissions: ConcatPermissions(orgsAdminReadRole.Permissions, []Permission{
|
||||||
{
|
{
|
||||||
Action: ActionOrgUsersAdd,
|
Action: ActionOrgUsersAdd,
|
||||||
Scope: ScopeOrgAllUsersAll,
|
Scope: ScopeOrgAllUsersAll,
|
||||||
@ -69,7 +69,7 @@ var orgsCurrentReadRole = RoleDTO{
|
|||||||
var orgsCurrentEditRole = RoleDTO{
|
var orgsCurrentEditRole = RoleDTO{
|
||||||
Name: orgsCurrentEdit,
|
Name: orgsCurrentEdit,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Permissions: concat(orgsCurrentReadRole.Permissions, []Permission{
|
Permissions: ConcatPermissions(orgsCurrentReadRole.Permissions, []Permission{
|
||||||
{
|
{
|
||||||
Action: ActionOrgUsersAdd,
|
Action: ActionOrgUsersAdd,
|
||||||
Scope: ScopeOrgCurrentUsersAll,
|
Scope: ScopeOrgCurrentUsersAll,
|
||||||
@ -111,7 +111,7 @@ var usersAdminReadRole = RoleDTO{
|
|||||||
var usersAdminEditRole = RoleDTO{
|
var usersAdminEditRole = RoleDTO{
|
||||||
Name: usersAdminEdit,
|
Name: usersAdminEdit,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Permissions: concat(usersAdminReadRole.Permissions, []Permission{
|
Permissions: ConcatPermissions(usersAdminReadRole.Permissions, []Permission{
|
||||||
{
|
{
|
||||||
Action: ActionUsersPasswordUpdate,
|
Action: ActionUsersPasswordUpdate,
|
||||||
Scope: ScopeUsersAll,
|
Scope: ScopeUsersAll,
|
||||||
@ -205,7 +205,7 @@ var PredefinedRoleGrants = map[string][]string{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func concat(permissions ...[]Permission) []Permission {
|
func ConcatPermissions(permissions ...[]Permission) []Permission {
|
||||||
if permissions == nil {
|
if permissions == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func TestPredefinedRoleGrants(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConcat(t *testing.T) {
|
func TestConcatPermissions(t *testing.T) {
|
||||||
perms1 := []Permission{
|
perms1 := []Permission{
|
||||||
{
|
{
|
||||||
Action: "test",
|
Action: "test",
|
||||||
@ -67,6 +67,6 @@ func TestConcat(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
perms := concat(perms1, perms2)
|
perms := ConcatPermissions(perms1, perms2)
|
||||||
assert.ElementsMatch(t, perms, expected)
|
assert.ElementsMatch(t, perms, expected)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user