2020-04-20 16:20:45 +02:00
package permissions
import (
2023-04-06 11:16:15 +03:00
"bytes"
"fmt"
2023-11-01 09:17:38 -07:00
"slices"
2020-06-29 14:08:32 +02:00
"strings"
2022-03-03 15:05:47 +01:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2023-09-06 11:16:10 +02:00
"github.com/grafana/grafana/pkg/services/auth/identity"
2022-03-09 11:57:50 -05:00
"github.com/grafana/grafana/pkg/services/dashboards"
2023-11-22 14:20:22 +01:00
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
2023-04-06 11:16:15 +03:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
2023-07-12 12:31:36 +02:00
"github.com/grafana/grafana/pkg/services/login"
2022-03-16 10:07:04 -04:00
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
2020-04-20 16:20:45 +02:00
)
2023-04-06 11:16:15 +03:00
// maximum possible capacity for recursive queries array: one query for folder and one for dashboard actions
const maximumRecursiveQueries = 2
type clause struct {
string
2023-08-30 08:46:47 -07:00
params [ ] any
2023-04-06 11:16:15 +03:00
}
type accessControlDashboardPermissionFilter struct {
2023-09-06 11:16:10 +02:00
user identity . Requester
2022-10-25 11:14:27 +02:00
dashboardActions [ ] string
2023-01-09 14:38:57 +01:00
folderActions [ ] string
2023-04-06 11:16:15 +03:00
features featuremgmt . FeatureToggles
where clause
// any recursive CTE queries (if supported)
recQueries [ ] clause
recursiveQueriesAreSupported bool
2022-03-03 15:05:47 +01:00
}
2023-08-02 10:39:25 +03:00
type PermissionsFilter interface {
LeftJoin ( ) string
2023-08-30 08:46:47 -07:00
With ( ) ( string , [ ] any )
Where ( ) ( string , [ ] any )
2023-08-02 10:39:25 +03:00
buildClauses ( )
2023-11-06 15:16:23 +02:00
nestedFoldersSelectors ( permSelector string , permSelectorArgs [ ] any , leftTableCol string , rightTableCol string , orgID int64 ) ( string , [ ] any )
2023-08-02 10:39:25 +03:00
}
2023-11-22 14:20:22 +01:00
// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the dashboardaccess.PermissionType and query type
2023-08-02 10:39:25 +03:00
// The filter is configured to use the new permissions filter (without subqueries) if the feature flag is enabled
// The filter is configured to use the old permissions filter (with subqueries) if the feature flag is disabled
2023-11-22 14:20:22 +01:00
func NewAccessControlDashboardPermissionFilter ( user identity . Requester , permissionLevel dashboardaccess . PermissionType , queryType string , features featuremgmt . FeatureToggles , recursiveQueriesAreSupported bool ) PermissionsFilter {
needEdit := permissionLevel > dashboardaccess . PERMISSION_VIEW
2023-01-09 14:38:57 +01:00
var folderActions [ ] string
2022-03-16 10:07:04 -04:00
var dashboardActions [ ] string
2023-01-09 14:38:57 +01:00
if queryType == searchstore . TypeFolder {
folderActions = append ( folderActions , dashboards . ActionFoldersRead )
if needEdit {
folderActions = append ( folderActions , dashboards . ActionDashboardsCreate )
}
} else if queryType == searchstore . TypeDashboard {
dashboardActions = append ( dashboardActions , dashboards . ActionDashboardsRead )
if needEdit {
dashboardActions = append ( dashboardActions , dashboards . ActionDashboardsWrite )
}
} else if queryType == searchstore . TypeAlertFolder {
folderActions = append (
folderActions ,
dashboards . ActionFoldersRead ,
accesscontrol . ActionAlertingRuleRead ,
)
2022-03-16 10:07:04 -04:00
if needEdit {
2023-01-09 14:38:57 +01:00
folderActions = append (
folderActions ,
accesscontrol . ActionAlertingRuleCreate ,
)
2022-03-16 10:07:04 -04:00
}
2023-11-29 10:34:44 +00:00
} else if queryType == searchstore . TypeAnnotation {
dashboardActions = append ( dashboardActions , accesscontrol . ActionAnnotationsRead )
2022-03-16 10:07:04 -04:00
} else {
2023-01-09 14:38:57 +01:00
folderActions = append ( folderActions , dashboards . ActionFoldersRead )
2022-05-04 16:12:09 +02:00
dashboardActions = append ( dashboardActions , dashboards . ActionDashboardsRead )
2022-03-16 10:07:04 -04:00
if needEdit {
2022-05-04 16:12:09 +02:00
folderActions = append ( folderActions , dashboards . ActionDashboardsCreate )
dashboardActions = append ( dashboardActions , dashboards . ActionDashboardsWrite )
2022-03-16 10:07:04 -04:00
}
2022-03-08 12:46:49 +01:00
}
2023-01-09 14:38:57 +01:00
2023-08-02 10:39:25 +03:00
var f PermissionsFilter
2023-11-14 12:50:27 -08:00
if features . IsEnabledGlobally ( featuremgmt . FlagPermissionsFilterRemoveSubquery ) {
2023-08-02 10:39:25 +03:00
f = & accessControlDashboardPermissionFilterNoFolderSubquery {
accessControlDashboardPermissionFilter : accessControlDashboardPermissionFilter {
user : user , folderActions : folderActions , dashboardActions : dashboardActions , features : features ,
recursiveQueriesAreSupported : recursiveQueriesAreSupported ,
} ,
}
} else {
f = & accessControlDashboardPermissionFilter { user : user , folderActions : folderActions , dashboardActions : dashboardActions , features : features ,
recursiveQueriesAreSupported : recursiveQueriesAreSupported ,
}
2023-04-06 11:16:15 +03:00
}
f . buildClauses ( )
2023-08-02 10:39:25 +03:00
return f
}
2023-04-06 11:16:15 +03:00
2023-08-02 10:39:25 +03:00
func ( f * accessControlDashboardPermissionFilter ) LeftJoin ( ) string {
return ""
2022-03-16 10:07:04 -04:00
}
2022-03-08 12:46:49 +01:00
2023-04-06 11:16:15 +03:00
// Where returns:
// - a where clause for filtering dashboards with expected permissions
// - an array with the query parameters
2023-08-30 08:46:47 -07:00
func ( f * accessControlDashboardPermissionFilter ) Where ( ) ( string , [ ] any ) {
2023-04-06 11:16:15 +03:00
return f . where . string , f . where . params
}
func ( f * accessControlDashboardPermissionFilter ) buildClauses ( ) {
2023-09-06 11:16:10 +02:00
if f . user == nil || f . user . IsNil ( ) || len ( f . user . GetPermissions ( ) ) == 0 {
2023-04-06 11:16:15 +03:00
f . where = clause { string : "(1 = 0)" }
return
2022-10-25 11:14:27 +02:00
}
dashWildcards := accesscontrol . WildcardsFromPrefix ( dashboards . ScopeDashboardsPrefix )
folderWildcards := accesscontrol . WildcardsFromPrefix ( dashboards . ScopeFoldersPrefix )
2023-09-06 11:16:10 +02:00
userID := int64 ( 0 )
namespaceID , identifier := f . user . GetNamespacedID ( )
switch namespaceID {
case identity . NamespaceUser , identity . NamespaceServiceAccount :
userID , _ = identity . IntIdentifier ( namespaceID , identifier )
}
2023-11-06 15:16:23 +02:00
orgID := f . user . GetOrgID ( )
filter , params := accesscontrol . UserRolesFilter ( orgID , userID , f . user . GetTeams ( ) , accesscontrol . GetOrgRoles ( f . user ) )
2023-01-09 14:38:57 +01:00
rolesFilter := " AND role_id IN(SELECT id FROM role " + filter + ") "
2023-08-30 08:46:47 -07:00
var args [ ] any
2022-03-03 15:05:47 +01:00
builder := strings . Builder { }
2022-10-25 11:14:27 +02:00
builder . WriteRune ( '(' )
2023-04-06 11:16:15 +03:00
permSelector := strings . Builder { }
2023-08-30 08:46:47 -07:00
var permSelectorArgs [ ] any
2023-04-06 11:16:15 +03:00
2023-07-12 12:31:36 +02:00
// useSelfContainedPermissions is true if the user's permissions are stored and set from the JWT token
// currently it's used for the extended JWT module (when the user is authenticated via a JWT token generated by Grafana)
2023-09-06 11:16:10 +02:00
useSelfContainedPermissions := f . user . GetAuthenticatedBy ( ) == login . ExtendedJWTModule
2023-07-12 12:31:36 +02:00
2022-03-16 10:07:04 -04:00
if len ( f . dashboardActions ) > 0 {
2023-09-06 11:16:10 +02:00
toCheck := actionsToCheck ( f . dashboardActions , f . user . GetPermissions ( ) , dashWildcards , folderWildcards )
2022-03-03 15:05:47 +01:00
2023-01-09 14:38:57 +01:00
if len ( toCheck ) > 0 {
2023-07-12 12:31:36 +02:00
if ! useSelfContainedPermissions {
builder . WriteString ( "(dashboard.uid IN (SELECT substr(scope, 16) FROM permission WHERE scope LIKE 'dashboards:uid:%'" )
builder . WriteString ( rolesFilter )
args = append ( args , params ... )
if len ( toCheck ) == 1 {
builder . WriteString ( " AND action = ?" )
args = append ( args , toCheck [ 0 ] )
} else {
builder . WriteString ( " AND action IN (?" + strings . Repeat ( ", ?" , len ( toCheck ) - 1 ) + ") GROUP BY role_id, scope HAVING COUNT(action) = ?" )
args = append ( args , toCheck ... )
args = append ( args , len ( toCheck ) )
}
builder . WriteString ( ") AND NOT dashboard.is_folder)" )
2023-01-09 14:38:57 +01:00
} else {
2023-07-12 12:31:36 +02:00
actions := parseStringSliceFromInterfaceSlice ( toCheck )
args = getAllowedUIDs ( actions , f . user , dashboards . ScopeDashboardsPrefix )
// Only add the IN clause if we have any dashboards to check
if len ( args ) > 0 {
builder . WriteString ( "(dashboard.uid IN (?" + strings . Repeat ( ", ?" , len ( args ) - 1 ) + "" )
builder . WriteString ( ") AND NOT dashboard.is_folder)" )
} else {
builder . WriteString ( "(1 = 0)" )
}
2023-01-09 14:38:57 +01:00
}
2022-03-03 15:05:47 +01:00
2022-10-25 11:14:27 +02:00
builder . WriteString ( " OR " )
2023-01-09 14:38:57 +01:00
2023-07-12 12:31:36 +02:00
if ! useSelfContainedPermissions {
permSelector . WriteString ( "(SELECT substr(scope, 13) FROM permission WHERE scope LIKE 'folders:uid:%' " )
permSelector . WriteString ( rolesFilter )
permSelectorArgs = append ( permSelectorArgs , params ... )
if len ( toCheck ) == 1 {
permSelector . WriteString ( " AND action = ?" )
permSelectorArgs = append ( permSelectorArgs , toCheck [ 0 ] )
} else {
permSelector . WriteString ( " AND action IN (?" + strings . Repeat ( ", ?" , len ( toCheck ) - 1 ) + ") GROUP BY role_id, scope HAVING COUNT(action) = ?" )
permSelectorArgs = append ( permSelectorArgs , toCheck ... )
permSelectorArgs = append ( permSelectorArgs , len ( toCheck ) )
}
2023-01-09 14:38:57 +01:00
} else {
2023-07-12 12:31:36 +02:00
actions := parseStringSliceFromInterfaceSlice ( toCheck )
permSelectorArgs = getAllowedUIDs ( actions , f . user , dashboards . ScopeFoldersPrefix )
// Only add the IN clause if we have any folders to check
if len ( permSelectorArgs ) > 0 {
permSelector . WriteString ( "(?" + strings . Repeat ( ", ?" , len ( permSelectorArgs ) - 1 ) + "" )
} else {
permSelector . WriteString ( "(" )
}
2023-04-06 11:16:15 +03:00
}
permSelector . WriteRune ( ')' )
2023-11-14 12:50:27 -08:00
switch f . features . IsEnabledGlobally ( featuremgmt . FlagNestedFolders ) {
2023-04-06 11:16:15 +03:00
case true :
2023-08-02 14:12:46 +03:00
if len ( permSelectorArgs ) > 0 {
switch f . recursiveQueriesAreSupported {
case true :
builder . WriteString ( "(dashboard.folder_id IN (SELECT d.id FROM dashboard as d " )
recQueryName := fmt . Sprintf ( "RecQry%d" , len ( f . recQueries ) )
f . addRecQry ( recQueryName , permSelector . String ( ) , permSelectorArgs )
2023-11-06 15:16:23 +02:00
builder . WriteString ( fmt . Sprintf ( "WHERE d.org_id = ? AND d.uid IN (SELECT uid FROM %s)" , recQueryName ) )
args = append ( args , orgID )
2023-08-02 14:12:46 +03:00
default :
2023-11-06 15:16:23 +02:00
nestedFoldersSelectors , nestedFoldersArgs := f . nestedFoldersSelectors ( permSelector . String ( ) , permSelectorArgs , "dashboard.folder_id" , "d.id" , orgID )
2023-08-02 14:12:46 +03:00
builder . WriteRune ( '(' )
builder . WriteString ( nestedFoldersSelectors )
args = append ( args , nestedFoldersArgs ... )
}
} else {
2023-04-06 11:16:15 +03:00
builder . WriteString ( "(dashboard.folder_id IN (SELECT d.id FROM dashboard as d " )
2023-08-02 14:12:46 +03:00
builder . WriteString ( "WHERE 1 = 0" )
2023-04-06 11:16:15 +03:00
}
default :
builder . WriteString ( "(dashboard.folder_id IN (SELECT d.id FROM dashboard as d " )
2023-07-12 12:31:36 +02:00
if len ( permSelectorArgs ) > 0 {
2023-11-06 15:16:23 +02:00
builder . WriteString ( "WHERE d.org_id = ? AND d.uid IN " )
args = append ( args , orgID )
2023-07-12 12:31:36 +02:00
builder . WriteString ( permSelector . String ( ) )
args = append ( args , permSelectorArgs ... )
} else {
builder . WriteString ( "WHERE 1 = 0" )
}
2023-01-09 14:38:57 +01:00
}
2023-04-06 11:16:15 +03:00
builder . WriteString ( ") AND NOT dashboard.is_folder)" )
2023-10-24 09:55:38 +01:00
// Include all the dashboards under the root if the user has the required permissions on the root (used to be the General folder)
if hasAccessToRoot ( toCheck , f . user ) {
builder . WriteString ( " OR (dashboard.folder_id = 0 AND NOT dashboard.is_folder)" )
}
2022-10-25 11:14:27 +02:00
} else {
builder . WriteString ( "NOT dashboard.is_folder" )
}
2022-03-16 10:07:04 -04:00
}
2022-03-03 15:05:47 +01:00
2023-04-06 11:16:15 +03:00
// recycle and reuse
permSelector . Reset ( )
permSelectorArgs = permSelectorArgs [ : 0 ]
2022-03-16 10:07:04 -04:00
if len ( f . folderActions ) > 0 {
if len ( f . dashboardActions ) > 0 {
builder . WriteString ( " OR " )
}
2022-10-25 11:14:27 +02:00
2023-09-06 11:16:10 +02:00
toCheck := actionsToCheck ( f . folderActions , f . user . GetPermissions ( ) , folderWildcards )
2023-01-09 14:38:57 +01:00
if len ( toCheck ) > 0 {
2023-07-12 12:31:36 +02:00
if ! useSelfContainedPermissions {
permSelector . WriteString ( "(SELECT substr(scope, 13) FROM permission WHERE scope LIKE 'folders:uid:%'" )
permSelector . WriteString ( rolesFilter )
permSelectorArgs = append ( permSelectorArgs , params ... )
if len ( toCheck ) == 1 {
permSelector . WriteString ( " AND action = ?" )
permSelectorArgs = append ( permSelectorArgs , toCheck [ 0 ] )
} else {
permSelector . WriteString ( " AND action IN (?" + strings . Repeat ( ", ?" , len ( toCheck ) - 1 ) + ") GROUP BY role_id, scope HAVING COUNT(action) = ?" )
permSelectorArgs = append ( permSelectorArgs , toCheck ... )
permSelectorArgs = append ( permSelectorArgs , len ( toCheck ) )
}
2023-01-09 14:38:57 +01:00
} else {
2023-07-12 12:31:36 +02:00
actions := parseStringSliceFromInterfaceSlice ( toCheck )
permSelectorArgs = getAllowedUIDs ( actions , f . user , dashboards . ScopeFoldersPrefix )
if len ( permSelectorArgs ) > 0 {
permSelector . WriteString ( "(?" + strings . Repeat ( ", ?" , len ( permSelectorArgs ) - 1 ) + "" )
} else {
permSelector . WriteString ( "(" )
}
2023-01-09 14:38:57 +01:00
}
2023-07-12 12:31:36 +02:00
2023-04-06 11:16:15 +03:00
permSelector . WriteRune ( ')' )
2023-11-14 12:50:27 -08:00
switch f . features . IsEnabledGlobally ( featuremgmt . FlagNestedFolders ) {
2023-04-06 11:16:15 +03:00
case true :
2023-08-02 14:12:46 +03:00
if len ( permSelectorArgs ) > 0 {
switch f . recursiveQueriesAreSupported {
case true :
recQueryName := fmt . Sprintf ( "RecQry%d" , len ( f . recQueries ) )
f . addRecQry ( recQueryName , permSelector . String ( ) , permSelectorArgs )
builder . WriteString ( "(dashboard.uid IN " )
builder . WriteString ( fmt . Sprintf ( "(SELECT uid FROM %s)" , recQueryName ) )
default :
2023-11-06 15:16:23 +02:00
nestedFoldersSelectors , nestedFoldersArgs := f . nestedFoldersSelectors ( permSelector . String ( ) , permSelectorArgs , "dashboard.uid" , "d.uid" , orgID )
2023-08-02 14:12:46 +03:00
builder . WriteRune ( '(' )
builder . WriteString ( nestedFoldersSelectors )
builder . WriteRune ( ')' )
args = append ( args , nestedFoldersArgs ... )
}
} else {
builder . WriteString ( "(1 = 0" )
2023-04-06 11:16:15 +03:00
}
default :
2023-07-12 12:31:36 +02:00
if len ( permSelectorArgs ) > 0 {
builder . WriteString ( "(dashboard.uid IN " )
builder . WriteString ( permSelector . String ( ) )
args = append ( args , permSelectorArgs ... )
} else {
builder . WriteString ( "(1 = 0" )
}
2023-04-06 11:16:15 +03:00
}
builder . WriteString ( " AND dashboard.is_folder)" )
2022-10-25 11:14:27 +02:00
} else {
builder . WriteString ( "dashboard.is_folder" )
}
2022-03-16 10:07:04 -04:00
}
2023-07-12 12:31:36 +02:00
2022-10-25 11:14:27 +02:00
builder . WriteRune ( ')' )
2023-04-06 11:16:15 +03:00
f . where = clause { string : builder . String ( ) , params : args }
}
// With returns:
// - a with clause for fetching folders with inherited permissions if nested folders are enabled or an empty string
2023-08-30 08:46:47 -07:00
func ( f * accessControlDashboardPermissionFilter ) With ( ) ( string , [ ] any ) {
2023-04-06 11:16:15 +03:00
var sb bytes . Buffer
2023-08-30 08:46:47 -07:00
var params [ ] any
2023-04-06 11:16:15 +03:00
if len ( f . recQueries ) > 0 {
sb . WriteString ( "WITH RECURSIVE " )
sb . WriteString ( f . recQueries [ 0 ] . string )
params = append ( params , f . recQueries [ 0 ] . params ... )
for _ , r := range f . recQueries [ 1 : ] {
sb . WriteRune ( ',' )
sb . WriteString ( r . string )
params = append ( params , r . params ... )
}
}
return sb . String ( ) , params
}
2023-08-30 08:46:47 -07:00
func ( f * accessControlDashboardPermissionFilter ) addRecQry ( queryName string , whereUIDSelect string , whereParams [ ] any ) {
2023-04-06 11:16:15 +03:00
if f . recQueries == nil {
f . recQueries = make ( [ ] clause , 0 , maximumRecursiveQueries )
}
2023-08-30 08:46:47 -07:00
c := make ( [ ] any , len ( whereParams ) )
2023-04-06 11:16:15 +03:00
copy ( c , whereParams )
f . recQueries = append ( f . recQueries , clause {
string : fmt . Sprintf ( ` % s AS (
SELECT uid , parent_uid , org_id FROM folder WHERE uid IN % s
UNION ALL SELECT f . uid , f . parent_uid , f . org_id FROM folder f INNER JOIN % s r ON f . parent_uid = r . uid and f . org_id = r . org_id
) ` , queryName , whereUIDSelect , queryName ) ,
params : c ,
} )
2022-03-03 15:05:47 +01:00
}
2023-01-09 14:38:57 +01:00
2023-08-30 08:46:47 -07:00
func actionsToCheck ( actions [ ] string , permissions map [ string ] [ ] string , wildcards ... accesscontrol . Wildcards ) [ ] any {
toCheck := make ( [ ] any , 0 , len ( actions ) )
2023-01-18 13:19:09 +01:00
2023-01-09 14:38:57 +01:00
for _ , a := range actions {
var hasWildcard bool
2023-01-18 13:19:09 +01:00
outer :
2023-01-09 14:38:57 +01:00
for _ , scope := range permissions [ a ] {
for _ , w := range wildcards {
if w . Contains ( scope ) {
hasWildcard = true
2023-01-18 13:19:09 +01:00
break outer
2023-01-09 14:38:57 +01:00
}
}
}
2023-01-18 13:19:09 +01:00
2023-01-09 14:38:57 +01:00
if ! hasWildcard {
toCheck = append ( toCheck , a )
}
}
return toCheck
}
2023-04-06 11:16:15 +03:00
2023-11-06 15:16:23 +02:00
func ( f * accessControlDashboardPermissionFilter ) nestedFoldersSelectors ( permSelector string , permSelectorArgs [ ] any , leftTableCol string , rightTableCol string , orgID int64 ) ( string , [ ] any ) {
2023-04-06 11:16:15 +03:00
wheres := make ( [ ] string , 0 , folder . MaxNestedFolderDepth + 1 )
2023-08-30 08:46:47 -07:00
args := make ( [ ] any , 0 , len ( permSelectorArgs ) * ( folder . MaxNestedFolderDepth + 1 ) )
2023-04-06 11:16:15 +03:00
joins := make ( [ ] string , 0 , folder . MaxNestedFolderDepth + 2 )
tmpl := "INNER JOIN folder %s ON %s.%s = %s.uid AND %s.org_id = %s.org_id "
prev := "d"
onCol := "uid"
for i := 1 ; i <= folder . MaxNestedFolderDepth + 2 ; i ++ {
t := fmt . Sprintf ( "f%d" , i )
s := fmt . Sprintf ( tmpl , t , prev , onCol , t , prev , t )
joins = append ( joins , s )
2023-11-06 15:16:23 +02:00
wheres = append ( wheres , fmt . Sprintf ( "(%s IN (SELECT %s FROM dashboard d %s WHERE %s.org_id = ? AND %s.uid IN %s)" , leftTableCol , rightTableCol , strings . Join ( joins , " " ) , t , t , permSelector ) )
args = append ( args , orgID )
2023-04-06 11:16:15 +03:00
args = append ( args , permSelectorArgs ... )
prev = t
onCol = "parent_uid"
}
return strings . Join ( wheres , ") OR " ) , args
}
2023-07-12 12:31:36 +02:00
2023-08-30 08:46:47 -07:00
func parseStringSliceFromInterfaceSlice ( slice [ ] any ) [ ] string {
2023-07-12 12:31:36 +02:00
result := make ( [ ] string , 0 , len ( slice ) )
for _ , s := range slice {
result = append ( result , s . ( string ) )
}
return result
}
2023-09-06 11:16:10 +02:00
func getAllowedUIDs ( actions [ ] string , user identity . Requester , scopePrefix string ) [ ] any {
2023-07-12 12:31:36 +02:00
uidToActions := make ( map [ string ] map [ string ] struct { } )
for _ , action := range actions {
2023-09-06 11:16:10 +02:00
for _ , uidScope := range user . GetPermissions ( ) [ action ] {
2023-07-12 12:31:36 +02:00
if ! strings . HasPrefix ( uidScope , scopePrefix ) {
continue
}
uid := strings . TrimPrefix ( uidScope , scopePrefix )
if _ , exists := uidToActions [ uid ] ; ! exists {
uidToActions [ uid ] = make ( map [ string ] struct { } )
}
uidToActions [ uid ] [ action ] = struct { } { }
}
}
// args max capacity is the length of the different uids
2023-08-30 08:46:47 -07:00
args := make ( [ ] any , 0 , len ( uidToActions ) )
2023-07-12 12:31:36 +02:00
for uid , assignedActions := range uidToActions {
if len ( assignedActions ) == len ( actions ) {
args = append ( args , uid )
}
}
return args
}
2023-10-24 09:55:38 +01:00
// Checks if the user has the required permissions on the root (used to be the General folder)
func hasAccessToRoot ( actionsToCheck [ ] any , user identity . Requester ) bool {
generalFolderScope := dashboards . ScopeFoldersProvider . GetResourceScopeUID ( folder . GeneralFolderUID )
for _ , action := range actionsToCheck {
if ! slices . Contains ( user . GetPermissions ( ) [ action . ( string ) ] , generalFolderScope ) {
return false
}
}
return true
}