From 3b638443908be39293dec8ebf1910b411b23f828 Mon Sep 17 00:00:00 2001 From: Gabriel MABILLE Date: Fri, 14 Apr 2023 17:17:59 +0200 Subject: [PATCH] RBAC: Feature to override default assignments (#66561) * RBAC: Feature to override default assignments Co-authored-by: Kalle Persson * Add test and trim spaces * Pass linting * Apply the rbac overrides to fixed_authentication.config_writer * Removing from the default ini file for now * Add grants overrides section to cfg * slimmer handleGrantOverrides function --------- Co-authored-by: Kalle Persson --- pkg/services/accesscontrol/acimpl/service.go | 16 ++++- .../accesscontrol/acimpl/service_test.go | 71 +++++++++++++++++++ pkg/services/accesscontrol/models.go | 5 +- pkg/services/accesscontrol/roles.go | 5 +- pkg/setting/setting.go | 14 ++++ 5 files changed, 106 insertions(+), 5 deletions(-) diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go index fd83c593593..0ce0c6ba672 100644 --- a/pkg/services/accesscontrol/acimpl/service.go +++ b/pkg/services/accesscontrol/acimpl/service.go @@ -166,7 +166,12 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat return nil } - for _, r := range registrations { + for i := range registrations { + r := registrations[i] + if r.AllowGrantsOverride { + s.handleGrantOverrides(&r) + } + err := accesscontrol.ValidateFixedRole(r.Role) if err != nil { return err @@ -183,6 +188,15 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat return nil } +func (s *Service) handleGrantOverrides(r *accesscontrol.RoleRegistration) { + // Replace ":" and "." with "_" to match the key in the config + key := strings.ReplaceAll(strings.ReplaceAll(r.Role.Name, ":", "_"), ".", "_") + if overrides, ok := s.cfg.RBACGrantOverrides[key]; ok { + r.Grants = overrides + s.log.Info("Overriding grants for role", "role", r.Role.Name, "overrides", overrides) + } +} + // RegisterFixedRoles registers all declared roles in RAM func (s *Service) RegisterFixedRoles(ctx context.Context) error { // If accesscontrol is disabled no need to register roles diff --git a/pkg/services/accesscontrol/acimpl/service_test.go b/pkg/services/accesscontrol/acimpl/service_test.go index 06ab9b18d3d..c6babb34fec 100644 --- a/pkg/services/accesscontrol/acimpl/service_test.go +++ b/pkg/services/accesscontrol/acimpl/service_test.go @@ -161,6 +161,77 @@ func TestService_DeclareFixedRoles(t *testing.T) { } } +func TestService_DeclareFixedRoles_Overrides(t *testing.T) { + tests := []struct { + name string + registration accesscontrol.RoleRegistration + overrides map[string][]string + wantGrants []string + wantErr bool + }{ + { + name: "no grant override", + registration: accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{Name: "fixed:test:test"}, + Grants: []string{"Admin"}, + AllowGrantsOverride: true, + }, + wantGrants: []string{"Admin"}, + wantErr: false, + }, + { + name: "should account for grant overrides", + registration: accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{Name: "fixed:test:test"}, + Grants: []string{"Admin"}, + AllowGrantsOverride: true, + }, + overrides: map[string][]string{"fixed_test_test": {"Viewer", "Grafana Admin"}}, + wantGrants: []string{"Viewer", "Grafana Admin"}, + wantErr: false, + }, + { + name: "should not account for grant overrides", + registration: accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{Name: "fixed:test:test"}, + Grants: []string{"Admin"}, + AllowGrantsOverride: false, + }, + overrides: map[string][]string{"fixed_test_test": {"Viewer", "Grafana Admin"}}, + wantGrants: []string{"Admin"}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ac := setupTestEnv(t) + + // Reset the registations + ac.registrations = accesscontrol.RegistrationList{} + ac.cfg.RBACGrantOverrides = tt.overrides + + // Test + err := ac.DeclareFixedRoles(tt.registration) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + registrationCnt := 0 + grants := []string{} + ac.registrations.Range(func(registration accesscontrol.RoleRegistration) bool { + registrationCnt++ + grants = registration.Grants + return true + }) + require.Equal(t, 1, registrationCnt, + "expected service registration list to contain the registration") + require.ElementsMatch(t, tt.wantGrants, grants) + }) + } +} + func TestService_DeclarePluginRoles(t *testing.T) { tests := []struct { name string diff --git a/pkg/services/accesscontrol/models.go b/pkg/services/accesscontrol/models.go index ea688c67635..0810a34e20c 100644 --- a/pkg/services/accesscontrol/models.go +++ b/pkg/services/accesscontrol/models.go @@ -16,8 +16,9 @@ var ErrInternal = errutil.NewBase(errutil.StatusInternal, "accesscontrol.interna // RoleRegistration stores a role and its assignments to built-in roles // (Viewer, Editor, Admin, Grafana Admin) type RoleRegistration struct { - Role RoleDTO - Grants []string + Role RoleDTO + Grants []string + AllowGrantsOverride bool } // Role is the model for Role in RBAC. diff --git a/pkg/services/accesscontrol/roles.go b/pkg/services/accesscontrol/roles.go index 5f195f604bd..1b02f2db662 100644 --- a/pkg/services/accesscontrol/roles.go +++ b/pkg/services/accesscontrol/roles.go @@ -233,8 +233,9 @@ func DeclareFixedRoles(service Service) error { Grants: []string{RoleGrafanaAdmin}, } authenticationConfigWriter := RoleRegistration{ - Role: authenticationConfigWriterRole, - Grants: []string{RoleGrafanaAdmin}, + Role: authenticationConfigWriterRole, + Grants: []string{RoleGrafanaAdmin}, + AllowGrantsOverride: true, } return service.DeclareFixedRoles(ldapReader, ldapWriter, orgUsersReader, orgUsersWriter, diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index d4236f46610..bbf734ecce8 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -505,6 +505,9 @@ type Cfg struct { RBACPermissionValidationEnabled bool // Reset basic roles permissions on start-up RBACResetBasicRoles bool + // Override default fixed role assignments + RBACGrantOverrides map[string][]string + // GRPC Server. GRPCServerNetwork string GRPCServerAddress string @@ -1559,6 +1562,17 @@ func readAccessControlSettings(iniFile *ini.File, cfg *Cfg) { cfg.RBACPermissionCache = rbac.Key("permission_cache").MustBool(true) cfg.RBACPermissionValidationEnabled = rbac.Key("permission_validation_enabled").MustBool(false) cfg.RBACResetBasicRoles = rbac.Key("reset_basic_roles").MustBool(false) + + rbacOverrides := iniFile.Section("rbac.overrides") + cfg.RBACGrantOverrides = map[string][]string{} + for _, key := range rbacOverrides.Keys() { + value := key.MustString("") + grants := strings.Split(value, ",") + for i, grant := range grants { + grants[i] = strings.TrimSpace(grant) + } + cfg.RBACGrantOverrides[key.Name()] = grants + } } func readUserSettings(iniFile *ini.File, cfg *Cfg) error {