diff --git a/server/app/boot_levels.go b/server/app/boot_levels.go index c58153834..b5f8889fd 100644 --- a/server/app/boot_levels.go +++ b/server/app/boot_levels.go @@ -258,7 +258,10 @@ func (app *CortezaApp) Provision(ctx context.Context) (err error) { // @todo envoy should be decoupled from RBAC and import directly into store, // w/o using any access control - rbac.SetGlobal(rbac.NoopSvc(rbac.Allow)) + rbac.SetGlobal(rbac.NoopSvc(rbac.Allow, rbac.Config{ + RuleStorage: app.Store, + RoleStorage: app.Store, + })) defer rbac.SetGlobal(nil) } diff --git a/server/compose/service/chart_test.go b/server/compose/service/chart_test.go index ed90bf307..e125477ea 100644 --- a/server/compose/service/chart_test.go +++ b/server/compose/service/chart_test.go @@ -48,7 +48,10 @@ func TestCharts(t *testing.T) { req := require.New(t) svc := &chart{ store: s, - ac: &accessControl{rbac: rbac.NoopSvc(rbac.Allow)}, + ac: &accessControl{rbac: rbac.NoopSvc(rbac.Allow, rbac.Config{ + RuleStorage: s, + RoleStorage: s, + })}, } res, err := svc.Create(ctx, &types.Chart{Name: "My first chart", NamespaceID: namespaceID}) req.NoError(unwrapChartInternal(err)) diff --git a/server/compose/service/module_test.go b/server/compose/service/module_test.go index f0ed07b08..0c3892b7e 100644 --- a/server/compose/service/module_test.go +++ b/server/compose/service/module_test.go @@ -83,6 +83,8 @@ func makeTestModuleService(t *testing.T, mods ...any) *module { CleanupInterval: time.Hour * 2, ReindexInterval: time.Hour * 2, IndexFlushInterval: time.Hour * 2, + RuleStorage: svc.store, + RoleStorage: svc.store, }) require.NoError(t, err) svc.ac = &accessControl{rbac: rc} @@ -129,7 +131,7 @@ func TestModules(t *testing.T) { svc := makeTestModuleService(t, ns, - rbac.NoopSvc(rbac.Allow), + rbac.NoopSvc(rbac.Allow, rbac.Config{}), ) res, err := svc.Create(ctx, &types.Module{Name: "My first module", NamespaceID: ns.ID}) @@ -174,7 +176,7 @@ func TestModule_LabelSearch(t *testing.T) { req = require.New(t) svc = makeTestModuleService(t, ns, - rbac.NoopSvc(rbac.Allow), + rbac.NoopSvc(rbac.Allow, rbac.Config{}), ) ctx = context.Background() @@ -246,7 +248,7 @@ func TestModule_LabelCRUD(t *testing.T) { req = require.New(t) svc = makeTestModuleService(t, ns, - rbac.NoopSvc(rbac.Allow), + rbac.NoopSvc(rbac.Allow, rbac.Config{}), ) findAndReturnLabel = func(id uint64) map[string]string { diff --git a/server/compose/service/page_test.go b/server/compose/service/page_test.go index b0485eaf7..5a04bee2f 100644 --- a/server/compose/service/page_test.go +++ b/server/compose/service/page_test.go @@ -49,8 +49,11 @@ func TestPageDeleting(t *testing.T) { } svc = &page{ - store: s, - ac: &accessControl{rbac: rbac.NoopSvc(rbac.Allow)}, + store: s, + ac: &accessControl{rbac: rbac.NoopSvc(rbac.Allow, rbac.Config{ + RuleStorage: s, + RoleStorage: s, + })}, eventbus: eventbus.New(), locale: ResourceTranslationsManager(locale.Static()), } diff --git a/server/compose/service/record_test.go b/server/compose/service/record_test.go index 0dd046134..11b3c0b32 100644 --- a/server/compose/service/record_test.go +++ b/server/compose/service/record_test.go @@ -88,6 +88,8 @@ func makeTestRecordService(t *testing.T, mods ...any) *record { CleanupInterval: time.Hour * 2, ReindexInterval: time.Hour * 2, IndexFlushInterval: time.Hour * 2, + RuleStorage: svc.store, + RoleStorage: svc.store, }) require.NoError(t, err) svc.rbacSvc = rc @@ -263,8 +265,8 @@ func TestRecord_boolFieldPermissionIssueKBR(t *testing.T) { modConf = types.ModuleConfig{DAL: types.ModuleConfigDAL{ConnectionID: 1}} mod = &types.Module{ID: nextID(), NamespaceID: ns.ID, Config: modConf} - stringField = &types.ModuleField{ID: nextID(), ModuleID: mod.ID, Name: "string", Kind: "String"} - boolField = &types.ModuleField{ID: nextID(), ModuleID: mod.ID, Name: "bool", Kind: "Boolean"} + stringField = &types.ModuleField{ID: nextID(), NamespaceID: ns.ID, ModuleID: mod.ID, Name: "string", Kind: "String"} + boolField = &types.ModuleField{ID: nextID(), NamespaceID: ns.ID, ModuleID: mod.ID, Name: "bool", Kind: "Boolean"} authRoleID uint64 = 1 @@ -916,6 +918,8 @@ func TestSetRecordOwner(t *testing.T) { CleanupInterval: time.Hour * 2, ReindexInterval: time.Hour * 2, IndexFlushInterval: time.Hour * 2, + RuleStorage: s, + RoleStorage: s, }) ac = &accessControl{rbac: rbacService} diff --git a/server/pkg/rbac/service.go b/server/pkg/rbac/service.go index 5757a9ca7..3d6dd93ec 100644 --- a/server/pkg/rbac/service.go +++ b/server/pkg/rbac/service.go @@ -169,10 +169,16 @@ func SetGlobal(svc *Service) { } // NoopSvc creates a blank RBAC service which always returns the stated access -func NoopSvc(access Access) (svc *Service) { +func NoopSvc(access Access, cc Config) (svc *Service) { return &Service{ noop: true, noopAccess: access, + logger: zap.NewNop(), + + RuleStorage: cc.RuleStorage, + RoleStorage: cc.RoleStorage, + + cfg: cc, } } @@ -856,7 +862,7 @@ func (svc *Service) segmentRoles(roles partRoles, resource string) (indexed, uni unindexed = partRoles{} indexed = partRoles{} - if svc.index.index.empty() { + if svc.index == nil || svc.index.index == nil || svc.index.index.empty() { return indexed, roles, nil } @@ -949,9 +955,11 @@ func (svc *Service) incCounterSync(roles partRoles, res Resource) { } func (svc *Service) incCounterAsync(roles partRoles, res Resource) { - for _, rr := range roles { - for r := range rr { - svc.usageCounter.incChan <- fmt.Sprintf("%d:%s", r, res.RbacResource()) + if svc.usageCounter != nil && svc.usageCounter.incChan != nil { + for _, rr := range roles { + for r := range rr { + svc.usageCounter.incChan <- fmt.Sprintf("%d:%s", r, res.RbacResource()) + } } } } @@ -963,8 +971,10 @@ func (svc *Service) cleanupCounterSync(roles ...*Role) { } func (svc *Service) cleanupCounterAsync(roles ...*Role) { - for _, r := range roles { - svc.usageCounter.rmChan <- r.id + if svc.usageCounter != nil && svc.usageCounter.rmChan != nil { + for _, r := range roles { + svc.usageCounter.rmChan <- r.id + } } } @@ -1081,7 +1091,9 @@ func (svc *Service) logAccessSync(timing time.Duration) { } func (svc *Service) logAccessAsync(timing time.Duration) { - svc.StatLogger.timingChan <- timing + if svc.StatLogger != nil && svc.StatLogger.timingChan != nil { + svc.StatLogger.timingChan <- timing + } } func (svc *Service) logCachePerformance(hits, misses partRoles, resource, op string) { @@ -1124,7 +1136,7 @@ func (svc *Service) logCachePerformanceSync(hits, misses partRoles, resource, op func (svc *Service) logCachePerformanceAsync(hits, misses partRoles, resource, op string) { // Hits - { + if svc.StatLogger != nil && svc.StatLogger.cacheHitChan != nil { rls := make([]uint64, 0, 4) for _, rr := range hits { @@ -1142,7 +1154,7 @@ func (svc *Service) logCachePerformanceAsync(hits, misses partRoles, resource, o } // Misses - { + if svc.StatLogger != nil && svc.StatLogger.cacheMissChan != nil { rls := make([]uint64, 0, 4) for _, rr := range misses { diff --git a/server/pkg/rbac/svc_index.go b/server/pkg/rbac/svc_index.go index e809db87f..f702a4231 100644 --- a/server/pkg/rbac/svc_index.go +++ b/server/pkg/rbac/svc_index.go @@ -30,6 +30,10 @@ func (svc *wrapperIndex) add(role uint64, resource string, rules ...*Rule) { } func (svc *wrapperIndex) get(role uint64, op string, res string) (out []*Rule) { + if svc == nil { + return + } + svc.mux.RLock() defer svc.mux.RUnlock() diff --git a/server/system/service/user_test.go b/server/system/service/user_test.go index 01f682301..0465eb058 100644 --- a/server/system/service/user_test.go +++ b/server/system/service/user_test.go @@ -55,6 +55,8 @@ func TestUser_ProtectedSearch(t *testing.T) { CleanupInterval: time.Hour * 2, ReindexInterval: time.Hour * 2, IndexFlushInterval: time.Hour * 2, + RuleStorage: s, + RoleStorage: s, }) ) diff --git a/server/tests/compose/module_test.go b/server/tests/compose/module_test.go index 46fad53b9..5b5119653 100644 --- a/server/tests/compose/module_test.go +++ b/server/tests/compose/module_test.go @@ -160,7 +160,7 @@ func TestModuleList_filterForbidden(t *testing.T) { h.makeModule(ns, "module") f := h.makeModule(ns, "module_forbidden") - helpers.DenyMe(h, types.ModuleRbacResource(0, f.ID), "read") + helpers.DenyMe(h, types.ModuleRbacResource(f.NamespaceID, f.ID), "read") h.apiInit(). Get(fmt.Sprintf("/namespace/%d/module/", ns.ID)). diff --git a/server/tests/compose/record_test.go b/server/tests/compose/record_test.go index 1e0d1ff6c..ee434c664 100644 --- a/server/tests/compose/record_test.go +++ b/server/tests/compose/record_test.go @@ -326,7 +326,7 @@ func TestRecordListForbiddenFields(t *testing.T) { module := h.repoMakeRecordModuleWithFields("record testing module") helpers.AllowMe(h, module.RbacResource(), "records.create", "records.search") - helpers.DenyMe(h, types.ModuleFieldRbacResource(0, 0, module.Fields[0].ID), "record.value.read") + helpers.DenyMe(h, types.ModuleFieldRbacResource(module.NamespaceID, module.ID, module.Fields[0].ID), "record.value.read") h.makeRecord(module, &types.RecordValue{Name: "name", Value: "v_name_0"}, &types.RecordValue{Name: "email", Value: "v_email_0"}) h.makeRecord(module, &types.RecordValue{Name: "name", Value: "v_name_1"}, &types.RecordValue{Name: "email", Value: "v_email_1"}) @@ -657,9 +657,9 @@ func TestRecordUpdate_forbiddenFields(t *testing.T) { &types.RecordValue{Name: "f-b-t-n", Value: "1"}, // no-value &types.RecordValue{Name: "f-b-t-v", Value: "1"}, // value ) - helpers.AllowMe(h, types.RecordRbacResource(0, 0, record.ID), "update") + helpers.AllowMe(h, types.RecordRbacResource(record.NamespaceID, record.ModuleID, record.ID), "update") helpers.AllowMe(h, module.Fields[0].RbacResource(), "record.value.update") - helpers.DenyMe(h, types.ModuleFieldRbacResource(0, record.ModuleID, 0), "record.value.update") + helpers.DenyMe(h, types.ModuleFieldRbacResource(record.NamespaceID, record.ModuleID, 0), "record.value.update") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)).