Improve envoy RBAC rule management
This commit is contained in:
@@ -2,6 +2,7 @@ package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -37,6 +38,14 @@ func NewAPIGateway(res *types.ApigwRoute) *APIGateway {
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *APIGateway) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.ApigwRouteRbacResourceTpl(), types.ApigwRouteResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *APIGateway) AddGatewayFilter(res *types.ApigwFilter) *APIGatewayFilter {
|
||||
f := &APIGatewayFilter{
|
||||
base: &base{},
|
||||
|
||||
@@ -2,6 +2,7 @@ package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -37,6 +38,14 @@ func (r *Application) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Application) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.ApplicationRbacResourceTpl(), types.ApplicationResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Name))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindApplication looks for the app in the resource set
|
||||
func FindApplication(rr InterfaceSet, ii Identifiers) (ap *types.Application) {
|
||||
var apRes *Application
|
||||
|
||||
@@ -73,6 +73,14 @@ func (r *AutomationWorkflow) AddAutomationTrigger(res *types.Trigger) *Automatio
|
||||
return t
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.WorkflowRbacResourceTpl(), types.WorkflowResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
|
||||
@@ -43,8 +43,12 @@ func (r *ComposeChart) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposeChart) RBACPath() []*Ref {
|
||||
return []*Ref{r.RefNs}
|
||||
func (r *ComposeChart) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.ChartRbacResourceTpl(), types.ChartResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// func (r *ComposeChart) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
|
||||
@@ -80,9 +80,12 @@ func (r *ComposeModule) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
// @todo name
|
||||
func (r *ComposeModule) RBACPath() []*Ref {
|
||||
return []*Ref{r.RefNs}
|
||||
func (r *ComposeModule) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.ModuleRbacResourceTpl(), types.ModuleResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeModule) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
@@ -133,46 +136,33 @@ func (r *ComposeModule) AddField(f *ComposeModuleField) {
|
||||
r.ResFields = append(r.ResFields, f)
|
||||
}
|
||||
|
||||
// func FindComposeModuleField(mod *ComposeModule, ii Identifiers) (f *ComposeModuleField) {
|
||||
// for _, f := range mod.ResFields {
|
||||
// if f.Identifiers().HasAny(ii) {
|
||||
// return f
|
||||
// }
|
||||
// }
|
||||
// FindComposeModule looks for the module in the resource set
|
||||
func FindComposeModuleField(rr InterfaceSet, mod, ii Identifiers) (field *types.ModuleField) {
|
||||
var fieldRes *ComposeModuleField
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// FindComposeModuleField looks for the module field in the given module
|
||||
func FindComposeModuleField(mod *types.Module, ii Identifiers) (f *types.ModuleField) {
|
||||
ids := make(map[uint64]bool)
|
||||
handles := make(map[string]bool)
|
||||
for i := range ii {
|
||||
auxID, err := cast.ToUint64E(i)
|
||||
if err == nil {
|
||||
ids[auxID] = true
|
||||
continue
|
||||
rr.Walk(func(r Interface) error {
|
||||
mr, ok := r.(*ComposeModule)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
handles[i] = true
|
||||
}
|
||||
|
||||
var ok bool
|
||||
ff, _ := mod.Fields.Filter(func(mf *types.ModuleField) (bool, error) {
|
||||
if _, ok = ids[mf.ID]; ok {
|
||||
return true, nil
|
||||
}
|
||||
if _, ok = handles[mf.Name]; ok {
|
||||
return true, nil
|
||||
if !mr.Identifiers().HasAny(mod) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
for _, rf := range mr.ResFields {
|
||||
if rf.Identifiers().HasAny(ii) {
|
||||
fieldRes = rf
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if len(ff) == 0 {
|
||||
return nil
|
||||
// Found it
|
||||
if fieldRes != nil {
|
||||
return fieldRes.Res
|
||||
}
|
||||
return ff[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ComposeModuleField) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
@@ -217,6 +207,10 @@ func NewComposeModuleField(res *types.ModuleField, nsRef, modRef string) *Compos
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
|
||||
res.ID = 0
|
||||
res.NamespaceID = 0
|
||||
res.ModuleID = 0
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,14 @@ func NewComposeNamespace(ns *types.Namespace) *ComposeNamespace {
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeNamespace) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.NamespaceRbacResourceTpl(), types.NamespaceResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Slug))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeNamespace) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
|
||||
@@ -150,8 +150,12 @@ func (r *ComposePage) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposePage) RBACPath() []*Ref {
|
||||
return []*Ref{r.RefNs}
|
||||
func (r *ComposePage) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.PageRbacResourceTpl(), types.PageResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposePage) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package resource
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
composeTypes "github.com/cortezaproject/corteza-server/compose/types"
|
||||
systemTypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -71,8 +72,13 @@ func (r *ComposeRecord) SetUserFlakes(uu UserstampIndex) {
|
||||
r.AddRef(systemTypes.UserResourceType, "*")
|
||||
}
|
||||
|
||||
func (r *ComposeRecord) RBACPath() []*Ref {
|
||||
return []*Ref{r.RefNs, r.RefMod}
|
||||
func (r *ComposeRecord) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = []*Ref{r.RefNs, r.RefMod}
|
||||
// @todo specific records
|
||||
resource = fmt.Sprintf(types.RecordRbacResourceTpl(), types.RecordResourceType, r.RefNs.Identifiers.First(), r.RefMod.Identifiers.First(), "*")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func FindComposeRecordResource(rr InterfaceSet, ii Identifiers) (rec *ComposeRecord) {
|
||||
|
||||
@@ -13,21 +13,23 @@ type (
|
||||
*base
|
||||
Res *rbac.Rule
|
||||
|
||||
RefResource string
|
||||
RefRes *Ref
|
||||
RefRole *Ref
|
||||
RefResource *Ref
|
||||
RefPath []*Ref
|
||||
}
|
||||
)
|
||||
|
||||
func NewRbacRule(res *rbac.Rule, refRole string, resRef *Ref, refPath ...*Ref) *RbacRule {
|
||||
func NewRbacRule(res *rbac.Rule, refRole string, refRes *Ref, refResource string, refPath ...*Ref) *RbacRule {
|
||||
r := &RbacRule{base: &base{}}
|
||||
r.SetResourceType(RbacResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.RefRole = r.AddRef(types.RoleResourceType, refRole)
|
||||
|
||||
if resRef != nil {
|
||||
r.RefResource = r.AddRef(resRef.ResourceType, resRef.Identifiers.StringSlice()...)
|
||||
r.RefResource = refResource
|
||||
if refRes != nil {
|
||||
r.RefRes = r.AddRef(refRes.ResourceType, refRes.Identifiers.StringSlice()...)
|
||||
}
|
||||
|
||||
// any additional constraints
|
||||
@@ -35,14 +37,41 @@ func NewRbacRule(res *rbac.Rule, refRole string, resRef *Ref, refPath ...*Ref) *
|
||||
r.RefPath = append(r.RefPath, r.AddRef(rp.ResourceType, rp.Identifiers.StringSlice()...))
|
||||
}
|
||||
|
||||
// ComposeRecords are internally grouped and identified with the module identifier.
|
||||
if res.Resource == composeTypes.RecordResourceType && resRef != nil && len(refPath) == 2 {
|
||||
r.AddRef(res.Resource, refPath[1].Identifiers.StringSlice()...)
|
||||
// Handle cases for nested resources
|
||||
if refRes != nil {
|
||||
switch refRes.ResourceType {
|
||||
case composeTypes.RecordResourceType:
|
||||
r.handleComposeRecord(res, refPath)
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
r.handleComposeModuleField(res, refPath)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *RbacRule) handleComposeRecord(res *rbac.Rule, refPath []*Ref) {
|
||||
|
||||
// records are grouped under module
|
||||
|
||||
if len(refPath) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
r.AddRef(composeTypes.RecordResourceType, refPath[1].Identifiers.StringSlice()...)
|
||||
}
|
||||
|
||||
func (r *RbacRule) handleComposeModuleField(res *rbac.Rule, refPath []*Ref) {
|
||||
|
||||
// module fields are grouped under module
|
||||
|
||||
if len(refPath) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
r.AddRef(composeTypes.ModuleFieldResourceTranslationType, refPath[1].Identifiers.StringSlice()...)
|
||||
}
|
||||
|
||||
func RbacResourceErrNotFound(ii Identifiers) error {
|
||||
return fmt.Errorf("rbac resource not found %v", ii.StringSlice())
|
||||
}
|
||||
|
||||
@@ -54,6 +54,14 @@ func (r *Report) AddReportSource(res *types.ReportDataSource) *ReportSource {
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Report) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.ReportRbacResourceTpl(), types.ReportResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Report) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
|
||||
@@ -12,7 +12,6 @@ type (
|
||||
*base
|
||||
Res types.ResourceTranslationSet
|
||||
|
||||
// RelResource string
|
||||
RefResource string
|
||||
RefRes *Ref
|
||||
RefPath []*Ref
|
||||
|
||||
@@ -2,6 +2,7 @@ package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -31,6 +32,14 @@ func (r *Role) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Role) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.RoleRbacResourceTpl(), types.RoleResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindRole looks for the role in the resources
|
||||
func FindRole(rr InterfaceSet, ii Identifiers) (rl *types.Role) {
|
||||
var rlRes *Role
|
||||
|
||||
@@ -2,6 +2,7 @@ package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -31,6 +32,14 @@ func (r *Template) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Template) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.TemplateRbacResourceTpl(), types.TemplateResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindTemplate looks for the template in the resources
|
||||
func FindTemplate(rr InterfaceSet, ii Identifiers) (u *types.Template) {
|
||||
var tRes *Template
|
||||
|
||||
@@ -29,7 +29,7 @@ type (
|
||||
RBACInterface interface {
|
||||
Interface
|
||||
|
||||
RBACPath() []*Ref
|
||||
RBACParts() (string, *Ref, []*Ref)
|
||||
}
|
||||
|
||||
LocaleInterface interface {
|
||||
|
||||
@@ -2,6 +2,7 @@ package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -31,6 +32,14 @@ func (r *User) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *User) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.UserRbacResourceTpl(), types.UserResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle, r.Res.Username))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindUser looks for the user in the resources
|
||||
func FindUser(rr InterfaceSet, ii Identifiers) (u *types.User) {
|
||||
var uRes *User
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
func firstOkString(ss ...string) string {
|
||||
for _, s := range ss {
|
||||
if s != "" {
|
||||
if s != "" && s != "0" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ func (n *composeModule) Encode(ctx context.Context, pl *payload) (err error) {
|
||||
f.DeletedAt = nil
|
||||
f.CreatedAt = *now()
|
||||
|
||||
if f.Kind == "Record" {
|
||||
if f.Options != nil && f.Kind == "Record" {
|
||||
refMod := f.Options.String("module")
|
||||
if refMod == "" {
|
||||
refMod = f.Options.String("moduleID")
|
||||
@@ -186,7 +186,7 @@ func (n *composeModule) Encode(ctx context.Context, pl *payload) (err error) {
|
||||
delete(f.Options, "module")
|
||||
}
|
||||
|
||||
if f.Kind == "User" {
|
||||
if f.Options != nil && f.Kind == "User" {
|
||||
roles := resource.ComposeModuleFieldExtractUserFieldRoles(f.Options["roles"])
|
||||
if len(roles) == 0 {
|
||||
roles = resource.ComposeModuleFieldExtractUserFieldRoles(f.Options["role"])
|
||||
|
||||
@@ -12,13 +12,16 @@ type (
|
||||
rbacRule struct {
|
||||
cfg *EncoderConfig
|
||||
|
||||
res *resource.RbacRule
|
||||
rule *rbac.Rule
|
||||
|
||||
refRes *resource.Ref
|
||||
// point to the rbac rule
|
||||
refRbacResource string
|
||||
refRbacRes *resource.Ref
|
||||
|
||||
refPathRes []*resource.Ref
|
||||
|
||||
relRole *types.Role
|
||||
refRole *resource.Ref
|
||||
role *types.Role
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package store
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
automationTypes "github.com/cortezaproject/corteza-server/automation/types"
|
||||
composeTypes "github.com/cortezaproject/corteza-server/compose/types"
|
||||
@@ -16,54 +17,62 @@ import (
|
||||
|
||||
var (
|
||||
gRbacRules map[string]bool
|
||||
|
||||
rbacRuleIndex = func(r *rbac.Rule) string {
|
||||
return fmt.Sprintf("%d_%s_%s", r.RoleID, r.Resource, r.Operation)
|
||||
}
|
||||
)
|
||||
|
||||
func newRbacRuleFromResource(res *resource.RbacRule, cfg *EncoderConfig) resourceState {
|
||||
return &rbacRule{
|
||||
cfg: mergeConfig(cfg, res.Config()),
|
||||
|
||||
res: res,
|
||||
rule: res.Res,
|
||||
|
||||
refRbacResource: res.RefResource,
|
||||
refRbacRes: res.RefRes,
|
||||
|
||||
refPathRes: res.RefPath,
|
||||
|
||||
refRole: res.RefRole,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *rbacRule) Prepare(ctx context.Context, pl *payload) (err error) {
|
||||
// Init global state
|
||||
if gRbacRules == nil {
|
||||
gRbacRules = make(map[string]bool)
|
||||
rr, _, err := store.SearchRbacRules(ctx, pl.s, rbac.RuleFilter{})
|
||||
if err != store.ErrNotFound && err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range rr {
|
||||
gRbacRules[rbacRuleIndex(r)] = true
|
||||
err = n.initGlobalIndex(ctx, pl.s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Related role
|
||||
n.relRole, err = findRole(ctx, pl.s, pl.state.ParentResources, n.res.RefRole.Identifiers)
|
||||
n.role, err = findRole(ctx, pl.s, pl.state.ParentResources, n.refRole.Identifiers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n.relRole == nil {
|
||||
return resource.RoleErrUnresolved(n.res.RefRole.Identifiers)
|
||||
if n.role == nil {
|
||||
return resource.RoleErrUnresolved(n.refRole.Identifiers)
|
||||
}
|
||||
|
||||
refRes := n.refRbacRes
|
||||
if refRes == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// For now we will only allow resource specific RBAC rules if that resource is
|
||||
// also present.
|
||||
// Here we check if we can find it in case we're handling a resource specific rule.
|
||||
refRes := n.res.RefResource
|
||||
if refRes != nil && refRes.ResourceType == composeTypes.RecordResourceType {
|
||||
for _, r := range pl.state.ParentResources {
|
||||
if r.ResourceType() == composeTypes.RecordResourceType && r.Identifiers().HasAny(n.res.RefPath[1].Identifiers) {
|
||||
return
|
||||
}
|
||||
found := false
|
||||
switch refRes.ResourceType {
|
||||
case composeTypes.RecordResourceType:
|
||||
if found = n.handleComposeRecord(pl.state.ParentResources); !found {
|
||||
return resource.RbacResourceErrNotFound(refRes.Identifiers)
|
||||
}
|
||||
} else if refRes != nil && len(refRes.Identifiers) > 0 {
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
if found = n.handleComposeModuleField(pl.state.ParentResources); !found {
|
||||
return resource.RbacResourceErrNotFound(refRes.Identifiers)
|
||||
}
|
||||
|
||||
default:
|
||||
for _, r := range pl.state.ParentResources {
|
||||
if refRes.ResourceType == r.ResourceType() && r.Identifiers().HasAny(refRes.Identifiers) {
|
||||
return
|
||||
@@ -77,236 +86,25 @@ func (n *rbacRule) Prepare(ctx context.Context, pl *payload) (err error) {
|
||||
}
|
||||
|
||||
func (n *rbacRule) Encode(ctx context.Context, pl *payload) (err error) {
|
||||
res := n.res.Res
|
||||
|
||||
// Related role
|
||||
res.RoleID = n.relRole.ID
|
||||
if res.RoleID == 0 {
|
||||
rl := resource.FindRole(pl.state.ParentResources, n.res.RefRole.Identifiers)
|
||||
res.RoleID = rl.ID
|
||||
}
|
||||
if res.RoleID == 0 {
|
||||
return resource.RoleErrUnresolved(n.res.RefRole.Identifiers)
|
||||
// Assure correct resource
|
||||
n.rule.Resource, err = n.makeRBACResource(pl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p0ID := uint64(0)
|
||||
p1ID := uint64(0)
|
||||
p2ID := uint64(0)
|
||||
|
||||
switch n.rule.Resource {
|
||||
case composeTypes.ComponentResourceType:
|
||||
res.Resource = composeTypes.ComponentRbacResource()
|
||||
goto store
|
||||
case systemTypes.ComponentResourceType:
|
||||
res.Resource = systemTypes.ComponentRbacResource()
|
||||
goto store
|
||||
case automationTypes.ComponentResourceType:
|
||||
res.Resource = automationTypes.ComponentRbacResource()
|
||||
goto store
|
||||
case federationTypes.ComponentResourceType:
|
||||
res.Resource = federationTypes.ComponentRbacResource()
|
||||
goto store
|
||||
// Assure correct role
|
||||
n.rule.RoleID = n.role.ID
|
||||
if n.rule.RoleID == 0 {
|
||||
rl := resource.FindRole(pl.state.ParentResources, n.refRole.Identifiers)
|
||||
n.rule.RoleID = rl.ID
|
||||
}
|
||||
if n.rule.RoleID == 0 {
|
||||
return resource.RoleErrUnresolved(n.refRole.Identifiers)
|
||||
}
|
||||
|
||||
switch n.rule.Resource {
|
||||
case automationTypes.WorkflowResourceType:
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindAutomationWorkflow(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.AutomationWorkflowErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = automationTypes.WorkflowRbacResource(p1ID)
|
||||
|
||||
case composeTypes.NamespaceResourceType:
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindComposeNamespace(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = composeTypes.NamespaceRbacResource(p1ID)
|
||||
case composeTypes.ModuleResourceType:
|
||||
if len(n.res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(n.res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindComposeModule(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeModuleErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = composeTypes.ModuleRbacResource(p0ID, p1ID)
|
||||
case composeTypes.ChartResourceType:
|
||||
if len(n.res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(n.res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindComposeChart(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeChartErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = composeTypes.ChartRbacResource(p0ID, p1ID)
|
||||
case composeTypes.PageResourceType:
|
||||
if len(n.res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(n.res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindComposePage(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposePageErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = composeTypes.PageRbacResource(p0ID, p1ID)
|
||||
case composeTypes.RecordResourceType:
|
||||
if len(n.res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(n.res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
if len(n.res.RefPath) > 1 {
|
||||
p1 := resource.FindComposeModule(pl.state.ParentResources, n.res.RefPath[1].Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeModuleErrUnresolved(n.res.RefPath[1].Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
if n.res.RefResource != nil {
|
||||
ref := n.res.RefPath[1]
|
||||
|
||||
p2 := resource.FindComposeRecordResource(pl.state.ParentResources, ref.Identifiers)
|
||||
if p2 == nil {
|
||||
return resource.ComposeRecordErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
|
||||
for i := range n.res.RefResource.Identifiers {
|
||||
if p2ID = p2.IDMap[i]; p2ID > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if p2ID == 0 {
|
||||
return resource.ComposeRecordErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
}
|
||||
|
||||
res.Resource = composeTypes.RecordRbacResource(p0ID, p1ID, p2ID)
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
if len(n.res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(n.res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
if len(n.res.RefPath) > 1 {
|
||||
p1 := resource.FindComposeModule(pl.state.ParentResources, n.res.RefPath[1].Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeModuleErrUnresolved(n.res.RefPath[1].Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
// @todo specific ModuleField RBAC
|
||||
|
||||
res.Resource = composeTypes.ModuleFieldRbacResource(p0ID, p1ID, p2ID)
|
||||
|
||||
case systemTypes.UserResourceType:
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindUser(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.UserErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = systemTypes.UserRbacResource(p1ID)
|
||||
case systemTypes.RoleResourceType:
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindRole(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.RoleErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = systemTypes.RoleRbacResource(p1ID)
|
||||
case systemTypes.ApplicationResourceType:
|
||||
if n.res.RefResource != nil {
|
||||
p1 := resource.FindApplication(pl.state.ParentResources, n.res.RefResource.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ApplicationErrUnresolved(n.res.RefResource.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
res.Resource = systemTypes.ApplicationRbacResource(p1ID)
|
||||
case systemTypes.ApigwRouteResourceType:
|
||||
res.Resource = systemTypes.ApigwRouteRbacResource(p1ID)
|
||||
case systemTypes.ApigwFilterResourceType:
|
||||
res.Resource = systemTypes.ApigwFilterRbacResource(p1ID)
|
||||
case systemTypes.AuthClientResourceType:
|
||||
// @todo add support for importing rbac rules for specific client
|
||||
res.Resource = systemTypes.AuthClientRbacResource(p1ID)
|
||||
case systemTypes.TemplateResourceType:
|
||||
// @todo add support for importing rbac rules for specific template
|
||||
res.Resource = systemTypes.TemplateRbacResource(p1ID)
|
||||
case systemTypes.ReportResourceType:
|
||||
res.Resource = systemTypes.ReportRbacResource(p1ID)
|
||||
case messagebus.QueueResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
res.Resource = messagebus.QueueRbacResource(p1ID)
|
||||
|
||||
case federationTypes.NodeResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
res.Resource = federationTypes.NodeRbacResource(p1ID)
|
||||
|
||||
case federationTypes.SharedModuleResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
res.Resource = federationTypes.SharedModuleRbacResource(p0ID, p1ID)
|
||||
|
||||
case federationTypes.ExposedModuleResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
res.Resource = federationTypes.ExposedModuleRbacResource(p0ID, p1ID)
|
||||
|
||||
default:
|
||||
// @todo if we wish to support rbac for external stuff, this needs to pass through.
|
||||
// this also requires some tweaks in the path ID thing.
|
||||
return fmt.Errorf("unsupported resource type '%s' for RBAC store encode", n.rule.Resource)
|
||||
}
|
||||
|
||||
store:
|
||||
|
||||
if _, exists := gRbacRules[rbacRuleIndex(res)]; !exists {
|
||||
return store.CreateRbacRule(ctx, pl.s, res)
|
||||
// Upsert
|
||||
if _, exists := gRbacRules[n.rbacRuleIndex((n.rule))]; !exists {
|
||||
return store.CreateRbacRule(ctx, pl.s, n.rule)
|
||||
}
|
||||
|
||||
// On existing rbac rule, replace/merge right basically overwrites the existing rule;
|
||||
@@ -314,8 +112,267 @@ store:
|
||||
switch n.cfg.OnExisting {
|
||||
case resource.Replace,
|
||||
resource.MergeRight:
|
||||
return store.UpdateRbacRule(ctx, pl.s, res)
|
||||
return store.UpdateRbacRule(ctx, pl.s, n.rule)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *rbacRule) rbacRuleIndex(r *rbac.Rule) string {
|
||||
return fmt.Sprintf("%d_%s_%s", r.RoleID, r.Resource, r.Operation)
|
||||
}
|
||||
|
||||
func (n *rbacRule) initGlobalIndex(ctx context.Context, s store.Storer) error {
|
||||
gRbacRules = make(map[string]bool)
|
||||
|
||||
rr, _, err := store.SearchRbacRules(ctx, s, rbac.RuleFilter{})
|
||||
if err != store.ErrNotFound && err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
gRbacRules[n.rbacRuleIndex(r)] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *rbacRule) makeRBACResource(pl *payload) (string, error) {
|
||||
p0ID := uint64(0)
|
||||
p1ID := uint64(0)
|
||||
p2ID := uint64(0)
|
||||
|
||||
rt := strings.Split(n.refRbacResource, "/")[0]
|
||||
|
||||
// Component level stuff
|
||||
switch rt {
|
||||
case composeTypes.ComponentResourceType:
|
||||
return composeTypes.ComponentRbacResource(), nil
|
||||
case systemTypes.ComponentResourceType:
|
||||
return systemTypes.ComponentRbacResource(), nil
|
||||
case automationTypes.ComponentResourceType:
|
||||
return automationTypes.ComponentRbacResource(), nil
|
||||
case federationTypes.ComponentResourceType:
|
||||
return federationTypes.ComponentRbacResource(), nil
|
||||
}
|
||||
|
||||
// Component resource stuff
|
||||
switch rt {
|
||||
case automationTypes.WorkflowResourceType:
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindAutomationWorkflow(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.AutomationWorkflowErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return automationTypes.WorkflowRbacResource(p1ID), nil
|
||||
|
||||
case composeTypes.NamespaceResourceType:
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindComposeNamespace(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return composeTypes.NamespaceRbacResource(p1ID), nil
|
||||
|
||||
case composeTypes.ModuleResourceType:
|
||||
if len(n.refPathRes) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindComposeModule(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeModuleErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return composeTypes.ModuleRbacResource(p0ID, p1ID), nil
|
||||
|
||||
case composeTypes.ChartResourceType:
|
||||
if len(n.refPathRes) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindComposeChart(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeChartErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return composeTypes.ChartRbacResource(p0ID, p1ID), nil
|
||||
|
||||
case composeTypes.PageResourceType:
|
||||
if len(n.refPathRes) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindComposePage(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposePageErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return composeTypes.PageRbacResource(p0ID, p1ID), nil
|
||||
|
||||
case composeTypes.RecordResourceType:
|
||||
if len(n.refPathRes) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
if len(n.refPathRes) > 1 {
|
||||
p1 := resource.FindComposeModule(pl.state.ParentResources, n.refPathRes[1].Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeModuleErrUnresolved(n.refPathRes[1].Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
if n.refRbacRes != nil {
|
||||
ref := n.refPathRes[1]
|
||||
|
||||
p2 := resource.FindComposeRecordResource(pl.state.ParentResources, ref.Identifiers)
|
||||
if p2 == nil {
|
||||
return "", resource.ComposeRecordErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
|
||||
for i := range n.refRbacRes.Identifiers {
|
||||
if p2ID = p2.IDMap[i]; p2ID > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if p2ID == 0 {
|
||||
return "", resource.ComposeRecordErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
}
|
||||
return composeTypes.RecordRbacResource(p0ID, p1ID, p2ID), nil
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
if len(n.refPathRes) > 0 {
|
||||
p0 := resource.FindComposeNamespace(pl.state.ParentResources, n.refPathRes[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return "", resource.ComposeNamespaceErrUnresolved(n.refPathRes[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.ID
|
||||
}
|
||||
if len(n.refPathRes) > 1 {
|
||||
p1 := resource.FindComposeModule(pl.state.ParentResources, n.refPathRes[1].Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ComposeModuleErrUnresolved(n.refPathRes[1].Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
|
||||
if n.refRbacRes != nil {
|
||||
modRef := n.refPathRes[1]
|
||||
p2 := resource.FindComposeModuleField(pl.state.ParentResources, modRef.Identifiers, n.refRbacRes.Identifiers)
|
||||
if p2 == nil {
|
||||
return "", resource.ComposeModuleFieldErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
|
||||
p2ID = p2.ID
|
||||
}
|
||||
|
||||
return composeTypes.ModuleFieldRbacResource(p0ID, p1ID, p2ID), nil
|
||||
|
||||
case systemTypes.UserResourceType:
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindUser(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.UserErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return systemTypes.UserRbacResource(p1ID), nil
|
||||
|
||||
case systemTypes.RoleResourceType:
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindRole(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.RoleErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return systemTypes.RoleRbacResource(p1ID), nil
|
||||
|
||||
case systemTypes.ApplicationResourceType:
|
||||
if n.refRbacRes != nil {
|
||||
p1 := resource.FindApplication(pl.state.ParentResources, n.refRbacRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return "", resource.ApplicationErrUnresolved(n.refRbacRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.ID
|
||||
}
|
||||
return systemTypes.ApplicationRbacResource(p1ID), nil
|
||||
|
||||
case systemTypes.ApigwRouteResourceType:
|
||||
return systemTypes.ApigwRouteRbacResource(p1ID), nil
|
||||
case systemTypes.ApigwFilterResourceType:
|
||||
return systemTypes.ApigwFilterRbacResource(p1ID), nil
|
||||
case systemTypes.AuthClientResourceType:
|
||||
// @todo add support for importing rbac rules for specific client
|
||||
return systemTypes.AuthClientRbacResource(p1ID), nil
|
||||
case systemTypes.TemplateResourceType:
|
||||
// @todo add support for importing rbac rules for specific template
|
||||
return systemTypes.TemplateRbacResource(p1ID), nil
|
||||
case systemTypes.ReportResourceType:
|
||||
return systemTypes.ReportRbacResource(p1ID), nil
|
||||
case messagebus.QueueResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
return messagebus.QueueRbacResource(p1ID), nil
|
||||
|
||||
case federationTypes.NodeResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
return federationTypes.NodeRbacResource(p1ID), nil
|
||||
|
||||
case federationTypes.SharedModuleResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
return federationTypes.SharedModuleRbacResource(p0ID, p1ID), nil
|
||||
|
||||
case federationTypes.ExposedModuleResourceType:
|
||||
// @todo add support for importing rbac rules for specific queue
|
||||
return federationTypes.ExposedModuleRbacResource(p0ID, p1ID), nil
|
||||
}
|
||||
|
||||
// @todo if we wish to support rbac for external stuff, this needs to pass through.
|
||||
// this also requires some tweaks in the path ID thing.
|
||||
return "", fmt.Errorf("unsupported resource type '%s' for RBAC store encode", n.rule.Resource)
|
||||
}
|
||||
|
||||
func (n *rbacRule) handleComposeRecord(pp []resource.Interface) bool {
|
||||
for _, p := range pp {
|
||||
if p.ResourceType() == composeTypes.RecordResourceType && p.Identifiers().HasAny(n.refPathRes[1].Identifiers) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *rbacRule) handleComposeModuleField(pp []resource.Interface) bool {
|
||||
for _, p := range pp {
|
||||
if p.ResourceType() == composeTypes.ModuleResourceType && p.Identifiers().HasAny(n.refPathRes[1].Identifiers) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -7,21 +7,28 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy"
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
|
||||
"github.com/cortezaproject/corteza-server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func newRbacRule(rl *rbac.Rule) *rbacRule {
|
||||
func newRbacRule(rl *rbac.Rule) (*rbacRule, error) {
|
||||
res := rl.Resource
|
||||
_, ref, pp, err := resource.ParseRule(res)
|
||||
|
||||
return &rbacRule{
|
||||
rule: rl,
|
||||
}
|
||||
|
||||
refRbacResource: res,
|
||||
refRbacRes: ref,
|
||||
|
||||
refPathRes: pp,
|
||||
|
||||
refRole: resource.MakeRef(types.RoleResourceType, resource.MakeIdentifiers(strconv.FormatUint(rl.RoleID, 10))),
|
||||
}, err
|
||||
}
|
||||
|
||||
func (rl *rbacRule) MarshalEnvoy() ([]resource.Interface, error) {
|
||||
refRole := strconv.FormatUint(rl.rule.RoleID, 10)
|
||||
|
||||
rl.rule.Resource = rbac.ResourceType(rl.rule.Resource)
|
||||
|
||||
return envoy.CollectNodes(
|
||||
resource.NewRbacRule(rl.rule, refRole, rl.refRes, rl.refPathRes...),
|
||||
resource.NewRbacRule(rl.rule, rl.refRole.Identifiers.First(), rl.refRbacRes, rl.refRbacResource, rl.refPathRes...),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ func (n *resourceTranslation) makeResourceTranslation(pl *payload) (string, erro
|
||||
p1ID = p1.ID
|
||||
|
||||
// field
|
||||
f := resource.FindComposeModuleField(p1, n.refLocaleRes.Identifiers)
|
||||
f := resource.FindComposeModuleField(pl.state.ParentResources, n.refPathRes[1].Identifiers, n.refLocaleRes.Identifiers)
|
||||
if f == nil {
|
||||
return "", resource.ComposeModuleFieldErrUnresolved(n.refLocaleRes.Identifiers)
|
||||
}
|
||||
|
||||
+13
-10
@@ -379,7 +379,7 @@ func (d *systemDecoder) decodeRbac(ctx context.Context, s store.Storer, ff []*rb
|
||||
var nn rbac.RuleSet
|
||||
var err error
|
||||
|
||||
c := func(r *resource.Ref, f *rbacFilter) (bool, error) {
|
||||
c := func(r *resource.Ref, f *rbacFilter, path ...*resource.Ref) (bool, error) {
|
||||
if r == nil {
|
||||
return true, nil
|
||||
}
|
||||
@@ -390,6 +390,13 @@ func (d *systemDecoder) decodeRbac(ctx context.Context, s store.Storer, ff []*rb
|
||||
return false, err
|
||||
}
|
||||
|
||||
if r.ResourceType == composeTypes.ModuleFieldResourceType {
|
||||
id, err = cast.ToUint64E(path[1].Identifiers.First())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return f.resourceID[id], nil
|
||||
}
|
||||
|
||||
@@ -405,12 +412,8 @@ func (d *systemDecoder) decodeRbac(ctx context.Context, s store.Storer, ff []*rb
|
||||
}
|
||||
|
||||
for _, n := range nn {
|
||||
r := newRbacRule(n)
|
||||
|
||||
// parse the resource wo we can define relations/check if we can unmarshal it
|
||||
rt, ref, pp, err := resource.ParseRule(n.Resource)
|
||||
r.refRes = ref
|
||||
r.refPathRes = pp
|
||||
r, err := newRbacRule(n)
|
||||
rt := strings.Split(r.refRbacResource, "/")[0]
|
||||
if err != nil {
|
||||
return &auxRsp{
|
||||
err: err,
|
||||
@@ -419,13 +422,13 @@ func (d *systemDecoder) decodeRbac(ctx context.Context, s store.Storer, ff []*rb
|
||||
|
||||
// somesort of a generic rule; no specifc resource
|
||||
// @todo check for pp inclusion!!
|
||||
if ref == nil && len(pp) == 0 {
|
||||
if r.refRbacRes == nil && len(r.refPathRes) == 0 {
|
||||
mm = append(mm, r)
|
||||
} else {
|
||||
// Check the resource ref and the path refs for validity.
|
||||
// ComposeRecords are fetched in chunks so this check is not valid here.
|
||||
if rt != composeTypes.RecordResourceType {
|
||||
if ok, err := c(ref, f); err != nil {
|
||||
if ok, err := c(r.refRbacRes, f, r.refPathRes...); err != nil {
|
||||
return &auxRsp{
|
||||
err: err,
|
||||
}
|
||||
@@ -434,7 +437,7 @@ func (d *systemDecoder) decodeRbac(ctx context.Context, s store.Storer, ff []*rb
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range pp {
|
||||
for _, p := range r.refPathRes {
|
||||
if ok, err := c(p, f); err != nil {
|
||||
return &auxRsp{
|
||||
err: err,
|
||||
|
||||
@@ -155,6 +155,9 @@ func (c *composeModule) MarshalYAML() (interface{}, error) {
|
||||
func (c *composeModuleField) MarshalYAML() (interface{}, error) {
|
||||
|
||||
auxOpt := c.res.Options
|
||||
if auxOpt == nil {
|
||||
auxOpt = make(types.ModuleFieldOptions)
|
||||
}
|
||||
switch c.res.Kind {
|
||||
case "Record":
|
||||
ref := c.relMod.Handle
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
|
||||
@@ -12,18 +13,16 @@ type (
|
||||
rbacRule struct {
|
||||
res *rbac.Rule
|
||||
|
||||
// To help us construct the resource
|
||||
resource string
|
||||
// The resource in question
|
||||
refRbacResource string
|
||||
refRbacRes *resource.Ref
|
||||
|
||||
refResource string
|
||||
refRes *resource.Ref
|
||||
// The path items
|
||||
refPathRes []*resource.Ref
|
||||
|
||||
// PathRes and PathResource slices hold parent resources we should nest the rule by
|
||||
refPathRes []*resource.Ref
|
||||
relPathResource []resource.Interface
|
||||
|
||||
refRole string
|
||||
relRole *types.Role
|
||||
// The role
|
||||
refRole *resource.Ref
|
||||
role *types.Role
|
||||
}
|
||||
rbacRuleSet []*rbacRule
|
||||
)
|
||||
@@ -32,15 +31,19 @@ func rbacRuleFromResource(r *resource.RbacRule, cfg *EncoderConfig) *rbacRule {
|
||||
rr := r.Res.Resource
|
||||
rr = strings.Trim(rr, ":")
|
||||
|
||||
if !strings.Contains(rr, ";") {
|
||||
if !strings.Contains(rr, ":") {
|
||||
rr = "corteza::" + rr
|
||||
}
|
||||
|
||||
return &rbacRule{
|
||||
res: r.Res,
|
||||
refRes: r.RefResource,
|
||||
refResource: rr,
|
||||
refRole: r.RefRole.Identifiers.First(),
|
||||
res: r.Res,
|
||||
|
||||
refRbacResource: rr,
|
||||
refRbacRes: r.RefRes,
|
||||
|
||||
refPathRes: r.RefPath,
|
||||
|
||||
refRole: r.RefRole,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,11 +65,13 @@ func (rr rbacRuleSet) groupByRole() []rbacRuleSet {
|
||||
rolx := make(map[string]rbacRuleSet)
|
||||
|
||||
for _, r := range rr {
|
||||
if _, has := rolx[r.refRole]; !has {
|
||||
rolx[r.refRole] = make(rbacRuleSet, 0, 100)
|
||||
roleKey := r.getRoleKey()
|
||||
|
||||
if _, has := rolx[roleKey]; !has {
|
||||
rolx[roleKey] = make(rbacRuleSet, 0, 100)
|
||||
}
|
||||
|
||||
rolx[r.refRole] = append(rolx[r.refRole], r)
|
||||
rolx[roleKey] = append(rolx[roleKey], r)
|
||||
}
|
||||
|
||||
rtr := make([]rbacRuleSet, 0, len(rolx))
|
||||
@@ -97,13 +102,12 @@ func (rr rbacRuleSet) groupByResource() []rbacRuleSet {
|
||||
return rtr
|
||||
}
|
||||
|
||||
// Just a helper to make the above code shorter
|
||||
func (r *rbacRule) bindRefs(res *resource.Ref, path []*resource.Ref, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
func (r *rbacRule) getRoleKey() string {
|
||||
if r.role == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
r.refRes = res
|
||||
r.refPathRes = path
|
||||
return nil
|
||||
if r.role.Handle != "" {
|
||||
return r.role.Handle
|
||||
}
|
||||
return strconv.FormatUint(r.res.RoleID, 10)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package yaml
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
automationTypes "github.com/cortezaproject/corteza-server/automation/types"
|
||||
composeTypes "github.com/cortezaproject/corteza-server/compose/types"
|
||||
@@ -19,26 +20,32 @@ func (n *rbacRule) Prepare(ctx context.Context, state *envoy.ResourceState) (err
|
||||
}
|
||||
|
||||
// Get the related role
|
||||
n.relRole = resource.FindRole(state.ParentResources, rl.RefRole.Identifiers)
|
||||
if n.relRole == nil {
|
||||
n.role = resource.FindRole(state.ParentResources, rl.RefRole.Identifiers)
|
||||
if n.role == nil {
|
||||
return resource.RoleErrUnresolved(rl.RefRole.Identifiers)
|
||||
}
|
||||
if n.relRole == nil {
|
||||
return resource.RoleErrUnresolved(rl.RefRole.Identifiers)
|
||||
|
||||
refRes := n.refRbacRes
|
||||
if refRes == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// For now we will only allow resource specific RBAC rules if that resource is
|
||||
// also present.
|
||||
// Here we check if we can find it in case we're handling a resource specific rule.
|
||||
res := state.Res.(*resource.RbacRule)
|
||||
refRes := res.RefResource
|
||||
if refRes != nil && refRes.ResourceType == composeTypes.RecordResourceType {
|
||||
for _, r := range state.ParentResources {
|
||||
if r.ResourceType() == composeTypes.RecordResourceType && r.Identifiers().HasAny(res.RefPath[1].Identifiers) {
|
||||
return
|
||||
}
|
||||
found := false
|
||||
switch refRes.ResourceType {
|
||||
case composeTypes.RecordResourceType:
|
||||
if found = n.handleComposeRecord(state.ParentResources); !found {
|
||||
return resource.RbacResourceErrNotFound(refRes.Identifiers)
|
||||
}
|
||||
} else if refRes != nil && len(refRes.Identifiers) > 0 {
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
if found = n.handleComposeModuleField(state.ParentResources); !found {
|
||||
return resource.RbacResourceErrNotFound(refRes.Identifiers)
|
||||
}
|
||||
|
||||
default:
|
||||
for _, r := range state.ParentResources {
|
||||
if refRes.ResourceType == r.ResourceType() && r.Identifiers().HasAny(refRes.Identifiers) {
|
||||
return
|
||||
@@ -58,186 +65,225 @@ func (r *rbacRule) Encode(ctx context.Context, doc *Document, state *envoy.Resou
|
||||
// under the related namespace.
|
||||
// For now all rules will be nested under a root node for simplicity sake.
|
||||
|
||||
refResource, err := r.makeRBACResource(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.refRbacResource = refResource
|
||||
r.res.Resource = refResource
|
||||
|
||||
doc.addRbacRule(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rbacRule) makeRBACResource(state *envoy.ResourceState) (string, error) {
|
||||
res := state.Res.(*resource.RbacRule)
|
||||
|
||||
p0ID := "*"
|
||||
p1ID := "*"
|
||||
p2ID := "*"
|
||||
|
||||
switch r.res.Resource {
|
||||
rt := strings.Split(r.refRbacResource, "/")[0]
|
||||
|
||||
switch rt {
|
||||
case composeTypes.ComponentResourceType,
|
||||
systemTypes.ComponentResourceType,
|
||||
automationTypes.ComponentResourceType,
|
||||
federationTypes.ComponentResourceType:
|
||||
r.res.Resource += "/"
|
||||
goto next
|
||||
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
// @todo the following stuff I'm not too sure about
|
||||
switch r.res.Resource {
|
||||
switch rt {
|
||||
case composeTypes.NamespaceResourceType:
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindComposeNamespace(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindComposeNamespace(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Slug
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(composeTypes.NamespaceRbacResourceTpl(), composeTypes.NamespaceResourceType, p1ID)
|
||||
return fmt.Sprintf(composeTypes.NamespaceRbacResourceTpl(), composeTypes.NamespaceResourceType, p1ID), nil
|
||||
case composeTypes.ModuleResourceType:
|
||||
if len(res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.Slug
|
||||
}
|
||||
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindComposeModule(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindComposeModule(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeModuleErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ComposeModuleErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(composeTypes.ModuleRbacResourceTpl(), composeTypes.ModuleResourceType, p0ID, p1ID)
|
||||
return fmt.Sprintf(composeTypes.ModuleRbacResourceTpl(), composeTypes.ModuleResourceType, p0ID, p1ID), nil
|
||||
case composeTypes.ChartResourceType:
|
||||
if len(res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.Slug
|
||||
}
|
||||
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindComposeChart(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindComposeChart(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeChartErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ComposeChartErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(composeTypes.ChartRbacResourceTpl(), composeTypes.ChartResourceType, p0ID, p1ID)
|
||||
return fmt.Sprintf(composeTypes.ChartRbacResourceTpl(), composeTypes.ChartResourceType, p0ID, p1ID), nil
|
||||
case composeTypes.PageResourceType:
|
||||
if len(res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.Slug
|
||||
}
|
||||
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindComposePage(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindComposePage(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposePageErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ComposePageErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(composeTypes.PageRbacResourceTpl(), composeTypes.PageResourceType, p0ID, p1ID)
|
||||
return fmt.Sprintf(composeTypes.PageRbacResourceTpl(), composeTypes.PageResourceType, p0ID, p1ID), nil
|
||||
case composeTypes.RecordResourceType:
|
||||
if len(res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.Slug
|
||||
}
|
||||
if len(res.RefPath) > 1 {
|
||||
p1 := resource.FindComposeModule(state.ParentResources, res.RefPath[1].Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeModuleErrUnresolved(res.RefPath[1].Identifiers)
|
||||
return "", resource.ComposeModuleErrUnresolved(res.RefPath[1].Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
if res.RefResource != nil {
|
||||
if res.RefRes != nil {
|
||||
ref := res.RefPath[1]
|
||||
|
||||
p2 := resource.FindComposeRecordResource(state.ParentResources, ref.Identifiers)
|
||||
if p2 == nil {
|
||||
return resource.ComposeRecordErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ComposeRecordErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
|
||||
for i := range res.RefResource.Identifiers {
|
||||
for i := range res.RefRes.Identifiers {
|
||||
if _, ok := p2.IDMap[i]; ok {
|
||||
p2ID = res.RefResource.Identifiers.First()
|
||||
p2ID = res.RefRes.Identifiers.First()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if p2ID == "" {
|
||||
return resource.ComposeRecordErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ComposeRecordErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(composeTypes.RecordRbacResourceTpl(), composeTypes.RecordResourceType, p0ID, p1ID, p2ID)
|
||||
return fmt.Sprintf(composeTypes.RecordRbacResourceTpl(), composeTypes.RecordResourceType, p0ID, p1ID, p2ID), nil
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
if len(res.RefPath) > 0 {
|
||||
p0 := resource.FindComposeNamespace(state.ParentResources, res.RefPath[0].Identifiers)
|
||||
if p0 == nil {
|
||||
return resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
return "", resource.ComposeNamespaceErrUnresolved(res.RefPath[0].Identifiers)
|
||||
}
|
||||
p0ID = p0.Slug
|
||||
}
|
||||
if len(res.RefPath) > 1 {
|
||||
p1 := resource.FindComposeModule(state.ParentResources, res.RefPath[1].Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ComposeModuleErrUnresolved(res.RefPath[1].Identifiers)
|
||||
return "", resource.ComposeModuleErrUnresolved(res.RefPath[1].Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
if r.refRbacRes != nil {
|
||||
modRef := r.refPathRes[1]
|
||||
p2 := resource.FindComposeModuleField(state.ParentResources, modRef.Identifiers, r.refRbacRes.Identifiers)
|
||||
if p2 == nil {
|
||||
return "", resource.ComposeModuleFieldErrUnresolved(r.refRbacRes.Identifiers)
|
||||
}
|
||||
|
||||
p2ID = p2.Name
|
||||
}
|
||||
|
||||
// @todo specific module field RBAC
|
||||
r.res.Resource = fmt.Sprintf(composeTypes.ModuleFieldRbacResourceTpl(), composeTypes.ModuleFieldResourceType, p0ID, p1ID, p2ID)
|
||||
return fmt.Sprintf(composeTypes.ModuleFieldRbacResourceTpl(), composeTypes.ModuleFieldResourceType, p0ID, p1ID, p2ID), nil
|
||||
case systemTypes.UserResourceType:
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindUser(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindUser(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.UserErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.UserErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(systemTypes.UserRbacResourceTpl(), systemTypes.UserResourceType, p1ID)
|
||||
return fmt.Sprintf(systemTypes.UserRbacResourceTpl(), systemTypes.UserResourceType, p1ID), nil
|
||||
case systemTypes.RoleResourceType:
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindRole(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindRole(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.RoleErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.RoleErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Handle
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(systemTypes.RoleRbacResourceTpl(), systemTypes.RoleResourceType, p1ID)
|
||||
return fmt.Sprintf(systemTypes.RoleRbacResourceTpl(), systemTypes.RoleResourceType, p1ID), nil
|
||||
case systemTypes.ApplicationResourceType:
|
||||
if res.RefResource != nil {
|
||||
p1 := resource.FindApplication(state.ParentResources, res.RefResource.Identifiers)
|
||||
if res.RefRes != nil {
|
||||
p1 := resource.FindApplication(state.ParentResources, res.RefRes.Identifiers)
|
||||
if p1 == nil {
|
||||
return resource.ApplicationErrUnresolved(res.RefResource.Identifiers)
|
||||
return "", resource.ApplicationErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
p1ID = p1.Name
|
||||
}
|
||||
|
||||
r.res.Resource = fmt.Sprintf(systemTypes.ApplicationRbacResourceTpl(), systemTypes.ApplicationResourceType, p1ID)
|
||||
return fmt.Sprintf(systemTypes.ApplicationRbacResourceTpl(), systemTypes.ApplicationResourceType, p1ID), nil
|
||||
|
||||
// // @todo
|
||||
// case systemTypes.ApigwRouteResourceType:
|
||||
// case systemTypes.ApigwFilterResourceType:
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported resource type '%s' for RBAC YAML encode", r.res.Resource)
|
||||
// // @todo
|
||||
// case systemTypes.ApigwRouteResourceType:
|
||||
// case systemTypes.ApigwFilterResourceType:
|
||||
}
|
||||
|
||||
next:
|
||||
doc.addRbacRule(r)
|
||||
return "", fmt.Errorf("unsupported resource type '%s' for RBAC YAML encode", r.res.Resource)
|
||||
}
|
||||
|
||||
return nil
|
||||
func (n *rbacRule) handleComposeRecord(pp []resource.Interface) bool {
|
||||
for _, p := range pp {
|
||||
if p.ResourceType() == composeTypes.RecordResourceType && p.Identifiers().HasAny(n.refPathRes[1].Identifiers) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *rbacRule) handleComposeModuleField(pp []resource.Interface) bool {
|
||||
for _, p := range pp {
|
||||
if p.ResourceType() == composeTypes.ModuleResourceType && p.Identifiers().HasAny(n.refPathRes[1].Identifiers) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (rr rbacRuleSet) MarshalYAML() (interface{}, error) {
|
||||
@@ -272,13 +318,8 @@ func (rr rbacRuleSet) MarshalYAML() (interface{}, error) {
|
||||
}
|
||||
}
|
||||
|
||||
rr := roleRules[0].relRole
|
||||
rk := rr.Handle
|
||||
if rk == "" {
|
||||
rk = rr.Name
|
||||
}
|
||||
roleNode, err = addMap(roleNode,
|
||||
rk, resNode,
|
||||
roleRules[0].getRoleKey(), resNode,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
|
||||
"github.com/cortezaproject/corteza-server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza-server/pkg/y7s"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -46,7 +47,7 @@ func (rr rbacRuleSet) decodeRbac(a rbac.Access, rules *yaml.Node) (oo rbacRuleSe
|
||||
Access: a,
|
||||
Operation: op.Value,
|
||||
},
|
||||
refRole: roleRef,
|
||||
refRole: resource.MakeRef(types.RoleResourceType, resource.MakeIdentifiers(roleRef)),
|
||||
}
|
||||
|
||||
if res != "" {
|
||||
@@ -75,21 +76,13 @@ func (rr rbacRuleSet) decodeRbac(a rbac.Access, rules *yaml.Node) (oo rbacRuleSe
|
||||
}
|
||||
|
||||
func (rr rbacRuleSet) bindResource(resI resource.Interface) rbacRuleSet {
|
||||
ref := &resource.Ref{
|
||||
ResourceType: resI.ResourceType(),
|
||||
Identifiers: resI.Identifiers(),
|
||||
}
|
||||
|
||||
var path []*resource.Ref
|
||||
if resRbac, ok := resI.(resource.RBACInterface); ok {
|
||||
path = resRbac.RBACPath()
|
||||
}
|
||||
res, ref, pp := resI.(resource.RBACInterface).RBACParts()
|
||||
|
||||
rtr := make(rbacRuleSet, 0, len(rr))
|
||||
for _, r := range rr {
|
||||
_ = r.SetResource(ref.ResourceType)
|
||||
r.refRes = ref
|
||||
r.refPathRes = path
|
||||
r.refRbacResource = res
|
||||
r.refRbacRes = ref
|
||||
r.refPathRes = pp
|
||||
rtr = append(rtr, r)
|
||||
}
|
||||
|
||||
@@ -100,20 +93,19 @@ func (rr rbacRuleSet) MarshalEnvoy() ([]resource.Interface, error) {
|
||||
var nn = make([]resource.Interface, 0, len(rr))
|
||||
|
||||
for _, r := range rr {
|
||||
nn = append(nn, resource.NewRbacRule(r.res, r.refRole, r.refRes, r.refPathRes...))
|
||||
nn = append(nn, resource.NewRbacRule(r.res, r.refRole.Identifiers.First(), r.refRbacRes, r.refRbacResource, r.refPathRes...))
|
||||
}
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (r *rbacRule) SetResource(res string) error {
|
||||
res, ref, pp, err := resource.ParseRule(res)
|
||||
_, ref, pp, err := resource.ParseRule(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res != "" {
|
||||
r.res.Resource = res
|
||||
}
|
||||
|
||||
return r.bindRefs(ref, pp, err)
|
||||
r.refRbacResource = res
|
||||
r.refRbacRes = ref
|
||||
r.refPathRes = pp
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ func (r *resourceTranslation) makeResourceTranslationResource(state *envoy.Resou
|
||||
p1ID = p1.Handle
|
||||
|
||||
// field
|
||||
f := resource.FindComposeModuleField(p1, res.RefRes.Identifiers)
|
||||
f := resource.FindComposeModuleField(state.ParentResources, res.RefPath[1].Identifiers, res.RefRes.Identifiers)
|
||||
if f == nil {
|
||||
return "", resource.ComposeModuleFieldErrUnresolved(res.RefRes.Identifiers)
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ func (rr resourceTranslationSet) bindResource(resI resource.Interface) resourceT
|
||||
|
||||
rtr := make(resourceTranslationSet, 0, len(rr))
|
||||
for _, r := range rr {
|
||||
|
||||
r.refResourceTranslation = res
|
||||
r.refLocaleRes = ref
|
||||
r.refPathRes = pp
|
||||
|
||||
+82
-6
@@ -1,12 +1,88 @@
|
||||
# Setup so we don't need any boilerplate code
|
||||
roles:
|
||||
r1:
|
||||
name: test role 1
|
||||
r2:
|
||||
name: test role 2
|
||||
|
||||
namespaces:
|
||||
ns1:
|
||||
name: test namespace 1
|
||||
|
||||
modules:
|
||||
mod1:
|
||||
name: test module 1
|
||||
fields:
|
||||
f1:
|
||||
label: test module field 1
|
||||
|
||||
charts:
|
||||
chr1:
|
||||
name: test chart 1
|
||||
|
||||
# Access control
|
||||
allow:
|
||||
r1:
|
||||
corteza::compose/:
|
||||
- access
|
||||
corteza::compose:
|
||||
- allow;r1;compose;op1
|
||||
|
||||
corteza::compose:namespace/*:
|
||||
- allow;r1;compose:namespace/*;op1
|
||||
corteza::compose:namespace/ns1:
|
||||
- allow;r1;compose:namespace/ns1;op1
|
||||
|
||||
corteza::compose:module/*/*:
|
||||
- allow;r1;compose:module/*/*;op1
|
||||
corteza::compose:module/ns1/*:
|
||||
- allow;r1;compose:module/ns1/*;op1
|
||||
corteza::compose:module/ns1/mod1:
|
||||
- allow;r1;compose:module/ns1/mod1;op1
|
||||
|
||||
corteza::compose:module-field/*/*/*:
|
||||
- allow;r1;compose:module-field/*/*/*;op1
|
||||
corteza::compose:module-field/ns1/*/*:
|
||||
- allow;r1;compose:module-field/ns1/*/*;op1
|
||||
corteza::compose:module-field/ns1/mod1/*:
|
||||
- allow;r1;compose:module-field/ns1/mod1/*;op1
|
||||
corteza::compose:module-field/ns1/mod1/f1:
|
||||
- allow;r1;compose:module-field/ns1/mod1/f1;op1
|
||||
|
||||
corteza::compose:chart/*/*:
|
||||
- allow;r1;compose:chart/*/*;op1
|
||||
corteza::compose:chart/ns1/*:
|
||||
- allow;r1;compose:chart/ns1/*;op1
|
||||
corteza::compose:chart/ns1/chr1:
|
||||
- allow;r1;compose:chart/ns1/chr1;op1
|
||||
|
||||
deny:
|
||||
r1:
|
||||
corteza::compose:
|
||||
- deny;r1;compose;op1
|
||||
|
||||
corteza::compose:namespace/*:
|
||||
- access
|
||||
# @todo see comment for rbac store marshal if I forget to mention this to you
|
||||
corteza::system/:
|
||||
- access
|
||||
- deny;r1;compose:namespace/*;op1
|
||||
corteza::compose:namespace/ns1:
|
||||
- deny;r1;compose:namespace/ns1;op1
|
||||
|
||||
corteza::compose:module/*/*:
|
||||
- deny;r1;compose:module/*/*;op1
|
||||
corteza::compose:module/ns1/*:
|
||||
- deny;r1;compose:module/ns1/*;op1
|
||||
corteza::compose:module/ns1/mod1:
|
||||
- deny;r1;compose:module/ns1/mod1;op1
|
||||
|
||||
corteza::compose:module-field/*/*/*:
|
||||
- deny;r1;compose:module-field/*/*/*;op1
|
||||
corteza::compose:module-field/ns1/*/*:
|
||||
- deny;r1;compose:module-field/ns1/*/*;op1
|
||||
corteza::compose:module-field/ns1/mod1/*:
|
||||
- deny;r1;compose:module-field/ns1/mod1/*;op1
|
||||
corteza::compose:module-field/ns1/mod1/f1:
|
||||
- deny;r1;compose:module-field/ns1/mod1/f1;op1
|
||||
|
||||
corteza::compose:chart/*/*:
|
||||
- deny;r1;compose:chart/*/*;op1
|
||||
corteza::compose:chart/ns1/*:
|
||||
- deny;r1;compose:chart/ns1/*;op1
|
||||
corteza::compose:chart/ns1/chr1:
|
||||
- deny;r1;compose:chart/ns1/chr1;op1
|
||||
|
||||
@@ -3,9 +3,6 @@ allow:
|
||||
corteza::compose/:
|
||||
- op1
|
||||
|
||||
corteza::system:apigw-route/*:
|
||||
- op1
|
||||
|
||||
corteza::compose:namespace/*:
|
||||
- op1
|
||||
|
||||
|
||||
@@ -405,22 +405,6 @@ func TestYamlStore_base(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "rbac rules",
|
||||
file: "rbac_rules",
|
||||
pre: func() (err error) {
|
||||
return collect(
|
||||
storeRole(ctx, s, 100, "r1"),
|
||||
)
|
||||
},
|
||||
check: func(req *require.Assertions) {
|
||||
rr, _, err := store.SearchRbacRules(ctx, s, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
req.NotNil(rr)
|
||||
req.Len(rr, 3)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "records; no namespace",
|
||||
file: "records_no_ns",
|
||||
@@ -552,54 +536,6 @@ func TestYamlStore_base(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "base access control",
|
||||
file: "access_control_base",
|
||||
check: func(req *require.Assertions) {
|
||||
role, err := store.LookupRoleByHandle(ctx, s, "authenticated")
|
||||
req.NoError(err)
|
||||
req.NotNil(role)
|
||||
|
||||
rr, _, err := store.SearchRbacRules(ctx, s, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(rr, 16)
|
||||
|
||||
// Check that the role is ok
|
||||
for _, r := range rr {
|
||||
req.Equal(role.ID, r.RoleID)
|
||||
}
|
||||
|
||||
resources := []string{
|
||||
"corteza::compose:namespace/11",
|
||||
"corteza::compose:namespace/11",
|
||||
"corteza::compose:module/11/12",
|
||||
"corteza::compose:module/11/12",
|
||||
"corteza::compose:page/11/13",
|
||||
"corteza::compose:page/11/13",
|
||||
"corteza::compose:chart/11/14",
|
||||
"corteza::compose:chart/11/14",
|
||||
"corteza::system:role/16",
|
||||
"corteza::system:role/16",
|
||||
"corteza::system:user/17",
|
||||
"corteza::system:user/17",
|
||||
"corteza::system:application/18",
|
||||
"corteza::system:application/18",
|
||||
"corteza::compose/",
|
||||
"corteza::compose/",
|
||||
}
|
||||
|
||||
for i, res := range resources {
|
||||
req.Equal(res, rr[i].Resource)
|
||||
if i%2 == 0 {
|
||||
req.Equal("op1", rr[i].Operation)
|
||||
req.Equal(rbac.Allow, rr[i].Access)
|
||||
} else {
|
||||
req.Equal("op2", rr[i].Operation)
|
||||
req.Equal(rbac.Deny, rr[i].Access)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "settings",
|
||||
file: "settings",
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestYamlStore_provision(t *testing.T) {
|
||||
rrls, _, err = store.SearchRbacRules(ctx, s, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
req.NotNil(rrls)
|
||||
req.Len(rrls, 15)
|
||||
req.Len(rrls, 14)
|
||||
})
|
||||
|
||||
t.Run("namespaces", func(t *testing.T) {
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy"
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
|
||||
su "github.com/cortezaproject/corteza-server/pkg/envoy/store"
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/yaml"
|
||||
"github.com/cortezaproject/corteza-server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestYamlStore_rbac(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
namespace = "base"
|
||||
s = initServices(ctx, t)
|
||||
f = "rbac_rules.yaml"
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
ctx = auth.SetIdentityToContext(ctx, auth.ServiceUser())
|
||||
|
||||
ni := uint64(10)
|
||||
su.NextID = func() uint64 {
|
||||
ni++
|
||||
return ni
|
||||
}
|
||||
|
||||
truncateStore(ctx, s, t)
|
||||
|
||||
// util to check rule's operation
|
||||
checkPfx := func(req *require.Assertions, rr rbac.RuleSet, pfx string) {
|
||||
for _, r := range rr {
|
||||
req.Contains(r.Operation, pfx)
|
||||
}
|
||||
}
|
||||
// util to check the current store state if it's as expected
|
||||
checkStore := func() {
|
||||
// Preload all the resource
|
||||
ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "ns1")
|
||||
req.NoError(err)
|
||||
|
||||
mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, ns.ID, "mod1")
|
||||
req.NoError(err)
|
||||
|
||||
fld, err := store.LookupComposeModuleFieldByModuleIDName(ctx, s, mod.ID, "f1")
|
||||
req.NoError(err)
|
||||
|
||||
chr, err := store.LookupComposeChartByNamespaceIDHandle(ctx, s, ns.ID, "chr1")
|
||||
req.NoError(err)
|
||||
|
||||
// Preload RBAC rules
|
||||
rr, _, err := store.SearchRbacRules(ctx, s, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
// Check
|
||||
// - component
|
||||
composeRR := rbacRuleFilterByResource(rr, types.ComponentRbacResource())
|
||||
req.Len(composeRR, 2)
|
||||
req.Len(composeRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(composeRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, composeRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, composeRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
// - namespace
|
||||
nsRR := rbacRuleFilterByResource(rr, types.NamespaceRbacResource(0))
|
||||
req.Len(nsRR, 2)
|
||||
req.Len(nsRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(nsRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, nsRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, nsRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
nsRR = rbacRuleFilterByResource(rr, ns.RbacResource())
|
||||
req.Len(nsRR, 2)
|
||||
req.Len(nsRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(nsRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, nsRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, nsRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
// - module
|
||||
modRR := rbacRuleFilterByResource(rr, types.ModuleRbacResource(0, 0))
|
||||
req.Len(modRR, 2)
|
||||
req.Len(modRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(modRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, modRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, modRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
modRR = rbacRuleFilterByResource(rr, types.ModuleRbacResource(ns.ID, 0))
|
||||
req.Len(modRR, 2)
|
||||
req.Len(modRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(modRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, modRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, modRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
modRR = rbacRuleFilterByResource(rr, types.ModuleRbacResource(ns.ID, mod.ID))
|
||||
req.Len(modRR, 2)
|
||||
req.Len(modRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(modRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, modRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, modRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
// - module field
|
||||
mfRR := rbacRuleFilterByResource(rr, types.ModuleFieldRbacResource(0, 0, 0))
|
||||
req.Len(mfRR, 2)
|
||||
req.Len(mfRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(mfRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
mfRR = rbacRuleFilterByResource(rr, types.ModuleFieldRbacResource(ns.ID, 0, 0))
|
||||
req.Len(mfRR, 2)
|
||||
req.Len(mfRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(mfRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
mfRR = rbacRuleFilterByResource(rr, types.ModuleFieldRbacResource(ns.ID, mod.ID, 0))
|
||||
req.Len(mfRR, 2)
|
||||
req.Len(mfRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(mfRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
mfRR = rbacRuleFilterByResource(rr, types.ModuleFieldRbacResource(ns.ID, mod.ID, fld.ID))
|
||||
req.Len(mfRR, 2)
|
||||
req.Len(mfRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(mfRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, mfRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
// - chart
|
||||
chrRR := rbacRuleFilterByResource(rr, types.ChartRbacResource(0, 0))
|
||||
req.Len(chrRR, 2)
|
||||
req.Len(chrRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(chrRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, chrRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, chrRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
chrRR = rbacRuleFilterByResource(rr, types.ChartRbacResource(ns.ID, 0))
|
||||
req.Len(chrRR, 2)
|
||||
req.Len(chrRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(chrRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, chrRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, chrRR.FilterAccess(rbac.Deny), "deny")
|
||||
|
||||
chrRR = rbacRuleFilterByResource(rr, types.ChartRbacResource(ns.ID, chr.ID))
|
||||
req.Len(chrRR, 2)
|
||||
req.Len(chrRR.FilterAccess(rbac.Allow), 1)
|
||||
req.Len(chrRR.FilterAccess(rbac.Deny), 1)
|
||||
checkPfx(req, chrRR.FilterAccess(rbac.Allow), "allow")
|
||||
checkPfx(req, chrRR.FilterAccess(rbac.Deny), "deny")
|
||||
}
|
||||
|
||||
// YAML -> Store
|
||||
nn, err := decodeYaml(ctx, namespace, f)
|
||||
req.NoError(err)
|
||||
err = encode(ctx, s, nn)
|
||||
req.NoError(err)
|
||||
|
||||
checkStore()
|
||||
|
||||
// Store -> YAML -> Store
|
||||
df := su.NewDecodeFilter().
|
||||
ComposeNamespace(&types.NamespaceFilter{
|
||||
Slug: "ns1",
|
||||
}).
|
||||
ComposeModule(&types.ModuleFilter{}).
|
||||
ComposeChart(&types.ChartFilter{}).
|
||||
Roles(&systemTypes.RoleFilter{Handle: "r1"}).
|
||||
Rbac(&rbac.RuleFilter{})
|
||||
|
||||
// - decode store
|
||||
sd := su.Decoder()
|
||||
nn, err = sd.Decode(ctx, s, df)
|
||||
req.NoError(err)
|
||||
//
|
||||
// - into yaml
|
||||
ye := yaml.NewYamlEncoder(&yaml.EncoderConfig{})
|
||||
bld := envoy.NewBuilder(ye)
|
||||
g, err := bld.Build(ctx, nn...)
|
||||
req.NoError(err)
|
||||
err = envoy.Encode(ctx, g, ye)
|
||||
req.NoError(err)
|
||||
ss := ye.Stream()
|
||||
//
|
||||
// - cleanup the store
|
||||
truncateStore(ctx, s, t)
|
||||
//
|
||||
// - back into store
|
||||
se := su.NewStoreEncoder(s, &su.EncoderConfig{})
|
||||
yd := yaml.Decoder()
|
||||
nn = make([]resource.Interface, 0, len(nn))
|
||||
for _, s := range ss {
|
||||
mm, err := yd.Decode(ctx, s.Source, nil)
|
||||
req.NoError(err)
|
||||
nn = append(nn, mm...)
|
||||
}
|
||||
bld = envoy.NewBuilder(se)
|
||||
g, err = bld.Build(ctx, nn...)
|
||||
req.NoError(err)
|
||||
|
||||
err = envoy.Encode(ctx, g, se)
|
||||
req.NoError(err)
|
||||
//
|
||||
// - check store state
|
||||
checkStore()
|
||||
|
||||
truncateStore(ctx, s, t)
|
||||
}
|
||||
|
||||
func rbacRuleFilterByResource(rr rbac.RuleSet, res string) rbac.RuleSet {
|
||||
out := make(rbac.RuleSet, 0, len(rr)/2)
|
||||
|
||||
for _, r := range rr {
|
||||
if r.Resource == res {
|
||||
out = append(out, r)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user