3
0

Improve RBAC rule migration logic

* Add missing federation rule edgecases
* Properly construct resource paths using parent resources
This commit is contained in:
Tomaž Jerman
2021-09-29 19:26:21 +02:00
committed by Denis Arh
parent 9929886372
commit a122d75b8f
2 changed files with 153 additions and 9 deletions

View File

@@ -7,12 +7,24 @@ import (
composeTypes "github.com/cortezaproject/corteza-server/compose/types"
federationTypes "github.com/cortezaproject/corteza-server/federation/types"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/rbac"
"github.com/cortezaproject/corteza-server/store"
systemTypes "github.com/cortezaproject/corteza-server/system/types"
"go.uber.org/zap"
)
type (
resourceIndex struct {
fields map[uint64]*composeTypes.ModuleField
modules map[uint64]*composeTypes.Module
charts map[uint64]*composeTypes.Chart
pages map[uint64]*composeTypes.Page
exposedModules map[uint64]*federationTypes.ExposedModule
sharedModules map[uint64]*federationTypes.SharedModule
}
)
// MigrateOperations creates system roles
func migratePre202109RbacRules(ctx context.Context, log *zap.Logger, s store.Storer) error {
return store.Tx(ctx, s, func(ctx context.Context, s store.Storer) error {
@@ -22,10 +34,16 @@ func migratePre202109RbacRules(ctx context.Context, log *zap.Logger, s store.Sto
}
log.Info("migrating RBAC rules to new format", zap.Int("rules", len(rr)))
rx, err := preloadResourceIndex(ctx, s)
if err != nil {
return err
}
for _, r := range rr {
var (
cr = *r
action = migratePre202109RbacRule(r)
action = migratePre202109RbacRule(r, rx)
)
if action != 0 {
@@ -50,7 +68,7 @@ func migratePre202109RbacRules(ctx context.Context, log *zap.Logger, s store.Sto
// 0 - no action
// -1 - remove
// 1 - update
func migratePre202109RbacRule(r *rbac.Rule) (op int) {
func migratePre202109RbacRule(r *rbac.Rule, rx *resourceIndex) (op int) {
const (
nsSep = "::"
nsDef = "corteza"
@@ -105,19 +123,69 @@ func migratePre202109RbacRule(r *rbac.Rule) (op int) {
if len(parts) == 3 {
var ID, _ = strconv.ParseUint(parts[2], 10, 64)
p1 := uint64(0)
p2 := uint64(0)
// exceptions with nested references
switch rType {
case composeTypes.ModuleFieldResourceType:
r.Resource = composeTypes.ModuleFieldRbacResource(0, 0, ID)
if ID > 0 {
if f, ok := rx.fields[ID]; ok {
p1 = f.NamespaceID
p2 = f.ModuleID
}
}
r.Resource = composeTypes.ModuleFieldRbacResource(p1, p2, ID)
case composeTypes.ModuleResourceType:
r.Resource = composeTypes.ModuleRbacResource(0, ID)
if ID > 0 {
if r, ok := rx.modules[ID]; ok {
p1 = r.NamespaceID
}
}
r.Resource = composeTypes.ModuleRbacResource(p1, ID)
// ID belongs to module!
case composeTypes.RecordResourceType:
// ID belongs to module!
r.Resource = composeTypes.RecordRbacResource(0, ID, 0)
if ID > 0 {
if r, ok := rx.modules[ID]; ok {
p1 = r.NamespaceID
}
}
r.Resource = composeTypes.RecordRbacResource(p1, ID, 0)
case composeTypes.ChartResourceType:
r.Resource = composeTypes.ChartRbacResource(0, ID)
if ID > 0 {
if r, ok := rx.charts[ID]; ok {
p1 = r.NamespaceID
}
}
r.Resource = composeTypes.ChartRbacResource(p1, ID)
case composeTypes.PageResourceType:
r.Resource = composeTypes.PageRbacResource(0, ID)
if ID > 0 {
if r, ok := rx.pages[ID]; ok {
p1 = r.NamespaceID
}
}
r.Resource = composeTypes.PageRbacResource(p1, ID)
case federationTypes.ExposedModuleResourceType:
if ID > 0 {
if r, ok := rx.exposedModules[ID]; ok {
p1 = r.NodeID
}
}
r.Resource = federationTypes.ExposedModuleRbacResource(p1, ID)
case federationTypes.SharedModuleResourceType:
if ID > 0 {
if r, ok := rx.sharedModules[ID]; ok {
p1 = r.NodeID
}
}
r.Resource = federationTypes.SharedModuleRbacResource(p1, ID)
default:
r.Resource = rType + "/" + func() string {
if ID == 0 {
@@ -133,3 +201,68 @@ func migratePre202109RbacRule(r *rbac.Rule) (op int) {
return
}
// helper to preloadresources that may be used when properly constructing rules
func preloadResourceIndex(ctx context.Context, s store.Storer) (*resourceIndex, error) {
rx := &resourceIndex{}
rx.modules = make(map[uint64]*composeTypes.Module)
modules, _, err := store.SearchComposeModules(ctx, s, composeTypes.ModuleFilter{Paging: filter.Paging{Limit: 0}})
modIDs := make([]uint64, 0, len(modules))
if err != nil {
return nil, err
}
for _, r := range modules {
rx.modules[r.ID] = r
modIDs = append(modIDs, r.ID)
}
if len(modIDs) > 0 {
rx.fields = make(map[uint64]*composeTypes.ModuleField)
fields, _, err := store.SearchComposeModuleFields(ctx, s, composeTypes.ModuleFieldFilter{ModuleID: modIDs})
if err != nil {
return nil, err
}
for _, r := range fields {
rx.fields[r.ID] = r
}
}
rx.charts = make(map[uint64]*composeTypes.Chart)
chart, _, err := store.SearchComposeCharts(ctx, s, composeTypes.ChartFilter{Paging: filter.Paging{Limit: 0}})
if err != nil {
return nil, err
}
for _, r := range chart {
rx.charts[r.ID] = r
}
rx.pages = make(map[uint64]*composeTypes.Page)
page, _, err := store.SearchComposePages(ctx, s, composeTypes.PageFilter{Paging: filter.Paging{Limit: 0}})
if err != nil {
return nil, err
}
for _, r := range page {
rx.pages[r.ID] = r
}
rx.exposedModules = make(map[uint64]*federationTypes.ExposedModule)
exposedModule, _, err := store.SearchFederationExposedModules(ctx, s, federationTypes.ExposedModuleFilter{Paging: filter.Paging{Limit: 0}})
if err != nil {
return nil, err
}
for _, r := range exposedModule {
rx.exposedModules[r.ID] = r
}
rx.sharedModules = make(map[uint64]*federationTypes.SharedModule)
sharedModule, _, err := store.SearchFederationSharedModules(ctx, s, federationTypes.SharedModuleFilter{Paging: filter.Paging{Limit: 0}})
if err != nil {
return nil, err
}
for _, r := range sharedModule {
rx.sharedModules[r.ID] = r
}
return rx, nil
}

View File

@@ -3,11 +3,22 @@ package provision
import (
"testing"
composeTypes "github.com/cortezaproject/corteza-server/compose/types"
federationTypes "github.com/cortezaproject/corteza-server/federation/types"
"github.com/cortezaproject/corteza-server/pkg/rbac"
"github.com/stretchr/testify/require"
)
func Test_migratePre202109RbacRule(t *testing.T) {
rx := &resourceIndex{
fields: make(map[uint64]*composeTypes.ModuleField),
modules: make(map[uint64]*composeTypes.Module),
charts: make(map[uint64]*composeTypes.Chart),
pages: make(map[uint64]*composeTypes.Page),
exposedModules: make(map[uint64]*federationTypes.ExposedModule),
sharedModules: make(map[uint64]*federationTypes.SharedModule),
}
tcc := []struct {
wantOp int
rule *rbac.Rule
@@ -23,7 +34,7 @@ func Test_migratePre202109RbacRule(t *testing.T) {
}
for _, tc := range tcc {
t.Run(tc.rule.String(), func(t *testing.T) {
require.Equal(t, tc.wantOp, migratePre202109RbacRule(tc.rule))
require.Equal(t, tc.wantOp, migratePre202109RbacRule(tc.rule, rx))
if tc.wantRule != nil {
require.Equal(t, tc.wantRule.String(), tc.rule.String())
}