Improve RBAC rule migration logic
* Add missing federation rule edgecases * Properly construct resource paths using parent resources
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user