RBAC: Add userLogin filter to the permission search endpoint (#81137)

* RBAC: Search add user login filter

* Switch to a userService resolving instead

* Remove unused error

* Fallback to use the cache

* account for userID filter

* Account for the error

* snake case

* Add test cases

* Add api tests

* Fix return on error

* Re-order imports
This commit is contained in:
Gabriel MABILLE
2024-01-26 09:43:16 +01:00
committed by GitHub
parent 2e352ba4d6
commit 722b78f3e0
11 changed files with 246 additions and 30 deletions
+42 -16
View File
@@ -42,8 +42,8 @@ var SharedWithMeFolderPermission = accesscontrol.Permission{
}
func ProvideService(cfg *setting.Cfg, db db.DB, routeRegister routing.RouteRegister, cache *localcache.CacheService,
accessControl accesscontrol.AccessControl, features featuremgmt.FeatureToggles) (*Service, error) {
service := ProvideOSSService(cfg, database.ProvideService(db), cache, features)
accessControl accesscontrol.AccessControl, userSvc user.Service, features featuremgmt.FeatureToggles) (*Service, error) {
service := ProvideOSSService(cfg, database.ProvideService(db), cache, userSvc, features)
api.NewAccessControlAPI(routeRegister, accessControl, service, features).RegisterAPIEndpoints()
if err := accesscontrol.DeclareFixedRoles(service, cfg); err != nil {
@@ -63,14 +63,15 @@ func ProvideService(cfg *setting.Cfg, db db.DB, routeRegister routing.RouteRegis
return service, nil
}
func ProvideOSSService(cfg *setting.Cfg, store store, cache *localcache.CacheService, features featuremgmt.FeatureToggles) *Service {
func ProvideOSSService(cfg *setting.Cfg, store store, cache *localcache.CacheService, userSvc user.Service, features featuremgmt.FeatureToggles) *Service {
s := &Service{
cfg: cfg,
store: store,
log: log.New("accesscontrol.service"),
cache: cache,
roles: accesscontrol.BuildBasicRoleDefinitions(),
cfg: cfg,
features: features,
log: log.New("accesscontrol.service"),
roles: accesscontrol.BuildBasicRoleDefinitions(),
store: store,
userSvc: userSvc,
}
return s
@@ -88,13 +89,14 @@ type store interface {
// Service is the service implementing role based access control.
type Service struct {
log log.Logger
cfg *setting.Cfg
store store
cache *localcache.CacheService
cfg *setting.Cfg
features featuremgmt.FeatureToggles
log log.Logger
registrations accesscontrol.RegistrationList
roles map[string]*accesscontrol.RoleDTO
features featuremgmt.FeatureToggles
store store
userSvc user.Service
}
func (s *Service) GetUsageStats(_ context.Context) map[string]any {
@@ -243,8 +245,25 @@ func (s *Service) DeclarePluginRoles(ctx context.Context, ID, name string, regs
}
// SearchUsersPermissions returns all users' permissions filtered by action prefixes
func (s *Service) SearchUsersPermissions(ctx context.Context, user identity.Requester,
func (s *Service) SearchUsersPermissions(ctx context.Context, usr identity.Requester,
options accesscontrol.SearchOptions) (map[int64][]accesscontrol.Permission, error) {
if options.UserLogin != "" {
// Resolve userLogin -> userID
if err := options.ResolveUserLogin(ctx, s.userSvc); err != nil {
return nil, err
}
options.UserLogin = ""
}
if options.UserID > 0 {
// Reroute to the user specific implementation of search permissions
// because it leverages the user permission cache.
userPerms, err := s.SearchUserPermissions(ctx, usr.GetOrgID(), options)
if err != nil {
return nil, err
}
return map[int64][]accesscontrol.Permission{options.UserID: userPerms}, nil
}
timer := prometheus.NewTimer(metrics.MAccessSearchPermissionsSummary)
defer timer.ObserveDuration()
@@ -258,20 +277,20 @@ func (s *Service) SearchUsersPermissions(ctx context.Context, user identity.Requ
}
}
usersRoles, err := s.store.GetUsersBasicRoles(ctx, nil, user.GetOrgID())
usersRoles, err := s.store.GetUsersBasicRoles(ctx, nil, usr.GetOrgID())
if err != nil {
return nil, err
}
// Get managed permissions (DB)
usersPermissions, err := s.store.SearchUsersPermissions(ctx, user.GetOrgID(), options)
usersPermissions, err := s.store.SearchUsersPermissions(ctx, usr.GetOrgID(), options)
if err != nil {
return nil, err
}
// helper to filter out permissions the signed in users cannot see
canView := func() func(userID int64) bool {
siuPermissions := user.GetPermissions()
siuPermissions := usr.GetPermissions()
if len(siuPermissions) == 0 {
return func(_ int64) bool { return false }
}
@@ -329,8 +348,15 @@ func (s *Service) SearchUserPermissions(ctx context.Context, orgID int64, search
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
defer timer.ObserveDuration()
if searchOptions.UserLogin != "" {
// Resolve userLogin -> userID
if err := searchOptions.ResolveUserLogin(ctx, s.userSvc); err != nil {
return nil, err
}
}
if searchOptions.UserID == 0 {
return nil, fmt.Errorf("expected user ID to be specified")
return nil, fmt.Errorf("expected user ID or login to be specified")
}
if permissions, success := s.searchUserPermissionsFromCache(orgID, searchOptions); success {