@ -114,6 +114,7 @@ func (s *Service) GetUsageStats(_ context.Context) map[string]any {
func ( s * Service ) GetUserPermissions ( ctx context . Context , user identity . Requester , options accesscontrol . Options ) ( [ ] accesscontrol . Permission , error ) {
ctx , span := s . tracer . Start ( ctx , "authz.GetUserPermissionsOSS" )
defer span . End ( )
timer := prometheus . NewTimer ( metrics . MAccessPermissionsSummary )
defer timer . ObserveDuration ( )
@ -125,6 +126,9 @@ func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requeste
}
func ( s * Service ) getUserPermissions ( ctx context . Context , user identity . Requester , options accesscontrol . Options ) ( [ ] accesscontrol . Permission , error ) {
ctx , span := s . tracer . Start ( ctx , "authz.getUserPermissions" )
defer span . End ( )
permissions := make ( [ ] accesscontrol . Permission , 0 )
for _ , builtin := range accesscontrol . GetOrgRoles ( user ) {
if basicRole , ok := s . roles [ builtin ] ; ok {
@ -265,8 +269,10 @@ func (s *Service) getCachedBasicRolesPermissions(ctx context.Context, user ident
defer span . End ( )
basicRoles := accesscontrol . GetOrgRoles ( user )
span . SetAttributes ( attribute . Int ( "roles" , len ( basicRoles ) ) )
for _ , role := range basicRoles {
perms , err := s . getCachedBasicRolePermissions ( ctx , role , user . GetOrgID ( ) , options )
span . SetAttributes ( attribute . Int ( fmt . Sprintf ( "role_%s_permissions" , role ) , len ( perms ) ) )
if err != nil {
return nil , err
}
@ -301,12 +307,13 @@ type getPermissionsFunc = func(ctx context.Context) ([]accesscontrol.Permission,
// Generic method for getting various permissions from cache
func ( s * Service ) getCachedPermissions ( ctx context . Context , key string , getPermissionsFn getPermissionsFunc , options accesscontrol . Options ) ( [ ] accesscontrol . Permission , error ) {
_ , span := s . tracer . Start ( ctx , "authz.getCachedPermissions" )
ctx , span := s . tracer . Start ( ctx , "authz.getCachedPermissions" )
defer span . End ( )
if ! options . ReloadCache {
permissions , ok := s . cache . Get ( key )
if ok {
span . SetAttributes ( attribute . Int ( "num_permissions_cached" , len ( permissions . ( [ ] accesscontrol . Permission ) ) ) )
metrics . MAccessPermissionsCacheUsage . WithLabelValues ( accesscontrol . CacheHit ) . Inc ( )
return permissions . ( [ ] accesscontrol . Permission ) , nil
}
@ -315,6 +322,7 @@ func (s *Service) getCachedPermissions(ctx context.Context, key string, getPermi
span . AddEvent ( "cache miss" )
metrics . MAccessPermissionsCacheUsage . WithLabelValues ( accesscontrol . CacheMiss ) . Inc ( )
permissions , err := getPermissionsFn ( ctx )
span . SetAttributes ( attribute . Int ( "num_permissions_fetched" , len ( permissions ) ) )
if err != nil {
return nil , err
}
@ -338,6 +346,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
teamPermissions , ok := s . cache . Get ( key )
if ok {
metrics . MAccessPermissionsCacheUsage . WithLabelValues ( accesscontrol . CacheHit ) . Inc ( )
span . SetAttributes ( attribute . Int ( "num_permissions_cached" , len ( teamPermissions . ( [ ] accesscontrol . Permission ) ) ) )
permissions = append ( permissions , teamPermissions . ( [ ] accesscontrol . Permission ) ... )
} else {
miss = append ( miss , teamID )
@ -349,6 +358,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
span . AddEvent ( "cache miss" )
metrics . MAccessPermissionsCacheUsage . WithLabelValues ( accesscontrol . CacheMiss ) . Inc ( )
teamsPermissions , err := s . getTeamsPermissions ( ctx , miss , orgID )
span . SetAttributes ( attribute . Int ( "num_permissions_fetched" , len ( teamsPermissions ) ) )
if err != nil {
return nil , err
}
@ -369,10 +379,16 @@ func (s *Service) ClearUserPermissionCache(user identity.Requester) {
}
func ( s * Service ) DeleteUserPermissions ( ctx context . Context , orgID int64 , userID int64 ) error {
ctx , span := s . tracer . Start ( ctx , "authz.DeleteUserPermissions" )
defer span . End ( )
return s . store . DeleteUserPermissions ( ctx , orgID , userID )
}
func ( s * Service ) DeleteTeamPermissions ( ctx context . Context , orgID int64 , teamID int64 ) error {
ctx , span := s . tracer . Start ( ctx , "authz.DeleteTeamPermissions" )
defer span . End ( )
return s . store . DeleteTeamPermissions ( ctx , orgID , teamID )
}
@ -398,6 +414,9 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat
// RegisterFixedRoles registers all declared roles in RAM
func ( s * Service ) RegisterFixedRoles ( ctx context . Context ) error {
_ , span := s . tracer . Start ( ctx , "authz.RegisterFixedRoles" )
defer span . End ( )
s . registrations . Range ( func ( registration accesscontrol . RoleRegistration ) bool {
for br := range accesscontrol . BuiltInRolesWithParents ( registration . Grants ) {
if basicRole , ok := s . roles [ br ] ; ok {
@ -421,6 +440,9 @@ func (s *Service) RegisterFixedRoles(ctx context.Context) error {
// DeclarePluginRoles allow the caller to declare, to the service, plugin roles and their assignments
// to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin"
func ( s * Service ) DeclarePluginRoles ( ctx context . Context , ID , name string , regs [ ] plugins . RoleRegistration ) error {
ctx , span := s . tracer . Start ( ctx , "authz.DeclarePluginRoles" )
defer span . End ( )
// Protect behind feature toggle
if ! s . features . IsEnabled ( ctx , featuremgmt . FlagAccessControlOnCall ) {
return nil
@ -455,6 +477,9 @@ func GetActionFilter(options accesscontrol.SearchOptions) func(action string) bo
// SearchUsersPermissions returns all users' permissions filtered by action prefixes
func ( s * Service ) SearchUsersPermissions ( ctx context . Context , usr identity . Requester , options accesscontrol . SearchOptions ) ( map [ int64 ] [ ] accesscontrol . Permission , error ) {
ctx , span := s . tracer . Start ( ctx , "authz.SearchUsersPermissions" )
defer span . End ( )
// Limit roles to available in OSS
options . RolePrefixes = OSSRolesPrefixes
if options . NamespacedID != "" {
@ -566,6 +591,9 @@ func (s *Service) SearchUsersPermissions(ctx context.Context, usr identity.Reque
}
func ( s * Service ) SearchUserPermissions ( ctx context . Context , orgID int64 , searchOptions accesscontrol . SearchOptions ) ( [ ] accesscontrol . Permission , error ) {
ctx , span := s . tracer . Start ( ctx , "authz.SearchUserPermissions" )
defer span . End ( )
timer := prometheus . NewTimer ( metrics . MAccessPermissionsSummary )
defer timer . ObserveDuration ( )
@ -573,13 +601,16 @@ func (s *Service) SearchUserPermissions(ctx context.Context, orgID int64, search
return nil , fmt . Errorf ( "expected namespaced ID to be specified" )
}
if permissions , success := s . searchUserPermissionsFromCache ( orgID , searchOptions ) ; success {
if permissions , success := s . searchUserPermissionsFromCache ( ctx , orgID , searchOptions ) ; success {
return permissions , nil
}
return s . searchUserPermissions ( ctx , orgID , searchOptions )
}
func ( s * Service ) searchUserPermissions ( ctx context . Context , orgID int64 , searchOptions accesscontrol . SearchOptions ) ( [ ] accesscontrol . Permission , error ) {
ctx , span := s . tracer . Start ( ctx , "authz.searchUserPermissions" )
defer span . End ( )
userID , err := searchOptions . ComputeUserID ( )
if err != nil {
return nil , err
@ -629,7 +660,10 @@ func (s *Service) searchUserPermissions(ctx context.Context, orgID int64, search
return permissions , nil
}
func ( s * Service ) searchUserPermissionsFromCache ( orgID int64 , searchOptions accesscontrol . SearchOptions ) ( [ ] accesscontrol . Permission , bool ) {
func ( s * Service ) searchUserPermissionsFromCache ( ctx context . Context , orgID int64 , searchOptions accesscontrol . SearchOptions ) ( [ ] accesscontrol . Permission , bool ) {
_ , span := s . tracer . Start ( ctx , "authz.searchUserPermissionsFromCache" )
defer span . End ( )
userID , err := searchOptions . ComputeUserID ( )
if err != nil {
return nil , false
@ -669,6 +703,9 @@ func PermissionMatchesSearchOptions(permission accesscontrol.Permission, searchO
}
func ( s * Service ) SaveExternalServiceRole ( ctx context . Context , cmd accesscontrol . SaveExternalServiceRoleCommand ) error {
ctx , span := s . tracer . Start ( ctx , "authz.SaveExternalServiceRole" )
defer span . End ( )
if ! s . features . IsEnabled ( ctx , featuremgmt . FlagExternalServiceAccounts ) {
s . log . Debug ( "Registering an external service role is behind a feature flag, enable it to use this feature." )
return nil
@ -682,6 +719,9 @@ func (s *Service) SaveExternalServiceRole(ctx context.Context, cmd accesscontrol
}
func ( s * Service ) DeleteExternalServiceRole ( ctx context . Context , externalServiceID string ) error {
ctx , span := s . tracer . Start ( ctx , "authz.DeleteExternalServiceRole" )
defer span . End ( )
if ! s . features . IsEnabled ( ctx , featuremgmt . FlagExternalServiceAccounts ) {
s . log . Debug ( "Deleting an external service role is behind a feature flag, enable it to use this feature." )
return nil
@ -697,6 +737,9 @@ func (*Service) SyncUserRoles(ctx context.Context, orgID int64, cmd accesscontro
}
func ( s * Service ) GetRoleByName ( ctx context . Context , orgID int64 , roleName string ) ( * accesscontrol . RoleDTO , error ) {
_ , span := s . tracer . Start ( ctx , "authz.GetRoleByName" )
defer span . End ( )
err := accesscontrol . ErrRoleNotFound
if _ , ok := s . roles [ roleName ] ; ok {
return nil , err