Access control: use uid for dashboard and folder scopes (#46807)
* use uid:s for folder and dashboard permissions * evaluate folder and dashboard permissions based on uids * add dashboard.uid to accept list * Check for exact suffix * Check parent folder on create * update test * drop dashboard:create actions with dashboard scope * fix typo * AccessControl: test id 0 scope conversion * AccessControl: store only parent folder UID * AccessControl: extract general as a constant * FolderServices: Prevent creation of a folder uid'd general * FolderServices: Test folder creation prevention * Update pkg/services/guardian/accesscontrol_guardian.go * FolderServices: fix mock call expect * FolderServices: remove uneeded mocks Co-authored-by: jguer <joao.guerreiro@grafana.com>
This commit is contained in:
@@ -9,6 +9,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ScopeFoldersRoot = "folders"
|
||||
ScopeFoldersPrefix = "folders:uid:"
|
||||
|
||||
ActionFoldersCreate = "folders:create"
|
||||
ActionFoldersRead = "folders:read"
|
||||
ActionFoldersWrite = "folders:write"
|
||||
@@ -16,7 +19,8 @@ const (
|
||||
ActionFoldersPermissionsRead = "folders.permissions:read"
|
||||
ActionFoldersPermissionsWrite = "folders.permissions:write"
|
||||
|
||||
ScopeFoldersRoot = "folders"
|
||||
ScopeDashboardsRoot = "dashboards"
|
||||
ScopeDashboardsPrefix = "dashboards:uid:"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -24,7 +28,7 @@ var (
|
||||
ScopeFoldersProvider = ac.NewScopeProvider(ScopeFoldersRoot)
|
||||
)
|
||||
|
||||
// NewNameScopeResolver provides an AttributeScopeResolver that is able to convert a scope prefixed with "folders:name:" into an id based scope.
|
||||
// NewNameScopeResolver provides an AttributeScopeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope.
|
||||
func NewNameScopeResolver(db Store) (string, ac.AttributeScopeResolveFunc) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScopeName("")
|
||||
resolver := func(ctx context.Context, orgID int64, scope string) (string, error) {
|
||||
@@ -39,27 +43,34 @@ func NewNameScopeResolver(db Store) (string, ac.AttributeScopeResolveFunc) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(folder.Id, 10)), nil
|
||||
return ScopeFoldersProvider.GetResourceScopeUID(folder.Uid), nil
|
||||
}
|
||||
return prefix, resolver
|
||||
}
|
||||
|
||||
// NewUidScopeResolver provides an AttributeScopeResolver that is able to convert a scope prefixed with "folders:uid:" into an id based scope.
|
||||
func NewUidScopeResolver(db Store) (string, ac.AttributeScopeResolveFunc) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScopeUID("")
|
||||
// NewIDScopeResolver provides an AttributeScopeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope.
|
||||
func NewIDScopeResolver(db Store) (string, ac.AttributeScopeResolveFunc) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScope("")
|
||||
resolver := func(ctx context.Context, orgID int64, scope string) (string, error) {
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
return "", ac.ErrInvalidScope
|
||||
}
|
||||
uid := scope[len(prefix):]
|
||||
if len(uid) == 0 {
|
||||
|
||||
id, err := strconv.ParseInt(scope[len(prefix):], 10, 64)
|
||||
if err != nil {
|
||||
return "", ac.ErrInvalidScope
|
||||
}
|
||||
folder, err := db.GetFolderByUID(ctx, orgID, uid)
|
||||
|
||||
if id == 0 {
|
||||
return ScopeFoldersProvider.GetResourceScopeUID(ac.GeneralFolderUID), nil
|
||||
}
|
||||
|
||||
folder, err := db.GetFolderByID(ctx, orgID, id)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(folder.Id, 10)), nil
|
||||
|
||||
return ScopeFoldersProvider.GetResourceScopeUID(folder.Uid), nil
|
||||
}
|
||||
return prefix, resolver
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user