mirror of https://github.com/grafana/grafana
AccessControl: keyword scope resolution (#40229)
parent
26dda75db5
commit
fbc6febb0e
@ -0,0 +1,43 @@ |
||||
package accesscontrol |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/grafana/grafana/pkg/models" |
||||
) |
||||
|
||||
type KeywordScopeResolveFunc func(*models.SignedInUser) (string, error) |
||||
|
||||
// ScopeResolver contains a map of functions to resolve scope keywords such as `self` or `current` into `id` based scopes
|
||||
type ScopeResolver struct { |
||||
keywordResolvers map[string]KeywordScopeResolveFunc |
||||
} |
||||
|
||||
func NewScopeResolver() ScopeResolver { |
||||
return ScopeResolver{ |
||||
keywordResolvers: map[string]KeywordScopeResolveFunc{ |
||||
"orgs:current": resolveCurrentOrg, |
||||
"users:self": resolveUserSelf, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func resolveCurrentOrg(u *models.SignedInUser) (string, error) { |
||||
return Scope("orgs", "id", fmt.Sprintf("%v", u.OrgId)), nil |
||||
} |
||||
|
||||
func resolveUserSelf(u *models.SignedInUser) (string, error) { |
||||
return Scope("users", "id", fmt.Sprintf("%v", u.UserId)), nil |
||||
} |
||||
|
||||
// ResolveKeyword resolves scope with keywords such as `self` or `current` into `id` based scopes
|
||||
func (s *ScopeResolver) ResolveKeyword(user *models.SignedInUser, permission Permission) (*Permission, error) { |
||||
if fn, ok := s.keywordResolvers[permission.Scope]; ok { |
||||
resolvedScope, err := fn(user) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("could not resolve %v: %v", permission.Scope, err) |
||||
} |
||||
permission.Scope = resolvedScope |
||||
} |
||||
return &permission, nil |
||||
} |
@ -0,0 +1,55 @@ |
||||
package accesscontrol |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/grafana/grafana/pkg/models" |
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
var testUser = &models.SignedInUser{ |
||||
UserId: 2, |
||||
OrgId: 3, |
||||
OrgName: "TestOrg", |
||||
OrgRole: models.ROLE_VIEWER, |
||||
Login: "testUser", |
||||
Name: "Test User", |
||||
Email: "testuser@example.org", |
||||
} |
||||
|
||||
func TestResolveKeywordedScope(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
user *models.SignedInUser |
||||
permission Permission |
||||
want *Permission |
||||
wantErr bool |
||||
}{ |
||||
{ |
||||
name: "no scope", |
||||
user: testUser, |
||||
permission: Permission{Action: "users:read"}, |
||||
want: &Permission{Action: "users:read"}, |
||||
wantErr: false, |
||||
}, |
||||
{ |
||||
name: "user if resolution", |
||||
user: testUser, |
||||
permission: Permission{Action: "users:read", Scope: "users:self"}, |
||||
want: &Permission{Action: "users:read", Scope: "users:id:2"}, |
||||
wantErr: false, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
resolver := NewScopeResolver() |
||||
resolved, err := resolver.ResolveKeyword(tt.user, tt.permission) |
||||
if tt.wantErr { |
||||
assert.Error(t, err, "expected an error during the resolution of the scope") |
||||
return |
||||
} |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, tt.want, resolved, "permission did not match expected resolution") |
||||
}) |
||||
} |
||||
} |
Loading…
Reference in new issue