From 74d6eabf94d8820edd4262e2a455dbd40780c402 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Fri, 31 Dec 2021 17:25:14 +0100 Subject: [PATCH] Various template & def fixes --- .github/workflows/snapshot.yml | 3 +- .../gocode/locale/$component_types.go.tpl | 6 +- codegen/envoy-rbac.cue | 2 +- codegen/locale-service.cue | 3 +- codegen/locale-types.cue | 2 +- codegen/rbac-access_control.cue | 8 +- codegen/rbac-types.cue | 4 +- codegen/schema/locale.cue | 2 - codegen/schema/rbac.cue | 11 +- compose/module-field.cue | 4 +- compose/rest/module.go | 8 +- compose/service/access_control.gen.go | 95 +++--- compose/service/record.go | 14 +- compose/types/locale.gen.go | 22 +- compose/types/rbac.gen.go | 17 +- .../resource_translation_parse.gen.go | 1 - pkg/envoy/store/encoder.go | 4 +- system/service/access_control.gen.go | 276 +++++++++++++++--- system/types/rbac.gen.go | 136 ++++++--- 19 files changed, 443 insertions(+), 175 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 2d331978e..ab009f526 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -27,8 +27,7 @@ jobs: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - - run: make test.codegen -# - run: make test.all test.codegen + - run: make test.codegen test.all snapshot-docker: runs-on: ubuntu-latest diff --git a/codegen/assets/templates/gocode/locale/$component_types.go.tpl b/codegen/assets/templates/gocode/locale/$component_types.go.tpl index 28a957631..7bdbc0655 100644 --- a/codegen/assets/templates/gocode/locale/$component_types.go.tpl +++ b/codegen/assets/templates/gocode/locale/$component_types.go.tpl @@ -41,7 +41,7 @@ var ( // // This function is auto-generated func (r {{ .expIdent }}) ResourceTranslation() string { - return {{ .expIdent }}ResourceTranslation({{ if .references }}{{ range .references }}r.{{ . }},{{ end }}{{ end }}) + return {{ .expIdent }}ResourceTranslation({{ range .references }}r.{{ .refField }},{{ end }}) } // {{ .expIdent }}ResourceTranslation returns string representation of Locale resource for {{ .expIdent }} @@ -49,12 +49,12 @@ func (r {{ .expIdent }}) ResourceTranslation() string { // Locale resource is in the {{ .type }}/{{- if .references }}...{{ end }} format // // This function is auto-generated -func {{ .expIdent }}ResourceTranslation({{ if .references }}{{ range .references }}{{ . }} uint64,{{ end }}{{ end }}) string { +func {{ .expIdent }}ResourceTranslation({{ range .references }}{{ .refField }} uint64,{{ end }}) string { {{- if .references }} cpts := []interface{{"{}"}}{ {{ .expIdent }}ResourceTranslationType, {{- range .references }} - strconv.FormatUint({{ . }}, 10), + strconv.FormatUint({{ .refField }}, 10), {{- end }} } diff --git a/codegen/envoy-rbac.cue b/codegen/envoy-rbac.cue index f7dd1aa9b..e90892400 100644 --- a/codegen/envoy-rbac.cue +++ b/codegen/envoy-rbac.cue @@ -88,7 +88,7 @@ envoyRBAC: payload: { package: "resource" imports: [ - for cmp in app.corteza.components { + for cmp in app.corteza.components for res in cmp.resources if res.locale != _|_ { "\(cmp.ident)Types \"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"" }, ] diff --git a/codegen/locale-service.cue b/codegen/locale-service.cue index 3f8810b70..8a25a331e 100644 --- a/codegen/locale-service.cue +++ b/codegen/locale-service.cue @@ -3,7 +3,6 @@ package codegen import ( "github.com/cortezaproject/corteza-server/app" "github.com/cortezaproject/corteza-server/codegen/schema" - "strings" ) localeService: @@ -25,7 +24,7 @@ localeService: expIdent: res.expIdent ident: res.ident - references: [ for field in res.locale.resource.references {strings.ToTitle(field)}] + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] extended: res.locale.extended diff --git a/codegen/locale-types.cue b/codegen/locale-types.cue index 5cf6fcace..a9e6b8e69 100644 --- a/codegen/locale-types.cue +++ b/codegen/locale-types.cue @@ -23,7 +23,7 @@ localeTypes: const: res.locale.resource.const type: res.locale.resource.type - references: [ for field in res.locale.resource.references {strings.ToTitle(field)}] + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] extended: res.locale.extended diff --git a/codegen/rbac-access_control.cue b/codegen/rbac-access_control.cue index 82d1151ee..5dd4f810e 100644 --- a/codegen/rbac-access_control.cue +++ b/codegen/rbac-access_control.cue @@ -28,9 +28,7 @@ rbacAccessControl: description: op.description checkFuncName: op.checkFuncName - if len(res.parents) > 0 { - references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] - } + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] }, for op in cmp.rbac.operations { "op": op.handle @@ -49,9 +47,7 @@ rbacAccessControl: label: res.ident const: "types.\(res.expIdent)ResourceType" funcName: "rbac\(res.expIdent)ResourceValidator" - if len(res.parents) > 0 { - references: [ for p in res.parents {p.refField}, "ID"] - } + references: [ for p in res.parents {p.refField}, "ID"] operations: [ for op in res.rbac.operations {op.handle}] }, { diff --git a/codegen/rbac-types.cue b/codegen/rbac-types.cue index ee1ae8875..a374e65df 100644 --- a/codegen/rbac-types.cue +++ b/codegen/rbac-types.cue @@ -25,9 +25,7 @@ rbacTypes: attFunc: "\(res.expIdent)RbacAttributes" goType: res.expIdent - if len(res.parents) > 0 { - references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] - } + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] }, { const: "ComponentResourceType" diff --git a/codegen/schema/locale.cue b/codegen/schema/locale.cue index 4908f6acb..69261b822 100644 --- a/codegen/schema/locale.cue +++ b/codegen/schema/locale.cue @@ -14,8 +14,6 @@ import ( extended: bool | *false resource: { - // @todo merge with RBAC res-ref and move 2 levels lower. - references: [ ...string] | *["ID"] type: string const: string | *("\(resourceExpIdent)ResourceTranslationType") } diff --git a/codegen/schema/rbac.cue b/codegen/schema/rbac.cue index d09f7976a..712d007f8 100644 --- a/codegen/schema/rbac.cue +++ b/codegen/schema/rbac.cue @@ -43,14 +43,19 @@ import ( _operation: strings.Replace(strings.Replace(handle, "-", " ", -1), "_", " ", -1) _opSplit: strings.Split(_operation, ".") + _opFlip: [_opSplit[len(_opSplit)-1]] + _opSplit[0:len(_opSplit)-1] _opFinal: strings.Replace(strings.ToTitle(strings.Join(_opFlip, " ")), " ", "", -1) if _resourceExpIdent == _|_ { - checkFuncName: #expIdent | *("Can" + _opFinal) + checkFuncName: #expIdent | *"Can\(_opFinal)" } - if _resourceExpIdent != _|_ { - checkFuncName: #expIdent | *("Can" + _opFinal + _resourceExpIdent) + if len(_opSplit) > 1 && _resourceExpIdent != _|_ { + checkFuncName: #expIdent | *"Can\(_opFinal)On\(_resourceExpIdent)" + } + + if len(_opSplit) <= 1 && _resourceExpIdent != _|_ { + checkFuncName: #expIdent | *"Can\(_opFinal)\(_resourceExpIdent)" } } diff --git a/compose/module-field.cue b/compose/module-field.cue index 62e6e6f99..46ef3b388 100644 --- a/compose/module-field.cue +++ b/compose/module-field.cue @@ -12,8 +12,8 @@ moduleField: schema.#resource & { rbac: { operations: { - "recod.value.read": description: "Read field value on records" - "recod.value.update": description: "Update field value on records" + "record.value.read": description: "Read field value on records" + "record.value.update": description: "Update field value on records" } } diff --git a/compose/rest/module.go b/compose/rest/module.go index d1d84d292..0499762c1 100644 --- a/compose/rest/module.go +++ b/compose/rest/module.go @@ -51,8 +51,8 @@ type ( CanCreateRecordOnModule(context.Context, *types.Module) bool CanReadRecord(context.Context, *types.Record) bool - CanReadRecordValue(context.Context, *types.ModuleField) bool - CanUpdateRecordValue(context.Context, *types.ModuleField) bool + CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool + CanUpdateRecordValueOnModuleField(context.Context, *types.ModuleField) bool } ) @@ -196,8 +196,8 @@ func (ctrl Module) makeFieldsPayload(ctx context.Context, m *types.Module) (out out[i] = &moduleFieldPayload{ ModuleField: f, - CanReadRecordValue: ctrl.ac.CanReadRecordValue(ctx, f), - CanUpdateRecordValue: ctrl.ac.CanUpdateRecordValue(ctx, f), + CanReadRecordValue: ctrl.ac.CanReadRecordValueOnModuleField(ctx, f), + CanUpdateRecordValue: ctrl.ac.CanUpdateRecordValueOnModuleField(ctx, f), } } diff --git a/compose/service/access_control.gen.go b/compose/service/access_control.gen.go index ae387c225..523a52e29 100644 --- a/compose/service/access_control.gen.go +++ b/compose/service/access_control.gen.go @@ -97,61 +97,61 @@ func (svc accessControl) List() (out []map[string]string) { { "type": types.ModuleFieldResourceType, "any": types.ModuleFieldRbacResource(0, 0, 0), - "op": "recod.value.read", + "op": "record.value.read", }, { "type": types.ModuleFieldResourceType, "any": types.ModuleFieldRbacResource(0, 0, 0), - "op": "recod.value.update", + "op": "record.value.update", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "read", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "update", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "delete", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "manage", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "module.create", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "modules.search", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "chart.create", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "charts.search", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "page.create", }, { "type": types.NamespaceResourceType, - "any": types.NamespaceRbacResource(), + "any": types.NamespaceRbacResource(0), "op": "pages.search", }, { @@ -329,32 +329,32 @@ func (svc accessControl) CanDeleteModule(ctx context.Context, r *types.Module) b return svc.can(ctx, "delete", r) } -// CanCreateRecordModule checks if current user can create record +// CanCreateRecordOnModule checks if current user can create record // // This function is auto-generated -func (svc accessControl) CanCreateRecordModule(ctx context.Context, r *types.Module) bool { +func (svc accessControl) CanCreateRecordOnModule(ctx context.Context, r *types.Module) bool { return svc.can(ctx, "record.create", r) } -// CanSearchRecordsModule checks if current user can list, search or filter records +// CanSearchRecordsOnModule checks if current user can list, search or filter records // // This function is auto-generated -func (svc accessControl) CanSearchRecordsModule(ctx context.Context, r *types.Module) bool { +func (svc accessControl) CanSearchRecordsOnModule(ctx context.Context, r *types.Module) bool { return svc.can(ctx, "records.search", r) } -// CanReadRecodValueModuleField checks if current user can read field value on records +// CanReadRecordValueOnModuleField checks if current user can read field value on records // // This function is auto-generated -func (svc accessControl) CanReadRecodValueModuleField(ctx context.Context, r *types.ModuleField) bool { - return svc.can(ctx, "recod.value.read", r) +func (svc accessControl) CanReadRecordValueOnModuleField(ctx context.Context, r *types.ModuleField) bool { + return svc.can(ctx, "record.value.read", r) } -// CanUpdateRecodValueModuleField checks if current user can update field value on records +// CanUpdateRecordValueOnModuleField checks if current user can update field value on records // // This function is auto-generated -func (svc accessControl) CanUpdateRecodValueModuleField(ctx context.Context, r *types.ModuleField) bool { - return svc.can(ctx, "recod.value.update", r) +func (svc accessControl) CanUpdateRecordValueOnModuleField(ctx context.Context, r *types.ModuleField) bool { + return svc.can(ctx, "record.value.update", r) } // CanReadNamespace checks if current user can read @@ -385,45 +385,45 @@ func (svc accessControl) CanManageNamespace(ctx context.Context, r *types.Namesp return svc.can(ctx, "manage", r) } -// CanCreateModuleNamespace checks if current user can create module on namespace +// CanCreateModuleOnNamespace checks if current user can create module on namespace // // This function is auto-generated -func (svc accessControl) CanCreateModuleNamespace(ctx context.Context, r *types.Namespace) bool { +func (svc accessControl) CanCreateModuleOnNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "module.create", r) } -// CanSearchModulesNamespace checks if current user can list, search or filter module on namespace +// CanSearchModulesOnNamespace checks if current user can list, search or filter module on namespace // // This function is auto-generated -func (svc accessControl) CanSearchModulesNamespace(ctx context.Context, r *types.Namespace) bool { +func (svc accessControl) CanSearchModulesOnNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "modules.search", r) } -// CanCreateChartNamespace checks if current user can create chart on namespace +// CanCreateChartOnNamespace checks if current user can create chart on namespace // // This function is auto-generated -func (svc accessControl) CanCreateChartNamespace(ctx context.Context, r *types.Namespace) bool { +func (svc accessControl) CanCreateChartOnNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "chart.create", r) } -// CanSearchChartsNamespace checks if current user can list, search or filter chart on namespace +// CanSearchChartsOnNamespace checks if current user can list, search or filter chart on namespace // // This function is auto-generated -func (svc accessControl) CanSearchChartsNamespace(ctx context.Context, r *types.Namespace) bool { +func (svc accessControl) CanSearchChartsOnNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "charts.search", r) } -// CanCreatePageNamespace checks if current user can create page on namespace +// CanCreatePageOnNamespace checks if current user can create page on namespace // // This function is auto-generated -func (svc accessControl) CanCreatePageNamespace(ctx context.Context, r *types.Namespace) bool { +func (svc accessControl) CanCreatePageOnNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "page.create", r) } -// CanSearchPagesNamespace checks if current user can list, search or filter pages on namespace +// CanSearchPagesOnNamespace checks if current user can list, search or filter pages on namespace // // This function is auto-generated -func (svc accessControl) CanSearchPagesNamespace(ctx context.Context, r *types.Namespace) bool { +func (svc accessControl) CanSearchPagesOnNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "pages.search", r) } @@ -562,8 +562,8 @@ func rbacResourceOperations(r string) map[string]bool { } case types.ModuleFieldResourceType: return map[string]bool{ - "recod.value.read": true, - "recod.value.update": true, + "record.value.read": true, + "record.value.update": true, } case types.NamespaceResourceType: return map[string]bool{ @@ -758,6 +758,29 @@ func rbacNamespaceResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.NamespaceResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for namespace resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } diff --git a/compose/service/record.go b/compose/service/record.go index 2d2c0de81..cec0c5055 100644 --- a/compose/service/record.go +++ b/compose/service/record.go @@ -62,8 +62,8 @@ type ( } recordValueAccessController interface { - CanReadRecordValue(context.Context, *types.ModuleField) bool - CanUpdateRecordValue(context.Context, *types.ModuleField) bool + CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool + CanUpdateRecordValueOnModuleField(context.Context, *types.ModuleField) bool } recordAccessController interface { @@ -637,7 +637,7 @@ func RecordValueUpdateOpCheck(ctx context.Context, ac recordValueAccessControlle return nil } - if v.IsUpdated() && !ac.CanUpdateRecordValue(ctx, f) { + if v.IsUpdated() && !ac.CanUpdateRecordValueOnModuleField(ctx, f) { rve.Push(types.RecordValueError{Kind: "updateDenied", Meta: map[string]interface{}{"field": v.Name, "value": v.Value}}) } @@ -908,7 +908,7 @@ func (svc record) procUpdate(ctx context.Context, invokerID uint64, m *types.Mod upd = RecordUpdateOwner(invokerID, upd, old) upd.Values = old.Values.Merge(m.Fields, upd.Values, func(f *types.ModuleField) bool { - return svc.ac.CanUpdateRecordValue(ctx, m.Fields.FindByName(f.Name)) + return svc.ac.CanUpdateRecordValueOnModuleField(ctx, m.Fields.FindByName(f.Name)) }) if rve = RecordValueUpdateOpCheck(ctx, svc.ac, m, upd.Values); !rve.IsValid() { @@ -1095,7 +1095,7 @@ func (svc record) Organize(ctx context.Context, namespaceID, moduleID, recordID return fmt.Errorf("cannot reorder on multi-value field %q", posField) } - if !svc.ac.CanUpdateRecordValue(ctx, sf) { + if !svc.ac.CanUpdateRecordValueOnModuleField(ctx, sf) { return RecordErrNotAllowedToUpdate() } @@ -1119,7 +1119,7 @@ func (svc record) Organize(ctx context.Context, namespaceID, moduleID, recordID return fmt.Errorf("cannot update multi-value field %q", posField) } - if !svc.ac.CanUpdateRecordValue(ctx, vf) { + if !svc.ac.CanUpdateRecordValueOnModuleField(ctx, vf) { return RecordErrNotAllowedToUpdate() } @@ -1404,7 +1404,7 @@ func ComposeRecordFilterAC(ctx context.Context, ac recordValueAccessController, ) for _, f := range m.Fields { - readableFields[f.Name] = ac.CanReadRecordValue(ctx, f) + readableFields[f.Name] = ac.CanReadRecordValueOnModuleField(ctx, f) } for _, r := range rr { diff --git a/compose/types/locale.gen.go b/compose/types/locale.gen.go index d267f6df4..97fa977f0 100644 --- a/compose/types/locale.gen.go +++ b/compose/types/locale.gen.go @@ -55,7 +55,7 @@ var ( // // This function is auto-generated func (r Module) ResourceTranslation() string { - return ModuleResourceTranslation(r.ID) + return ModuleResourceTranslation(r.NamespaceID, r.ID) } // ModuleResourceTranslation returns string representation of Locale resource for Module @@ -63,9 +63,10 @@ func (r Module) ResourceTranslation() string { // Locale resource is in the compose:module/... format // // This function is auto-generated -func ModuleResourceTranslation(ID uint64) string { +func ModuleResourceTranslation(NamespaceID uint64, ID uint64) string { cpts := []interface{}{ ModuleResourceTranslationType, + strconv.FormatUint(NamespaceID, 10), strconv.FormatUint(ID, 10), } @@ -73,7 +74,7 @@ func ModuleResourceTranslation(ID uint64) string { } func ModuleResourceTranslationTpl() string { - return "%s/%s" + return "%s/%s/%s" } func (r *Module) DecodeTranslations(tt locale.ResourceTranslationIndex) { @@ -104,7 +105,7 @@ func (r *Module) EncodeTranslations() (out locale.ResourceTranslationSet) { // // This function is auto-generated func (r ModuleField) ResourceTranslation() string { - return ModuleFieldResourceTranslation(r.ID) + return ModuleFieldResourceTranslation(r.NamespaceID, r.ModuleID, r.ID) } // ModuleFieldResourceTranslation returns string representation of Locale resource for ModuleField @@ -112,9 +113,11 @@ func (r ModuleField) ResourceTranslation() string { // Locale resource is in the compose:module-field/... format // // This function is auto-generated -func ModuleFieldResourceTranslation(ID uint64) string { +func ModuleFieldResourceTranslation(NamespaceID uint64, ModuleID uint64, ID uint64) string { cpts := []interface{}{ ModuleFieldResourceTranslationType, + strconv.FormatUint(NamespaceID, 10), + strconv.FormatUint(ModuleID, 10), strconv.FormatUint(ID, 10), } @@ -122,7 +125,7 @@ func ModuleFieldResourceTranslation(ID uint64) string { } func ModuleFieldResourceTranslationTpl() string { - return "%s/%s" + return "%s/%s/%s/%s" } func (r *ModuleField) DecodeTranslations(tt locale.ResourceTranslationIndex) { @@ -251,7 +254,7 @@ func (r *Namespace) EncodeTranslations() (out locale.ResourceTranslationSet) { // // This function is auto-generated func (r Page) ResourceTranslation() string { - return PageResourceTranslation(r.ID) + return PageResourceTranslation(r.NamespaceID, r.ID) } // PageResourceTranslation returns string representation of Locale resource for Page @@ -259,9 +262,10 @@ func (r Page) ResourceTranslation() string { // Locale resource is in the compose:page/... format // // This function is auto-generated -func PageResourceTranslation(ID uint64) string { +func PageResourceTranslation(NamespaceID uint64, ID uint64) string { cpts := []interface{}{ PageResourceTranslationType, + strconv.FormatUint(NamespaceID, 10), strconv.FormatUint(ID, 10), } @@ -269,7 +273,7 @@ func PageResourceTranslation(ID uint64) string { } func PageResourceTranslationTpl() string { - return "%s/%s" + return "%s/%s/%s" } func (r *Page) DecodeTranslations(tt locale.ResourceTranslationIndex) { diff --git a/compose/types/rbac.gen.go b/compose/types/rbac.gen.go index 98f15e2a4..4198023a2 100644 --- a/compose/types/rbac.gen.go +++ b/compose/types/rbac.gen.go @@ -153,21 +153,28 @@ func ModuleFieldRbacResourceTpl() string { // // This function is auto-generated func (r Namespace) RbacResource() string { - return NamespaceRbacResource() + return NamespaceRbacResource(r.ID) } // NamespaceRbacResource returns string representation of RBAC resource for Namespace // -// RBAC resource is in the corteza::compose:namespace/ format +// RBAC resource is in the corteza::compose:namespace/... format // // This function is auto-generated -func NamespaceRbacResource() string { - return NamespaceResourceType + "/" +func NamespaceRbacResource(id uint64) string { + cpts := []interface{}{NamespaceResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(NamespaceRbacResourceTpl(), cpts...) } func NamespaceRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Page by calling PageRbacResource fn diff --git a/pkg/envoy/resource/resource_translation_parse.gen.go b/pkg/envoy/resource/resource_translation_parse.gen.go index d912071c3..12bd1f611 100644 --- a/pkg/envoy/resource/resource_translation_parse.gen.go +++ b/pkg/envoy/resource/resource_translation_parse.gen.go @@ -9,7 +9,6 @@ package resource import ( "fmt" composeTypes "github.com/cortezaproject/corteza-server/compose/types" - systemTypes "github.com/cortezaproject/corteza-server/system/types" "strings" ) diff --git a/pkg/envoy/store/encoder.go b/pkg/envoy/store/encoder.go index 344c41249..299f31a88 100644 --- a/pkg/envoy/store/encoder.go +++ b/pkg/envoy/store/encoder.go @@ -49,8 +49,8 @@ type ( composeRecordAccessController } composeRecordValueAccessController interface { - CanReadRecordValue(context.Context, *types.ModuleField) bool - CanUpdateRecordValue(context.Context, *types.ModuleField) bool + CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool + CanUpdateRecordValueOnModuleField(context.Context, *types.ModuleField) bool } composeRecordAccessController interface { diff --git a/system/service/access_control.gen.go b/system/service/access_control.gen.go index d5fc40d1e..6978d8e3f 100644 --- a/system/service/access_control.gen.go +++ b/system/service/access_control.gen.go @@ -56,182 +56,182 @@ func (svc accessControl) List() (out []map[string]string) { def := []map[string]string{ { "type": types.ApigwRouteResourceType, - "any": types.ApigwRouteRbacResource(), + "any": types.ApigwRouteRbacResource(0), "op": "read", }, { "type": types.ApigwRouteResourceType, - "any": types.ApigwRouteRbacResource(), + "any": types.ApigwRouteRbacResource(0), "op": "update", }, { "type": types.ApigwRouteResourceType, - "any": types.ApigwRouteRbacResource(), + "any": types.ApigwRouteRbacResource(0), "op": "delete", }, { "type": types.ApplicationResourceType, - "any": types.ApplicationRbacResource(), + "any": types.ApplicationRbacResource(0), "op": "read", }, { "type": types.ApplicationResourceType, - "any": types.ApplicationRbacResource(), + "any": types.ApplicationRbacResource(0), "op": "update", }, { "type": types.ApplicationResourceType, - "any": types.ApplicationRbacResource(), + "any": types.ApplicationRbacResource(0), "op": "delete", }, { "type": types.AuthClientResourceType, - "any": types.AuthClientRbacResource(), + "any": types.AuthClientRbacResource(0), "op": "read", }, { "type": types.AuthClientResourceType, - "any": types.AuthClientRbacResource(), + "any": types.AuthClientRbacResource(0), "op": "update", }, { "type": types.AuthClientResourceType, - "any": types.AuthClientRbacResource(), + "any": types.AuthClientRbacResource(0), "op": "delete", }, { "type": types.AuthClientResourceType, - "any": types.AuthClientRbacResource(), + "any": types.AuthClientRbacResource(0), "op": "authorize", }, { "type": types.QueueResourceType, - "any": types.QueueRbacResource(), + "any": types.QueueRbacResource(0), "op": "render", }, { "type": types.QueueResourceType, - "any": types.QueueRbacResource(), + "any": types.QueueRbacResource(0), "op": "read", }, { "type": types.QueueResourceType, - "any": types.QueueRbacResource(), + "any": types.QueueRbacResource(0), "op": "update", }, { "type": types.QueueResourceType, - "any": types.QueueRbacResource(), + "any": types.QueueRbacResource(0), "op": "delete", }, { "type": types.QueueResourceType, - "any": types.QueueRbacResource(), + "any": types.QueueRbacResource(0), "op": "queue.read", }, { "type": types.QueueResourceType, - "any": types.QueueRbacResource(), + "any": types.QueueRbacResource(0), "op": "queue.write", }, { "type": types.ReportResourceType, - "any": types.ReportRbacResource(), + "any": types.ReportRbacResource(0), "op": "read", }, { "type": types.ReportResourceType, - "any": types.ReportRbacResource(), + "any": types.ReportRbacResource(0), "op": "update", }, { "type": types.ReportResourceType, - "any": types.ReportRbacResource(), + "any": types.ReportRbacResource(0), "op": "delete", }, { "type": types.ReportResourceType, - "any": types.ReportRbacResource(), + "any": types.ReportRbacResource(0), "op": "run", }, { "type": types.RoleResourceType, - "any": types.RoleRbacResource(), + "any": types.RoleRbacResource(0), "op": "read", }, { "type": types.RoleResourceType, - "any": types.RoleRbacResource(), + "any": types.RoleRbacResource(0), "op": "update", }, { "type": types.RoleResourceType, - "any": types.RoleRbacResource(), + "any": types.RoleRbacResource(0), "op": "delete", }, { "type": types.RoleResourceType, - "any": types.RoleRbacResource(), + "any": types.RoleRbacResource(0), "op": "members.manage", }, { "type": types.TemplateResourceType, - "any": types.TemplateRbacResource(), + "any": types.TemplateRbacResource(0), "op": "read", }, { "type": types.TemplateResourceType, - "any": types.TemplateRbacResource(), + "any": types.TemplateRbacResource(0), "op": "update", }, { "type": types.TemplateResourceType, - "any": types.TemplateRbacResource(), + "any": types.TemplateRbacResource(0), "op": "delete", }, { "type": types.TemplateResourceType, - "any": types.TemplateRbacResource(), + "any": types.TemplateRbacResource(0), "op": "render", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "read", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "update", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "delete", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "suspend", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "unsuspend", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "email.unmask", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "name.unmask", }, { "type": types.UserResourceType, - "any": types.UserRbacResource(), + "any": types.UserRbacResource(0), "op": "impersonate", }, { @@ -525,17 +525,17 @@ func (svc accessControl) CanDeleteQueue(ctx context.Context, r *types.Queue) boo return svc.can(ctx, "delete", r) } -// CanReadQueueQueue checks if current user can read from queue +// CanReadQueueOnQueue checks if current user can read from queue // // This function is auto-generated -func (svc accessControl) CanReadQueueQueue(ctx context.Context, r *types.Queue) bool { +func (svc accessControl) CanReadQueueOnQueue(ctx context.Context, r *types.Queue) bool { return svc.can(ctx, "queue.read", r) } -// CanWriteQueueQueue checks if current user can write to queue +// CanWriteQueueOnQueue checks if current user can write to queue // // This function is auto-generated -func (svc accessControl) CanWriteQueueQueue(ctx context.Context, r *types.Queue) bool { +func (svc accessControl) CanWriteQueueOnQueue(ctx context.Context, r *types.Queue) bool { return svc.can(ctx, "queue.write", r) } @@ -588,10 +588,10 @@ func (svc accessControl) CanDeleteRole(ctx context.Context, r *types.Role) bool return svc.can(ctx, "delete", r) } -// CanManageMembersRole checks if current user can manage members +// CanManageMembersOnRole checks if current user can manage members // // This function is auto-generated -func (svc accessControl) CanManageMembersRole(ctx context.Context, r *types.Role) bool { +func (svc accessControl) CanManageMembersOnRole(ctx context.Context, r *types.Role) bool { return svc.can(ctx, "members.manage", r) } @@ -658,17 +658,17 @@ func (svc accessControl) CanUnsuspendUser(ctx context.Context, r *types.User) bo return svc.can(ctx, "unsuspend", r) } -// CanUnmaskEmailUser checks if current user can unmask email +// CanUnmaskEmailOnUser checks if current user can unmask email // // This function is auto-generated -func (svc accessControl) CanUnmaskEmailUser(ctx context.Context, r *types.User) bool { +func (svc accessControl) CanUnmaskEmailOnUser(ctx context.Context, r *types.User) bool { return svc.can(ctx, "email.unmask", r) } -// CanUnmaskNameUser checks if current user can unmask name +// CanUnmaskNameOnUser checks if current user can unmask name // // This function is auto-generated -func (svc accessControl) CanUnmaskNameUser(ctx context.Context, r *types.User) bool { +func (svc accessControl) CanUnmaskNameOnUser(ctx context.Context, r *types.User) bool { return svc.can(ctx, "name.unmask", r) } @@ -1014,6 +1014,29 @@ func rbacApigwRouteResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.ApigwRouteResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for apigwRoute resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1035,6 +1058,29 @@ func rbacApplicationResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.ApplicationResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for application resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1056,6 +1102,29 @@ func rbacAuthClientResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.AuthClientResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for authClient resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1077,6 +1146,29 @@ func rbacQueueResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.QueueResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for queue resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1098,6 +1190,29 @@ func rbacReportResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.ReportResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for report resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1119,6 +1234,29 @@ func rbacRoleResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.RoleResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for role resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1140,6 +1278,29 @@ func rbacTemplateResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.TemplateResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for template resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } @@ -1161,6 +1322,29 @@ func rbacUserResourceValidator(r string, oo ...string) error { } } + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.UserResourceType):], sep), sep) + prc = []string{ + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for user resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } return nil } diff --git a/system/types/rbac.gen.go b/system/types/rbac.gen.go index ccb3413e5..e6a57df1e 100644 --- a/system/types/rbac.gen.go +++ b/system/types/rbac.gen.go @@ -41,21 +41,28 @@ const ( // // This function is auto-generated func (r ApigwRoute) RbacResource() string { - return ApigwRouteRbacResource() + return ApigwRouteRbacResource(r.ID) } // ApigwRouteRbacResource returns string representation of RBAC resource for ApigwRoute // -// RBAC resource is in the corteza::system:apigw-route/ format +// RBAC resource is in the corteza::system:apigw-route/... format // // This function is auto-generated -func ApigwRouteRbacResource() string { - return ApigwRouteResourceType + "/" +func ApigwRouteRbacResource(id uint64) string { + cpts := []interface{}{ApigwRouteResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(ApigwRouteRbacResourceTpl(), cpts...) } func ApigwRouteRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Application by calling ApplicationRbacResource fn @@ -64,21 +71,28 @@ func ApigwRouteRbacResourceTpl() string { // // This function is auto-generated func (r Application) RbacResource() string { - return ApplicationRbacResource() + return ApplicationRbacResource(r.ID) } // ApplicationRbacResource returns string representation of RBAC resource for Application // -// RBAC resource is in the corteza::system:application/ format +// RBAC resource is in the corteza::system:application/... format // // This function is auto-generated -func ApplicationRbacResource() string { - return ApplicationResourceType + "/" +func ApplicationRbacResource(id uint64) string { + cpts := []interface{}{ApplicationResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(ApplicationRbacResourceTpl(), cpts...) } func ApplicationRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for AuthClient by calling AuthClientRbacResource fn @@ -87,21 +101,28 @@ func ApplicationRbacResourceTpl() string { // // This function is auto-generated func (r AuthClient) RbacResource() string { - return AuthClientRbacResource() + return AuthClientRbacResource(r.ID) } // AuthClientRbacResource returns string representation of RBAC resource for AuthClient // -// RBAC resource is in the corteza::system:auth-client/ format +// RBAC resource is in the corteza::system:auth-client/... format // // This function is auto-generated -func AuthClientRbacResource() string { - return AuthClientResourceType + "/" +func AuthClientRbacResource(id uint64) string { + cpts := []interface{}{AuthClientResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(AuthClientRbacResourceTpl(), cpts...) } func AuthClientRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Queue by calling QueueRbacResource fn @@ -110,21 +131,28 @@ func AuthClientRbacResourceTpl() string { // // This function is auto-generated func (r Queue) RbacResource() string { - return QueueRbacResource() + return QueueRbacResource(r.ID) } // QueueRbacResource returns string representation of RBAC resource for Queue // -// RBAC resource is in the corteza::system:queue/ format +// RBAC resource is in the corteza::system:queue/... format // // This function is auto-generated -func QueueRbacResource() string { - return QueueResourceType + "/" +func QueueRbacResource(id uint64) string { + cpts := []interface{}{QueueResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(QueueRbacResourceTpl(), cpts...) } func QueueRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Report by calling ReportRbacResource fn @@ -133,21 +161,28 @@ func QueueRbacResourceTpl() string { // // This function is auto-generated func (r Report) RbacResource() string { - return ReportRbacResource() + return ReportRbacResource(r.ID) } // ReportRbacResource returns string representation of RBAC resource for Report // -// RBAC resource is in the corteza::system:report/ format +// RBAC resource is in the corteza::system:report/... format // // This function is auto-generated -func ReportRbacResource() string { - return ReportResourceType + "/" +func ReportRbacResource(id uint64) string { + cpts := []interface{}{ReportResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(ReportRbacResourceTpl(), cpts...) } func ReportRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Role by calling RoleRbacResource fn @@ -156,21 +191,28 @@ func ReportRbacResourceTpl() string { // // This function is auto-generated func (r Role) RbacResource() string { - return RoleRbacResource() + return RoleRbacResource(r.ID) } // RoleRbacResource returns string representation of RBAC resource for Role // -// RBAC resource is in the corteza::system:role/ format +// RBAC resource is in the corteza::system:role/... format // // This function is auto-generated -func RoleRbacResource() string { - return RoleResourceType + "/" +func RoleRbacResource(id uint64) string { + cpts := []interface{}{RoleResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(RoleRbacResourceTpl(), cpts...) } func RoleRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Template by calling TemplateRbacResource fn @@ -179,21 +221,28 @@ func RoleRbacResourceTpl() string { // // This function is auto-generated func (r Template) RbacResource() string { - return TemplateRbacResource() + return TemplateRbacResource(r.ID) } // TemplateRbacResource returns string representation of RBAC resource for Template // -// RBAC resource is in the corteza::system:template/ format +// RBAC resource is in the corteza::system:template/... format // // This function is auto-generated -func TemplateRbacResource() string { - return TemplateResourceType + "/" +func TemplateRbacResource(id uint64) string { + cpts := []interface{}{TemplateResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(TemplateRbacResourceTpl(), cpts...) } func TemplateRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for User by calling UserRbacResource fn @@ -202,21 +251,28 @@ func TemplateRbacResourceTpl() string { // // This function is auto-generated func (r User) RbacResource() string { - return UserRbacResource() + return UserRbacResource(r.ID) } // UserRbacResource returns string representation of RBAC resource for User // -// RBAC resource is in the corteza::system:user/ format +// RBAC resource is in the corteza::system:user/... format // // This function is auto-generated -func UserRbacResource() string { - return UserResourceType + "/" +func UserRbacResource(id uint64) string { + cpts := []interface{}{UserResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(UserRbacResourceTpl(), cpts...) } func UserRbacResourceTpl() string { - return "%s" + return "%s/%s" } // RbacResource returns string representation of RBAC resource for Component by calling ComponentRbacResource fn