From 0466ffeebc9e989ceaa052e00ff2a982babb7a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Thu, 9 Jun 2022 15:14:34 +0200 Subject: [PATCH] Rework pkg/rbac with new resource index struct --- pkg/rbac/resource_test.go | 6 ++++-- pkg/rbac/rule.go | 33 +++++++++++++++++++++++++++++---- pkg/rbac/ruleset_checks.go | 18 +++++++++++++++++- pkg/rbac/ruleset_checks_test.go | 10 ++++++---- pkg/rbac/service.go | 2 +- 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/pkg/rbac/resource_test.go b/pkg/rbac/resource_test.go index 479a27bc3..bbdba93de 100644 --- a/pkg/rbac/resource_test.go +++ b/pkg/rbac/resource_test.go @@ -82,8 +82,10 @@ func benchmarkMatchResource(b *testing.B, c int) { b.StartTimer() for n := 0; n < b.N; n++ { - matchResource("corteza::test/a/1/1/1", "corteza::test/a/1/1/1") - matchResource("corteza::test/a/*/*/1", "corteza::test/a/1/1/1") + for i := 0; i < c; i++ { + matchResource("corteza::test/a/1/1/1", "corteza::test/a/1/1/1") + matchResource("corteza::test/a/*/*/1", "corteza::test/a/1/1/1") + } } b.StopTimer() diff --git a/pkg/rbac/rule.go b/pkg/rbac/rule.go index 27ad04ca0..d9d2a02dd 100644 --- a/pkg/rbac/rule.go +++ b/pkg/rbac/rule.go @@ -2,6 +2,9 @@ package rbac import ( "fmt" + "strings" + + "github.com/cortezaproject/corteza-server/pkg/resource" ) type ( @@ -17,10 +20,19 @@ type ( RuleSet []*Rule + ruleIndexWrap struct { + index *resource.IndexNode + rules RuleSet + } + // OptRuleSet RBAC rule index (operation / role ID / rules) - OptRuleSet map[string]map[uint64]RuleSet + OptRuleSet map[string]map[uint64]*ruleIndexWrap ) +func (r Rule) Clone() *Rule { + return &r +} + func (r Rule) String() string { return fmt.Sprintf("%s %d to %s on %s", r.Access, r.RoleID, r.Operation, r.Resource) } @@ -29,19 +41,32 @@ func indexRules(rules []*Rule) OptRuleSet { i := make(OptRuleSet) for _, r := range rules { if i[r.Operation] == nil { - i[r.Operation] = make(map[uint64]RuleSet) + i[r.Operation] = make(map[uint64]*ruleIndexWrap) } if i[r.Operation][r.RoleID] == nil { - i[r.Operation][r.RoleID] = RuleSet{} + i[r.Operation][r.RoleID] = &ruleIndexWrap{ + index: resource.NewIndex(), + } } - i[r.Operation][r.RoleID] = append(i[r.Operation][r.RoleID], r) + i[r.Operation][r.RoleID].index.Add(r, r.IndexPath()...) + i[r.Operation][r.RoleID].rules = append(i[r.Operation][r.RoleID].rules, r) } return i } +func (r Rule) IndexPath() (out [][]string) { + pts := strings.Split(r.Resource, pathSep) + + for _, p := range pts { + out = append(out, []string{p}) + } + + return +} + func (set RuleSet) Len() int { return len(set) } func (set RuleSet) Swap(i, j int) { set[i], set[j] = set[j], set[i] } func (set RuleSet) Less(i, j int) bool { diff --git a/pkg/rbac/ruleset_checks.go b/pkg/rbac/ruleset_checks.go index a2e840f1b..90311f656 100644 --- a/pkg/rbac/ruleset_checks.go +++ b/pkg/rbac/ruleset_checks.go @@ -2,6 +2,7 @@ package rbac import ( "sort" + "strings" ) func check(indexedRules OptRuleSet, rolesByKind partRoles, op, res string) Access { @@ -44,7 +45,11 @@ func check(indexedRules OptRuleSet, rolesByKind partRoles, op, res string) Acces if !rolesByKind[kind][roleID] { continue } - rules = append(rules, r...) + + aux := r.index.Collect(resourceToIndexPath(res)...) + for _, a := range aux { + rules = append(rules, a.(*Rule)) + } } access := checkRulesByResource(rules, op, res) @@ -89,3 +94,14 @@ func member(r partRoles, k roleKind) bool { return false } + +// utility to get the resource index path from the resource identifier +func resourceToIndexPath(r string) (out [][]string) { + pts := strings.Split(r, pathSep) + + for _, pt := range pts { + out = append(out, []string{pt}) + } + + return +} diff --git a/pkg/rbac/ruleset_checks_test.go b/pkg/rbac/ruleset_checks_test.go index 5f24378ff..e1c9508dd 100644 --- a/pkg/rbac/ruleset_checks_test.go +++ b/pkg/rbac/ruleset_checks_test.go @@ -105,9 +105,11 @@ func benchmarkCheck(b *testing.B, c int) { for i := 0; i < cap(rules); i++ { rules = append(rules, &Rule{ - RoleID: uint64(rand.Int31n(50)), - Resource: fmt.Sprintf("res-%d", rand.Int31n(1000)), - Operation: fmt.Sprintf("op-%d", rand.Int31n(100)), + // one over because interval is [a, b) + // lowered others to make the cases more resource intensive + RoleID: uint64(rand.Int31n(10)), + Resource: fmt.Sprintf("res-%d", rand.Int31n(10)), + Operation: fmt.Sprintf("op-%d", rand.Int31n(5)), Access: Access(rand.Int31n(2)), }) } @@ -117,7 +119,7 @@ func benchmarkCheck(b *testing.B, c int) { b.StartTimer() for n := 0; n < b.N; n++ { - check(iRules, pr, "res-0", "op-0") + check(iRules, pr, "op-0", "res-0") } b.StopTimer() diff --git a/pkg/rbac/service.go b/pkg/rbac/service.go index f5172fc18..d379c92d9 100644 --- a/pkg/rbac/service.go +++ b/pkg/rbac/service.go @@ -279,7 +279,7 @@ func (svc service) String() (out string) { for _, byRole := range svc.indexed { for _, rr := range byRole { - for _, r := range rr { + for _, r := range rr.rules { out += fmt.Sprintf(tpl, r.Access, r.Operation, role(r.RoleID), r.Resource) } }