Refactoring tests
This commit is contained in:
@@ -48,7 +48,7 @@ func TestCharts(t *testing.T) {
|
||||
req := require.New(t)
|
||||
svc := &chart{
|
||||
store: s,
|
||||
ac: &accessControl{rbac: &rbac.ServiceAllowAll{}},
|
||||
ac: &accessControl{rbac: rbac.NoopSvc(rbac.Allow)},
|
||||
}
|
||||
res, err := svc.Create(ctx, &types.Chart{Name: "My first chart", NamespaceID: namespaceID})
|
||||
req.NoError(unwrapChartInternal(err))
|
||||
|
||||
@@ -58,10 +58,6 @@ func makeTestModuleService(t *testing.T, mods ...any) *module {
|
||||
}
|
||||
}
|
||||
|
||||
if svc.ac == nil {
|
||||
svc.ac = &accessControl{rbac: rbac.NewService(log, nil)}
|
||||
}
|
||||
|
||||
if svc.store == nil {
|
||||
t.Log("using SQLite in-memory Store")
|
||||
svc.store, err = sqlite.ConnectInMemoryWithDebug(ctx)
|
||||
@@ -78,7 +74,18 @@ func makeTestModuleService(t *testing.T, mods ...any) *module {
|
||||
req.NoError(store.TruncateComposeModuleFields(ctx, svc.store))
|
||||
req.NoError(store.TruncateRbacRules(ctx, svc.store))
|
||||
req.NoError(store.TruncateLabels(ctx, svc.store))
|
||||
}
|
||||
|
||||
if svc.ac == nil {
|
||||
rc, err := rbac.NewService(ctx, log, svc.store, rbac.Config{
|
||||
Synchronous: true,
|
||||
DecayInterval: time.Hour * 2,
|
||||
CleanupInterval: time.Hour * 2,
|
||||
ReindexInterval: time.Hour * 2,
|
||||
IndexFlushInterval: time.Hour * 2,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
svc.ac = &accessControl{rbac: rc}
|
||||
}
|
||||
|
||||
resourceMaker(ctx, t, svc.store, mods...)
|
||||
@@ -122,7 +129,7 @@ func TestModules(t *testing.T) {
|
||||
|
||||
svc := makeTestModuleService(t,
|
||||
ns,
|
||||
&rbac.ServiceAllowAll{},
|
||||
rbac.NoopSvc(rbac.Allow),
|
||||
)
|
||||
|
||||
res, err := svc.Create(ctx, &types.Module{Name: "My first module", NamespaceID: ns.ID})
|
||||
@@ -167,7 +174,7 @@ func TestModule_LabelSearch(t *testing.T) {
|
||||
req = require.New(t)
|
||||
svc = makeTestModuleService(t,
|
||||
ns,
|
||||
&rbac.ServiceAllowAll{},
|
||||
rbac.NoopSvc(rbac.Allow),
|
||||
)
|
||||
|
||||
ctx = context.Background()
|
||||
@@ -239,7 +246,7 @@ func TestModule_LabelCRUD(t *testing.T) {
|
||||
req = require.New(t)
|
||||
svc = makeTestModuleService(t,
|
||||
ns,
|
||||
&rbac.ServiceAllowAll{},
|
||||
rbac.NoopSvc(rbac.Allow),
|
||||
)
|
||||
|
||||
findAndReturnLabel = func(id uint64) map[string]string {
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestPageDeleting(t *testing.T) {
|
||||
|
||||
svc = &page{
|
||||
store: s,
|
||||
ac: &accessControl{rbac: &rbac.ServiceAllowAll{}},
|
||||
ac: &accessControl{rbac: rbac.NoopSvc(rbac.Allow)},
|
||||
eventbus: eventbus.New(),
|
||||
locale: ResourceTranslationsManager(locale.Static()),
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/pkg/revisions"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
@@ -44,6 +45,7 @@ type (
|
||||
|
||||
actionlog actionlog.Recorder
|
||||
|
||||
rbacSvc *rbac.Service
|
||||
ac recordAccessController
|
||||
eventbus eventDispatcher
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/eventbus"
|
||||
@@ -26,7 +27,6 @@ import (
|
||||
)
|
||||
|
||||
func makeTestRecordService(t *testing.T, mods ...any) *record {
|
||||
|
||||
var (
|
||||
err error
|
||||
req = require.New(t)
|
||||
@@ -68,10 +68,6 @@ func makeTestRecordService(t *testing.T, mods ...any) *record {
|
||||
}
|
||||
}
|
||||
|
||||
if svc.ac == nil {
|
||||
svc.ac = &accessControl{rbac: rbac.NewService(log, nil)}
|
||||
}
|
||||
|
||||
if svc.store == nil {
|
||||
svc.store, err = sqlite.ConnectInMemoryWithDebug(ctx)
|
||||
req.NoError(err)
|
||||
@@ -83,7 +79,19 @@ func makeTestRecordService(t *testing.T, mods ...any) *record {
|
||||
req.NoError(store.TruncateComposeModules(ctx, svc.store))
|
||||
req.NoError(store.TruncateComposeModuleFields(ctx, svc.store))
|
||||
req.NoError(store.TruncateRbacRules(ctx, svc.store))
|
||||
}
|
||||
|
||||
if svc.ac == nil {
|
||||
rc, err := rbac.NewService(ctx, log, svc.store, rbac.Config{
|
||||
Synchronous: true,
|
||||
DecayInterval: time.Hour * 2,
|
||||
CleanupInterval: time.Hour * 2,
|
||||
ReindexInterval: time.Hour * 2,
|
||||
IndexFlushInterval: time.Hour * 2,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
svc.rbacSvc = rc
|
||||
svc.ac = &accessControl{rbac: rc}
|
||||
}
|
||||
|
||||
resourceMaker(ctx, t, svc.store, mods...)
|
||||
@@ -264,14 +272,8 @@ func TestRecord_boolFieldPermissionIssueKBR(t *testing.T) {
|
||||
writerRole = &sysTypes.Role{Name: "writer", ID: nextID()}
|
||||
|
||||
//
|
||||
rbacService = rbac.NewService(
|
||||
zap.NewNop(),
|
||||
//logger.MakeDebugLogger(),
|
||||
nil,
|
||||
)
|
||||
|
||||
svc = makeTestRecordService(t,
|
||||
rbacService,
|
||||
logger.MakeDebugLogger(),
|
||||
u,
|
||||
ns,
|
||||
@@ -294,13 +296,13 @@ func TestRecord_boolFieldPermissionIssueKBR(t *testing.T) {
|
||||
|
||||
svc.validator = defaultValidator(svc)
|
||||
|
||||
rbacService.UpdateRoles(
|
||||
svc.rbacSvc.UpdateRoles(
|
||||
rbac.CommonRole.Make(readerRole.ID, readerRole.Name),
|
||||
rbac.CommonRole.Make(writerRole.ID, writerRole.Name),
|
||||
rbac.AuthenticatedRole.Make(authRoleID, "authenticated"),
|
||||
)
|
||||
|
||||
rbacService.Grant(ctx,
|
||||
svc.rbacSvc.Grant(ctx,
|
||||
// base permissions
|
||||
rbac.AllowRule(authRoleID, mod.RbacResource(), "record.create"),
|
||||
rbac.AllowRule(authRoleID, types.RecordRbacResource(0, 0, 0), "read"),
|
||||
@@ -382,12 +384,6 @@ func TestRecord_defValueFieldPermissionIssue(t *testing.T) {
|
||||
req = require.New(t)
|
||||
ctx = context.Background()
|
||||
|
||||
rbacService = rbac.NewService(
|
||||
//zap.NewNop(),
|
||||
logger.MakeDebugLogger(),
|
||||
nil,
|
||||
)
|
||||
|
||||
user = &sysTypes.User{ID: nextID()}
|
||||
|
||||
modConf = types.ModuleConfig{DAL: types.ModuleConfigDAL{ConnectionID: 1}}
|
||||
@@ -398,7 +394,6 @@ func TestRecord_defValueFieldPermissionIssue(t *testing.T) {
|
||||
readableField = &types.ModuleField{ID: nextID(), ModuleID: mod.ID, NamespaceID: ns.ID, Name: "readable", Kind: "String", DefaultValue: types.RecordValueSet{{Value: "def-r"}}}
|
||||
|
||||
svc = makeTestRecordService(t,
|
||||
rbacService,
|
||||
user,
|
||||
ns,
|
||||
mod,
|
||||
@@ -440,12 +435,12 @@ func TestRecord_defValueFieldPermissionIssue(t *testing.T) {
|
||||
|
||||
t.Log("setting up security")
|
||||
|
||||
rbacService.UpdateRoles(
|
||||
svc.rbacSvc.UpdateRoles(
|
||||
rbac.CommonRole.Make(editorRole.ID, editorRole.Name),
|
||||
rbac.AuthenticatedRole.Make(authRoleID, "authenticated"),
|
||||
)
|
||||
|
||||
rbacService.Grant(ctx,
|
||||
svc.rbacSvc.Grant(ctx,
|
||||
// base permissions
|
||||
rbac.AllowRule(authRoleID, mod.RbacResource(), "record.create"),
|
||||
rbac.AllowRule(authRoleID, types.RecordRbacResource(0, 0, 0), "read"),
|
||||
@@ -526,11 +521,6 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
req.NoError(store.TruncateRbacRules(ctx, s))
|
||||
|
||||
var (
|
||||
rbacService = rbac.NewService(
|
||||
//zap.NewNop(),
|
||||
logger.MakeDebugLogger(),
|
||||
nil,
|
||||
)
|
||||
nextIDi uint64 = 1
|
||||
nextID = func() uint64 {
|
||||
nextIDi++
|
||||
@@ -558,7 +548,6 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
testerRole = &sysTypes.Role{Name: "tester", ID: nextID()}
|
||||
|
||||
svc = makeTestRecordService(t,
|
||||
rbacService,
|
||||
user,
|
||||
ns,
|
||||
mod1,
|
||||
@@ -581,7 +570,7 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
svc.validator = defaultValidator(svc)
|
||||
|
||||
t.Log("inform rbac service about new roles")
|
||||
rbacService.UpdateRoles(
|
||||
svc.rbacSvc.UpdateRoles(
|
||||
rbac.CommonRole.Make(testerRole.ID, testerRole.Name),
|
||||
)
|
||||
|
||||
@@ -596,7 +585,7 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
req.EqualError(err, "not allowed to create records")
|
||||
|
||||
t.Logf("granting permissions to create records on this module")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, mod1.RbacResource(), "record.create")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, mod1.RbacResource(), "record.create")))
|
||||
|
||||
t.Log("retry creating record on 1st module; should fail because we do not have permissions to update field")
|
||||
_, _, err = svc.Create(ctx, mod1rec1)
|
||||
@@ -604,7 +593,7 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
req.True(types.IsRecordValueErrorSet(err).HasKind("updateDenied"))
|
||||
|
||||
t.Logf("granting permissions to update records values on module field")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, mod1strField.RbacResource(), "record.value.update")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, mod1strField.RbacResource(), "record.value.update")))
|
||||
|
||||
t.Log("retry creating record on 1st module; should succeed")
|
||||
mod1rec1, _, err = svc.Create(ctx, mod1rec1)
|
||||
@@ -624,17 +613,17 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
req.EqualError(err, "not allowed to create records")
|
||||
|
||||
t.Log("grant record.create on namespace level")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, types.ModuleRbacResource(ns.ID, 0), "record.create")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, types.ModuleRbacResource(ns.ID, 0), "record.create")))
|
||||
|
||||
t.Log("grant record.value.update on namespace level")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, types.ModuleFieldRbacResource(ns.ID, 0, 0), "record.value.update")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, types.ModuleFieldRbacResource(ns.ID, 0, 0), "record.value.update")))
|
||||
|
||||
t.Log("create record on 2nd module with ref to record on the 1st module; most fail, not allowed to read (referenced) mod1rec1")
|
||||
_, _, err = svc.Create(ctx, mod2rec1)
|
||||
req.EqualError(err, "invalid record value input")
|
||||
|
||||
t.Log("grant read on record")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, mod1rec1.RbacResource(), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, mod1rec1.RbacResource(), "read")))
|
||||
|
||||
t.Log("create record on 2nd module with ref to record on the 1st module")
|
||||
mod2rec1, _, err = svc.Create(ctx, mod2rec1)
|
||||
@@ -646,7 +635,7 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
req.EqualError(err, "not allowed to update this record")
|
||||
|
||||
t.Log("grant update on namespace level")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, types.RecordRbacResource(ns.ID, 0, 0), "update")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, types.RecordRbacResource(ns.ID, 0, 0), "update")))
|
||||
|
||||
t.Log("update record on 2nd module with unchanged values")
|
||||
mod2rec1, _, err = svc.Update(ctx, mod2rec1)
|
||||
@@ -664,7 +653,7 @@ func TestRecord_refAccessControl(t *testing.T) {
|
||||
}
|
||||
{
|
||||
t.Log("revoke read on record")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.DenyRule(testerRole.ID, mod1rec1.RbacResource(), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.DenyRule(testerRole.ID, mod1rec1.RbacResource(), "read")))
|
||||
|
||||
t.Log("link 2nd record to 1st one again but w/o permissions; must work, value did not change")
|
||||
mod2rec1.Values = mod2rec1.Values.Set(&types.RecordValue{Name: "ref", Value: fmt.Sprintf("%d", mod1rec1.ID)})
|
||||
@@ -679,12 +668,6 @@ func TestRecord_searchAccessControl(t *testing.T) {
|
||||
req = require.New(t)
|
||||
ctx = context.Background()
|
||||
|
||||
rbacService = rbac.NewService(
|
||||
//zap.NewNop(),
|
||||
logger.MakeDebugLogger(),
|
||||
nil,
|
||||
)
|
||||
|
||||
nextIDi uint64 = 1
|
||||
nextID = func() uint64 {
|
||||
nextIDi++
|
||||
@@ -699,7 +682,6 @@ func TestRecord_searchAccessControl(t *testing.T) {
|
||||
strField = &types.ModuleField{ID: nextID(), NamespaceID: ns.ID, ModuleID: mod.ID, Name: "str", Kind: "String"}
|
||||
|
||||
svc = makeTestRecordService(t,
|
||||
rbacService,
|
||||
user,
|
||||
ns,
|
||||
mod,
|
||||
@@ -734,13 +716,13 @@ func TestRecord_searchAccessControl(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Log("inform rbac service about new roles")
|
||||
rbacService.UpdateRoles(
|
||||
svc.rbacSvc.UpdateRoles(
|
||||
rbac.CommonRole.Make(testerRole.ID, testerRole.Name),
|
||||
)
|
||||
|
||||
t.Log("log-in with test user ")
|
||||
ctx = auth.SetIdentityToContext(ctx, auth.Authenticated(user.ID, testerRole.ID))
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, mod.RbacResource(), "records.search")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, mod.RbacResource(), "records.search")))
|
||||
|
||||
t.Log("search for the newly created records; should not find any (all denied)")
|
||||
f.IncTotal = true
|
||||
@@ -750,8 +732,8 @@ func TestRecord_searchAccessControl(t *testing.T) {
|
||||
req.Equal(uint(0), f.Total)
|
||||
|
||||
t.Log("allow read access for two records")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, rr[3].RbacResource(), "read")))
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(testerRole.ID, rr[6].RbacResource(), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, rr[3].RbacResource(), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(testerRole.ID, rr[6].RbacResource(), "read")))
|
||||
|
||||
t.Log("search for the newly created records; should find 2 we're allowed to read")
|
||||
f.IncTotal = true
|
||||
@@ -770,8 +752,6 @@ func TestRecord_contextualRolesAccessControl(t *testing.T) {
|
||||
//log = zap.NewNop()
|
||||
log = logger.MakeDebugLogger()
|
||||
|
||||
rbacService = rbac.NewService(log, nil)
|
||||
|
||||
nextIDi uint64 = 1
|
||||
nextID = func() uint64 {
|
||||
nextIDi++
|
||||
@@ -794,7 +774,6 @@ func TestRecord_contextualRolesAccessControl(t *testing.T) {
|
||||
boolField = &types.ModuleField{ID: nextID(), NamespaceID: ns.ID, ModuleID: mod.ID, Name: "yes", Kind: "String"}
|
||||
|
||||
svc = makeTestRecordService(t,
|
||||
rbacService,
|
||||
log,
|
||||
user,
|
||||
ns,
|
||||
@@ -878,14 +857,14 @@ func TestRecord_contextualRolesAccessControl(t *testing.T) {
|
||||
// read: x x x x x x x x x (all but one)
|
||||
|
||||
t.Log("inform rbac service about new roles")
|
||||
rbacService.UpdateRoles(
|
||||
svc.rbacSvc.UpdateRoles(
|
||||
rbac.CommonRole.Make(baseRole.ID, baseRole.Name),
|
||||
rbac.MakeContextRole(ownerRole.ID, ownerRole.Name, roleCheckFnMaker("resource.ownedBy == userID"), types.RecordResourceType),
|
||||
rbac.MakeContextRole(truthyRole.ID, truthyRole.Name, roleCheckFnMaker(`has(resource.values, "yes") ? resource.values.yes : false`), types.RecordResourceType),
|
||||
rbac.MakeContextRole(tttRole.ID, tttRole.Name, roleCheckFnMaker(`has(resource.values, "num") ? resource.values.num == 333 : false`), types.RecordResourceType),
|
||||
)
|
||||
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(baseRole.ID, types.ModuleRbacResource(0, 0), "records.search")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(baseRole.ID, types.ModuleRbacResource(0, 0), "records.search")))
|
||||
|
||||
t.Log("log-in with test user")
|
||||
ctx = auth.SetIdentityToContext(ctx, auth.Authenticated(user.ID, baseRole.ID))
|
||||
@@ -896,19 +875,19 @@ func TestRecord_contextualRolesAccessControl(t *testing.T) {
|
||||
req.Len(hits, 0)
|
||||
|
||||
t.Log("expecting to find 5 records (owned by us)")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(ownerRole.ID, types.RecordRbacResource(0, 0, 0), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(ownerRole.ID, types.RecordRbacResource(0, 0, 0), "read")))
|
||||
hits, _, err = svc.Find(ctx, f)
|
||||
req.NoError(err)
|
||||
req.Len(hits, 5)
|
||||
|
||||
t.Log("expecting to find 2 records (owned by us and with true value for 'yes' field)")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(truthyRole.ID, types.RecordRbacResource(0, 0, 0), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(truthyRole.ID, types.RecordRbacResource(0, 0, 0), "read")))
|
||||
hits, _, err = svc.Find(ctx, f)
|
||||
req.NoError(err)
|
||||
req.Len(hits, 8)
|
||||
|
||||
t.Log("expecting to find 2 records (owned by us and with true value for 'yes' field + 333 for num)")
|
||||
req.NoError(rbacService.Grant(ctx, rbac.AllowRule(tttRole.ID, types.RecordRbacResource(0, 0, 0), "read")))
|
||||
req.NoError(svc.rbacSvc.Grant(ctx, rbac.AllowRule(tttRole.ID, types.RecordRbacResource(0, 0, 0), "read")))
|
||||
hits, _, err = svc.Find(ctx, f)
|
||||
req.NoError(err)
|
||||
req.Len(hits, 9)
|
||||
@@ -931,11 +910,13 @@ func TestSetRecordOwner(t *testing.T) {
|
||||
req.NoError(store.TruncateRbacRules(ctx, s))
|
||||
|
||||
var (
|
||||
rbacService = rbac.NewService(
|
||||
zap.NewNop(),
|
||||
//logger.MakeDebugLogger(),
|
||||
nil,
|
||||
)
|
||||
rbacService = rbac.NewServiceMust(ctx, zap.NewNop(), s, rbac.Config{
|
||||
Synchronous: true,
|
||||
DecayInterval: time.Hour * 2,
|
||||
CleanupInterval: time.Hour * 2,
|
||||
ReindexInterval: time.Hour * 2,
|
||||
IndexFlushInterval: time.Hour * 2,
|
||||
})
|
||||
ac = &accessControl{rbac: rbacService}
|
||||
|
||||
invoker = &sysTypes.User{ID: 1001}
|
||||
|
||||
+14
-12
@@ -19,7 +19,7 @@ type (
|
||||
mux sync.RWMutex
|
||||
cfg Config
|
||||
logger *zap.Logger
|
||||
StatLogger *statsLogger
|
||||
StatLogger *StatsLogger
|
||||
|
||||
noop bool
|
||||
noopAccess Access
|
||||
@@ -198,6 +198,15 @@ func NewService(ctx context.Context, l *zap.Logger, store rbacRulesStore, cc Con
|
||||
return
|
||||
}
|
||||
|
||||
func NewServiceMust(ctx context.Context, l *zap.Logger, store rbacRulesStore, cc Config) (svc *Service) {
|
||||
svc, err := NewService(ctx, l, store, cc)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("NewServiceMust failed with: %v", err))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func initUsageCounter(ctx context.Context, cc Config) (svc *usageCounter[string]) {
|
||||
svc = &usageCounter[string]{
|
||||
incChan: make(chan string, 1024),
|
||||
@@ -215,8 +224,8 @@ func initUsageCounter(ctx context.Context, cc Config) (svc *usageCounter[string]
|
||||
return
|
||||
}
|
||||
|
||||
func initStatsLogger(ctx context.Context, l *zap.Logger) (svc *statsLogger) {
|
||||
svc = &statsLogger{
|
||||
func initStatsLogger(ctx context.Context, l *zap.Logger) (svc *StatsLogger) {
|
||||
svc = &StatsLogger{
|
||||
log: l.Named("rbac stats logger"),
|
||||
cacheHitChan: make(chan statsWrap, 1024),
|
||||
cacheMissChan: make(chan statsWrap, 1024),
|
||||
@@ -227,7 +236,7 @@ func initStatsLogger(ctx context.Context, l *zap.Logger) (svc *statsLogger) {
|
||||
return
|
||||
}
|
||||
|
||||
func initSvc(ctx context.Context, l *zap.Logger, cc Config, sl *statsLogger, uc *usageCounter[string]) (svc *Service) {
|
||||
func initSvc(ctx context.Context, l *zap.Logger, cc Config, sl *StatsLogger, uc *usageCounter[string]) (svc *Service) {
|
||||
svc = &Service{
|
||||
logger: l,
|
||||
|
||||
@@ -411,6 +420,7 @@ func (svc *Service) Stats() (out Stats, err error) {
|
||||
|
||||
out.CacheHits,
|
||||
out.CacheMisses,
|
||||
out.CacheUpdates,
|
||||
out.AvgTiming,
|
||||
out.MinTiming,
|
||||
out.MaxTiming,
|
||||
@@ -423,14 +433,6 @@ func (svc *Service) Stats() (out Stats, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// AddRole adds an additional role after the service was initialized
|
||||
func (svc *Service) AddRole(r *Role) {
|
||||
svc.mux.Lock()
|
||||
defer svc.mux.Unlock()
|
||||
|
||||
svc.roles = append(svc.roles, r)
|
||||
}
|
||||
|
||||
func (svc *Service) UpdateRoles(rr ...*Role) {
|
||||
svc.mux.Lock()
|
||||
defer svc.mux.Unlock()
|
||||
|
||||
@@ -3,6 +3,7 @@ package rbac
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
statsLogger struct {
|
||||
StatsLogger struct {
|
||||
lock sync.RWMutex
|
||||
log *zap.Logger
|
||||
|
||||
@@ -44,12 +45,13 @@ type (
|
||||
)
|
||||
|
||||
// Stats returns the tracked stats
|
||||
func (l *statsLogger) Stats() (cacheHit uint, cacheMiss uint, avgTiming, minTiming, maxTiming time.Duration, lastHits []string, lastMisses []string, lastTimings []time.Duration) {
|
||||
func (l *StatsLogger) Stats() (cacheHit uint, cacheMiss uint, cacheUpdates uint, avgTiming, minTiming, maxTiming time.Duration, lastHits []string, lastMisses []string, lastTimings []time.Duration) {
|
||||
l.lock.RLock()
|
||||
defer l.lock.RUnlock()
|
||||
|
||||
return l.cacheHits,
|
||||
l.cacheMisses,
|
||||
l.cacheUpdates,
|
||||
l.avgTiming,
|
||||
l.minTiming,
|
||||
l.maxTiming,
|
||||
@@ -59,7 +61,7 @@ func (l *statsLogger) Stats() (cacheHit uint, cacheMiss uint, avgTiming, minTimi
|
||||
}
|
||||
|
||||
// Timing logs the giving duration
|
||||
func (l *statsLogger) Timing(timing time.Duration) {
|
||||
func (l *StatsLogger) Timing(timing time.Duration) {
|
||||
l.lock.Lock()
|
||||
defer l.lock.Unlock()
|
||||
|
||||
@@ -96,7 +98,7 @@ func (l *statsLogger) Timing(timing time.Duration) {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *statsLogger) CacheHit(roles []uint64, resource string, op string) {
|
||||
func (l *StatsLogger) CacheHit(roles []uint64, resource string, op string) {
|
||||
l.lock.Lock()
|
||||
defer l.lock.Unlock()
|
||||
|
||||
@@ -109,7 +111,7 @@ func (l *statsLogger) CacheHit(roles []uint64, resource string, op string) {
|
||||
l.lastHits.Add(l.strfEntry(roles, resource, op))
|
||||
}
|
||||
|
||||
func (l *statsLogger) CacheMiss(roles []uint64, resource string, op string) {
|
||||
func (l *StatsLogger) CacheMiss(roles []uint64, resource string, op string) {
|
||||
l.lock.Lock()
|
||||
defer l.lock.Unlock()
|
||||
|
||||
@@ -122,7 +124,7 @@ func (l *statsLogger) CacheMiss(roles []uint64, resource string, op string) {
|
||||
l.lastMisses.Add(l.strfEntry(roles, resource, op))
|
||||
}
|
||||
|
||||
func (l *statsLogger) CacheUpdate(in *Rule) {
|
||||
func (l *StatsLogger) CacheUpdate(in *Rule) {
|
||||
l.lock.Lock()
|
||||
defer l.lock.Unlock()
|
||||
|
||||
@@ -134,11 +136,13 @@ func (l *statsLogger) CacheUpdate(in *Rule) {
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Utils
|
||||
|
||||
func (l *statsLogger) strfEntry(roles []uint64, resource string, op string) string {
|
||||
func (l *StatsLogger) strfEntry(roles []uint64, resource string, op string) string {
|
||||
sort.Slice(roles, func(i, j int) bool { return roles[i] < roles[j] })
|
||||
|
||||
return fmt.Sprintf("%v %s %s", roles, op, resource)
|
||||
}
|
||||
|
||||
func (l *statsLogger) watch(ctx context.Context) {
|
||||
func (l *StatsLogger) watch(ctx context.Context) {
|
||||
t := time.NewTicker(time.Minute * 5)
|
||||
|
||||
go func() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -38,8 +39,6 @@ func TestUser_ProtectedSearch(t *testing.T) {
|
||||
|
||||
testUser = &types.User{ID: 42}
|
||||
|
||||
acRBAC = rbac.NewService(zap.NewNop(), nil)
|
||||
|
||||
s store.Storer
|
||||
)
|
||||
|
||||
@@ -49,6 +48,16 @@ func TestUser_ProtectedSearch(t *testing.T) {
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
var (
|
||||
acRBAC = rbac.NewServiceMust(ctx, zap.NewNop(), s, rbac.Config{
|
||||
Synchronous: true,
|
||||
DecayInterval: time.Hour * 2,
|
||||
CleanupInterval: time.Hour * 2,
|
||||
ReindexInterval: time.Hour * 2,
|
||||
IndexFlushInterval: time.Hour * 2,
|
||||
})
|
||||
)
|
||||
|
||||
acRBAC.UpdateRoles(rbac.CommonRole.Make(testRoleID, "test-role"))
|
||||
req.NoError(acRBAC.Grant(ctx,
|
||||
rbac.AllowRule(testRoleID, types.ComponentRbacResource(), "users.search"),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package automation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -8,7 +9,7 @@ import (
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/tests/helpers"
|
||||
"github.com/steinfletcher/apitest-jsonpath"
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
)
|
||||
|
||||
func TestPermissionsEffective(t *testing.T) {
|
||||
@@ -68,6 +69,7 @@ func TestPermissionsUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPermissionsDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
h := newHelper(t)
|
||||
p := rbac.Global()
|
||||
|
||||
@@ -77,12 +79,12 @@ func TestPermissionsDelete(t *testing.T) {
|
||||
// New role.
|
||||
permDelRole := h.roleID + 1
|
||||
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(permDelRole), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, permDelRole)), 0)
|
||||
|
||||
// Setup a few fake rules for new role
|
||||
helpers.Grant(rbac.AllowRule(permDelRole, types.ComponentRbacResource(), "workflow.create"))
|
||||
|
||||
h.a.Len(p.FindRulesByRoleID(permDelRole), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, permDelRole)), 1)
|
||||
|
||||
h.apiInit().
|
||||
Delete(fmt.Sprintf("/permissions/%d/rules", permDelRole)).
|
||||
@@ -93,7 +95,7 @@ func TestPermissionsDelete(t *testing.T) {
|
||||
End()
|
||||
|
||||
// Make sure all rules for this role are deleted
|
||||
for _, r := range p.FindRulesByRoleID(permDelRole) {
|
||||
for _, r := range mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, permDelRole)) {
|
||||
h.a.True(r.Access == rbac.Inherit)
|
||||
}
|
||||
}
|
||||
@@ -113,3 +115,11 @@ func TestPermissionsTrace(t *testing.T) {
|
||||
Assert(jsonpath.Present(`$.response`)).
|
||||
End()
|
||||
}
|
||||
|
||||
func mustFindRulesByRoleID(rr rbac.RuleSet, err error) rbac.RuleSet {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return rr
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -8,7 +9,7 @@ import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/tests/helpers"
|
||||
"github.com/steinfletcher/apitest-jsonpath"
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
)
|
||||
|
||||
func TestPermissionsEffective(t *testing.T) {
|
||||
@@ -74,6 +75,7 @@ func TestPermissionsUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPermissionsDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
h := newHelper(t)
|
||||
p := rbac.Global()
|
||||
|
||||
@@ -83,12 +85,12 @@ func TestPermissionsDelete(t *testing.T) {
|
||||
// New role.
|
||||
permDelRole := h.roleID + 1
|
||||
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(permDelRole), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, permDelRole)), 0)
|
||||
|
||||
// Setup a few fake rules for new role
|
||||
helpers.Grant(rbac.AllowRule(permDelRole, types.ComponentRbacResource(), "namespace.create"))
|
||||
|
||||
h.a.Len(p.FindRulesByRoleID(permDelRole), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, permDelRole)), 1)
|
||||
|
||||
h.apiInit().
|
||||
Delete(fmt.Sprintf("/permissions/%d/rules", permDelRole)).
|
||||
@@ -99,7 +101,7 @@ func TestPermissionsDelete(t *testing.T) {
|
||||
End()
|
||||
|
||||
// Make sure all rules for this role are deleted
|
||||
for _, r := range p.FindRulesByRoleID(permDelRole) {
|
||||
for _, r := range mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, permDelRole)) {
|
||||
h.a.True(r.Access == rbac.Inherit)
|
||||
}
|
||||
}
|
||||
@@ -119,3 +121,11 @@ func TestPermissionsTrace(t *testing.T) {
|
||||
Assert(jsonpath.Present(`$.response`)).
|
||||
End()
|
||||
}
|
||||
|
||||
func mustFindRulesByRoleID(rr rbac.RuleSet, err error) rbac.RuleSet {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return rr
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
automationEnvoy "github.com/cortezaproject/corteza/server/automation/envoy"
|
||||
composeEnvoy "github.com/cortezaproject/corteza/server/compose/envoy"
|
||||
systemEnvoy "github.com/cortezaproject/corteza/server/system/envoy"
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/id"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
"github.com/cortezaproject/corteza/server/tests/helpers"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
sesWrap struct {
|
||||
identity uint64
|
||||
roles []uint64
|
||||
context context.Context
|
||||
}
|
||||
|
||||
resWrap struct {
|
||||
resource string
|
||||
}
|
||||
|
||||
testStorage struct {
|
||||
upserts []*rbac.Rule
|
||||
|
||||
returnRuleSearch []*rbac.Rule
|
||||
}
|
||||
|
||||
svcModFnc func(*rbac.Service)
|
||||
)
|
||||
|
||||
var (
|
||||
defaultEnvoy *envoyx.Service
|
||||
defaultStore store.Storer
|
||||
)
|
||||
|
||||
func init() {
|
||||
helpers.RecursiveDotEnvLoad()
|
||||
id.Init(cli.Context())
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
InitTestApp()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func InitTestApp() {
|
||||
ctx := cli.Context()
|
||||
|
||||
if defaultStore == nil {
|
||||
initStore(ctx)
|
||||
}
|
||||
|
||||
if defaultEnvoy == nil {
|
||||
initSvc(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func initStore(ctx context.Context) {
|
||||
var err error
|
||||
// dsn := "postgres://corteza:corteza@127.0.0.1:3402/testing?sslmode=disable"
|
||||
dsn := "sqlite3+debug://file::memory:?cache=shared&mode=memory"
|
||||
defaultStore, err = store.Connect(ctx, zap.NewNop(), dsn, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = store.Upgrade(ctx, zap.NewNop(), defaultStore)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanup(b *testing.B) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
err := collect(
|
||||
store.TruncateRbacRules(ctx, defaultStore),
|
||||
store.TruncateRoles(ctx, defaultStore),
|
||||
store.TruncateUsers(ctx, defaultStore),
|
||||
)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to decode scenario data: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func collect(ee ...error) error {
|
||||
for _, e := range ee {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initSvc(ctx context.Context) {
|
||||
defaultEnvoy = envoyx.New()
|
||||
defaultEnvoy.AddDecoder(envoyx.DecodeTypeURI,
|
||||
composeEnvoy.YamlDecoder{},
|
||||
systemEnvoy.YamlDecoder{},
|
||||
automationEnvoy.YamlDecoder{},
|
||||
)
|
||||
|
||||
defaultEnvoy.AddEncoder(envoyx.EncodeTypeStore,
|
||||
composeEnvoy.StoreEncoder{},
|
||||
systemEnvoy.StoreEncoder{},
|
||||
automationEnvoy.StoreEncoder{},
|
||||
)
|
||||
}
|
||||
|
||||
func initState(t *testing.T, maxIndexSize int, things ...svcModFnc) (context.Context, *require.Assertions, *rbac.Service, *testStorage) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
store := &testStorage{}
|
||||
svc, err := rbac.NewService(ctx, zap.NewNop(), defaultStore, rbac.Config{
|
||||
Synchronous: true,
|
||||
|
||||
MaxIndexSize: maxIndexSize,
|
||||
PullInitialState: intst,
|
||||
DecayFactor: 1,
|
||||
DecayInterval: time.Hour * 4,
|
||||
CleanupInterval: time.Hour * 4,
|
||||
|
||||
RuleStorage: store,
|
||||
RoleStorage: store,
|
||||
})
|
||||
req.NoError(err)
|
||||
|
||||
for _, f := range things {
|
||||
f(svc)
|
||||
}
|
||||
|
||||
return ctx, req, svc, store
|
||||
}
|
||||
|
||||
func mustStats(req *require.Assertions, svc *rbac.Service) rbac.Stats {
|
||||
stats, err := svc.Stats()
|
||||
req.NoError(err)
|
||||
return stats
|
||||
}
|
||||
|
||||
func must(req *require.Assertions, err error) {
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
func checkHitRatios(req *require.Assertions, stats rbac.Stats, hits, misses uint, lastHitsLastMisses ...[][]uint64) {
|
||||
req.Equal(hits, stats.CacheHits)
|
||||
req.Equal(misses, stats.CacheMisses)
|
||||
|
||||
if len(lastHitsLastMisses) > 0 {
|
||||
for i := 0; i < len(lastHitsLastMisses[0]); i++ {
|
||||
req.Contains(stats.LastHits[i], fmt.Sprintf("%v", lastHitsLastMisses[0][i]))
|
||||
}
|
||||
}
|
||||
|
||||
if len(lastHitsLastMisses) > 1 {
|
||||
for i := 0; i < len(lastHitsLastMisses[1]); i++ {
|
||||
req.Contains(stats.LastMisses[i], fmt.Sprintf("%v", lastHitsLastMisses[1][i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
||||
func (ts *testStorage) SearchRbacRules(ctx context.Context, f rbac.RuleFilter) (rs rbac.RuleSet, rf rbac.RuleFilter, er error) {
|
||||
return ts.returnRuleSearch, f, nil
|
||||
}
|
||||
|
||||
func (ts *testStorage) UpsertRbacRule(ctx context.Context, rr ...*rbac.Rule) (err error) {
|
||||
ts.upserts = append(ts.upserts, rr...)
|
||||
return
|
||||
}
|
||||
|
||||
func (testStorage) DeleteRbacRule(ctx context.Context, rr ...*rbac.Rule) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (testStorage) TruncateRbacRules(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (testStorage) SearchRoles(ctx context.Context, f types.RoleFilter) (rs types.RoleSet, rf types.RoleFilter, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (sw sesWrap) Identity() uint64 {
|
||||
return sw.identity
|
||||
}
|
||||
func (sw sesWrap) Roles() []uint64 {
|
||||
return sw.roles
|
||||
}
|
||||
func (sw sesWrap) Context() context.Context {
|
||||
return sw.context
|
||||
}
|
||||
|
||||
func (rw resWrap) RbacResource() string {
|
||||
return rw.resource
|
||||
}
|
||||
|
||||
func svcWithRoles(roles ...*rbac.Role) svcModFnc {
|
||||
return func(s *rbac.Service) {
|
||||
s.UpdateRoles(roles...)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
)
|
||||
|
||||
func TestGrant(t *testing.T) {
|
||||
t.Run("completely empty index", func(t *testing.T) {
|
||||
ctx,
|
||||
req,
|
||||
svc,
|
||||
storage := initState(t, 0)
|
||||
|
||||
svc.Grant(ctx, &rbac.Rule{
|
||||
RoleID: 1,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
})
|
||||
|
||||
// No cache update since resource not indexed
|
||||
stats := mustStats(req, svc)
|
||||
req.Len(storage.upserts, 1)
|
||||
req.Equal(uint(0), stats.CacheUpdates)
|
||||
})
|
||||
|
||||
t.Run("granting existing resource", func(t *testing.T) {
|
||||
ctx,
|
||||
req,
|
||||
svc,
|
||||
storage := initState(t, 0)
|
||||
|
||||
must(req, svc.DebuggerSetIndex(1, "smt/1/1/1", &rbac.Rule{
|
||||
RoleID: 1,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "write",
|
||||
Access: rbac.Allow,
|
||||
}))
|
||||
|
||||
svc.Grant(ctx, &rbac.Rule{
|
||||
RoleID: 1,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
})
|
||||
|
||||
// Updated the index since resource indexed
|
||||
stt := mustStats(req, svc)
|
||||
req.Len(storage.upserts, 1)
|
||||
req.Equal(uint(1), stt.CacheUpdates)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheck(t *testing.T) {
|
||||
t.Run("completely empty index", func(t *testing.T) {
|
||||
ctx,
|
||||
req,
|
||||
svc,
|
||||
storage := initState(
|
||||
t,
|
||||
0,
|
||||
svcWithRoles(rbac.CommonRole.Make(1, "")),
|
||||
)
|
||||
|
||||
storage.returnRuleSearch = []*rbac.Rule{{
|
||||
RoleID: 1,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
}}
|
||||
|
||||
req.True(svc.Can(sesWrap{
|
||||
identity: 1,
|
||||
roles: []uint64{1},
|
||||
context: ctx,
|
||||
}, "read", resWrap{resource: "smt/1/1/1"}))
|
||||
|
||||
checkHitRatios(req, mustStats(req, svc), 0, 1)
|
||||
})
|
||||
|
||||
t.Run("half index, half unindex", func(t *testing.T) {
|
||||
ctx,
|
||||
req,
|
||||
svc,
|
||||
storage := initState(
|
||||
t,
|
||||
0,
|
||||
svcWithRoles(rbac.CommonRole.Make(1, ""), rbac.CommonRole.Make(2, "")),
|
||||
)
|
||||
|
||||
storage.returnRuleSearch = []*rbac.Rule{{
|
||||
RoleID: 2,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
}}
|
||||
|
||||
must(req, svc.DebuggerSetIndex(1, "smt/1/1/1", &rbac.Rule{
|
||||
RoleID: 1,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
}))
|
||||
|
||||
req.True(svc.Can(sesWrap{
|
||||
identity: 1,
|
||||
roles: []uint64{1, 2},
|
||||
context: ctx,
|
||||
}, "read", resWrap{resource: "smt/1/1/1"}))
|
||||
|
||||
checkHitRatios(req, mustStats(req, svc), 1, 1, [][]uint64{{1}}, [][]uint64{{2}})
|
||||
})
|
||||
|
||||
t.Run("all hits", func(t *testing.T) {
|
||||
ctx,
|
||||
req,
|
||||
svc,
|
||||
_ := initState(
|
||||
t,
|
||||
0,
|
||||
svcWithRoles(
|
||||
rbac.CommonRole.Make(1, ""),
|
||||
rbac.CommonRole.Make(2, ""),
|
||||
),
|
||||
)
|
||||
|
||||
must(req, svc.DebuggerSetIndex(1, "smt/1/1/1", &rbac.Rule{
|
||||
RoleID: 1,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
}))
|
||||
|
||||
must(req, svc.DebuggerAddIndex(2, "smt/1/1/1", &rbac.Rule{
|
||||
RoleID: 2,
|
||||
Resource: "smt/1/1/1",
|
||||
Operation: "read",
|
||||
Access: rbac.Allow,
|
||||
}))
|
||||
|
||||
req.True(svc.Can(sesWrap{
|
||||
identity: 1,
|
||||
roles: []uint64{1, 2},
|
||||
context: ctx,
|
||||
}, "read", resWrap{resource: "smt/1/1/1"}))
|
||||
|
||||
checkHitRatios(req, mustStats(req, svc), 1, 0, [][]uint64{{1, 2}})
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -117,6 +118,8 @@ func TestPermissionsUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPermissionsDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
h := newHelper(t)
|
||||
p := rbac.Global()
|
||||
|
||||
@@ -126,12 +129,14 @@ func TestPermissionsDelete(t *testing.T) {
|
||||
// New role.
|
||||
permDelRole := h.roleID + 1
|
||||
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(permDelRole), 0)
|
||||
rr := mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, permDelRole))
|
||||
h.a.Len(rr, 0)
|
||||
|
||||
// Setup a few fake rules for new role
|
||||
helpers.Grant(rbac.AllowRule(permDelRole, types.ComponentRbacResource(), "user.create"))
|
||||
|
||||
h.a.Len(p.FindRulesByRoleID(permDelRole), 1)
|
||||
rr = mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, permDelRole))
|
||||
h.a.Len(rr, 1)
|
||||
|
||||
h.apiInit().
|
||||
Delete(fmt.Sprintf("/permissions/%d/rules", permDelRole)).
|
||||
@@ -142,7 +147,8 @@ func TestPermissionsDelete(t *testing.T) {
|
||||
End()
|
||||
|
||||
// Make sure all rules for this role are deleted
|
||||
for _, r := range p.FindRulesByRoleID(permDelRole) {
|
||||
rr = mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, permDelRole))
|
||||
for _, r := range rr {
|
||||
h.a.True(r.Access == rbac.Inherit)
|
||||
}
|
||||
}
|
||||
@@ -166,6 +172,7 @@ func TestPermissionsTrace(t *testing.T) {
|
||||
func TestPermissionsCloneToSingleRole(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
p := rbac.Global()
|
||||
ctx := context.Background()
|
||||
|
||||
// Make sure our user can grant
|
||||
helpers.AllowMe(h, types.ComponentRbacResource(), "grant")
|
||||
@@ -174,8 +181,8 @@ func TestPermissionsCloneToSingleRole(t *testing.T) {
|
||||
roleS := h.roleID + 1
|
||||
roleT := h.roleID + 2
|
||||
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleS), 0)
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleT), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleS)), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleT)), 0)
|
||||
|
||||
// Set up a few fake rules for new role
|
||||
helpers.Grant(rbac.AllowRule(roleS, types.ComponentRbacResource(), "user.create"))
|
||||
@@ -183,8 +190,8 @@ func TestPermissionsCloneToSingleRole(t *testing.T) {
|
||||
helpers.Grant(rbac.AllowRule(roleT, types.ComponentRbacResource(), "user.update"))
|
||||
helpers.Grant(rbac.AllowRule(roleT, types.ComponentRbacResource(), "user.delete"))
|
||||
|
||||
h.a.Len(p.FindRulesByRoleID(roleS), 1)
|
||||
h.a.Len(p.FindRulesByRoleID(roleT), 2)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleS)), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleT)), 2)
|
||||
|
||||
h.apiInit().
|
||||
Post(fmt.Sprintf("/roles/%d/rules/clone", roleS)).
|
||||
@@ -196,12 +203,13 @@ func TestPermissionsCloneToSingleRole(t *testing.T) {
|
||||
End()
|
||||
|
||||
// Make sure all rules for role S are intact
|
||||
h.a.Len(p.FindRulesByRoleID(roleS), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleS)), 1)
|
||||
// Make sure all rules for role T are cloned from role S
|
||||
h.a.Len(p.FindRulesByRoleID(roleT), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleT)), 1)
|
||||
}
|
||||
|
||||
func TestPermissionsCloneToMultipleRole(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
h := newHelper(t)
|
||||
p := rbac.Global()
|
||||
|
||||
@@ -213,9 +221,9 @@ func TestPermissionsCloneToMultipleRole(t *testing.T) {
|
||||
roleT := h.roleID + 2
|
||||
roleY := h.roleID + 3
|
||||
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleS), 0)
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleT), 0)
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleY), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleS)), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleT)), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleY)), 0)
|
||||
|
||||
// Set up a few fake rules for new role
|
||||
helpers.Grant(rbac.AllowRule(roleS, types.ComponentRbacResource(), "user.create"))
|
||||
@@ -227,9 +235,9 @@ func TestPermissionsCloneToMultipleRole(t *testing.T) {
|
||||
helpers.Grant(rbac.AllowRule(roleY, types.ComponentRbacResource(), "user.update"))
|
||||
helpers.Grant(rbac.AllowRule(roleY, types.ComponentRbacResource(), "user.delete"))
|
||||
|
||||
h.a.Len(p.FindRulesByRoleID(roleS), 1)
|
||||
h.a.Len(p.FindRulesByRoleID(roleT), 2)
|
||||
h.a.Len(p.FindRulesByRoleID(roleY), 3)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleS)), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleT)), 2)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleY)), 3)
|
||||
|
||||
h.apiInit().
|
||||
Post(fmt.Sprintf("/roles/%d/rules/clone", roleS)).
|
||||
@@ -242,14 +250,15 @@ func TestPermissionsCloneToMultipleRole(t *testing.T) {
|
||||
End()
|
||||
|
||||
// Make sure all rules for role S are intact
|
||||
h.a.Len(p.FindRulesByRoleID(roleS), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleS)), 1)
|
||||
// Make sure all rules for role T are cloned from role S
|
||||
h.a.Len(p.FindRulesByRoleID(roleT), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleT)), 1)
|
||||
// Make sure all rules for role Y are cloned from role S
|
||||
h.a.Len(p.FindRulesByRoleID(roleY), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleY)), 1)
|
||||
}
|
||||
|
||||
func TestPermissionsCloneNotAllowed(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
h := newHelper(t)
|
||||
p := rbac.Global()
|
||||
|
||||
@@ -257,8 +266,8 @@ func TestPermissionsCloneNotAllowed(t *testing.T) {
|
||||
roleS := h.roleID + 1
|
||||
roleT := h.roleID + 2
|
||||
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleS), 0)
|
||||
h.a.Len(rbac.Global().FindRulesByRoleID(roleT), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleS)), 0)
|
||||
h.a.Len(mustFindRulesByRoleID(rbac.Global().FindRulesByRoleID(ctx, roleT)), 0)
|
||||
|
||||
// Set up a few fake rules for new role
|
||||
helpers.Grant(rbac.AllowRule(roleS, types.ComponentRbacResource(), "user.create"))
|
||||
@@ -266,8 +275,8 @@ func TestPermissionsCloneNotAllowed(t *testing.T) {
|
||||
helpers.Grant(rbac.AllowRule(roleT, types.ComponentRbacResource(), "user.update"))
|
||||
helpers.Grant(rbac.AllowRule(roleT, types.ComponentRbacResource(), "user.delete"))
|
||||
|
||||
h.a.Len(p.FindRulesByRoleID(roleS), 1)
|
||||
h.a.Len(p.FindRulesByRoleID(roleT), 2)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleS)), 1)
|
||||
h.a.Len(mustFindRulesByRoleID(p.FindRulesByRoleID(ctx, roleT)), 2)
|
||||
|
||||
h.apiInit().
|
||||
Post(fmt.Sprintf("/roles/%d/rules/clone", roleS)).
|
||||
@@ -278,3 +287,11 @@ func TestPermissionsCloneNotAllowed(t *testing.T) {
|
||||
Assert(helpers.AssertError("role.errors.notAllowedToCloneRules")).
|
||||
End()
|
||||
}
|
||||
|
||||
func mustFindRulesByRoleID(rr rbac.RuleSet, err error) rbac.RuleSet {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return rr
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ func Test0002_rbac_fn(t *testing.T) {
|
||||
|
||||
loadScenario(ctx, t)
|
||||
|
||||
req.Len(rbac.Global().Rules(), 0)
|
||||
rr, err := rbac.Global().Rules(ctx)
|
||||
req.NoError(err)
|
||||
req.Len(rr, 0)
|
||||
|
||||
var (
|
||||
aux = struct {
|
||||
@@ -30,5 +32,7 @@ func Test0002_rbac_fn(t *testing.T) {
|
||||
req.NoError(vars.Decode(&aux))
|
||||
req.Equal("y", aux.CanCurrentRead)
|
||||
req.Equal("n", aux.CanOtherRead)
|
||||
req.Len(rbac.Global().Rules(), 1)
|
||||
rr, err = rbac.Global().Rules(ctx)
|
||||
req.NoError(err)
|
||||
req.Len(rr, 1)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/cortezaproject/corteza/server/automation/service"
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/tests/helpers"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -46,8 +45,6 @@ func Test_exec_permissions(t *testing.T) {
|
||||
executors.ID,
|
||||
)
|
||||
|
||||
rbac.Global().Reload(ctx)
|
||||
|
||||
t.Run("exec allowed", func(t *testing.T) {
|
||||
ctx = auth.SetIdentityToContext(ctx, execAllowed)
|
||||
_, _ = mustExecWorkflow(ctx, t, "wf", types.WorkflowExecParams{})
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
sysTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/cortezaproject/corteza/server/tests/helpers"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -46,8 +45,6 @@ func Test_invoker_and_runner_in_scope(t *testing.T) {
|
||||
wfInvokers.ID,
|
||||
)
|
||||
|
||||
rbac.Global().Reload(ctx)
|
||||
|
||||
t.Run("invoker set in scope", func(t *testing.T) {
|
||||
var (
|
||||
req = require.New(t)
|
||||
|
||||
Reference in New Issue
Block a user