Implement ownership access-control on record creation
Besides "owner.manage" on record resoure we now also have "owned-record.create" on module.
This commit is contained in:
@@ -45,6 +45,7 @@ module: schema.#Resource & {
|
||||
"update": {}
|
||||
"delete": {}
|
||||
"record.create": description: "Create record"
|
||||
"owned-record.create": description: "Create record with custom owner"
|
||||
"records.search": description: "List, search or filter records"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,11 @@ type (
|
||||
|
||||
Fields []*moduleFieldPayload `json:"fields"`
|
||||
|
||||
CanGrant bool `json:"canGrant"`
|
||||
CanUpdateModule bool `json:"canUpdateModule"`
|
||||
CanDeleteModule bool `json:"canDeleteModule"`
|
||||
CanCreateRecord bool `json:"canCreateRecord"`
|
||||
CanGrant bool `json:"canGrant"`
|
||||
CanUpdateModule bool `json:"canUpdateModule"`
|
||||
CanDeleteModule bool `json:"canDeleteModule"`
|
||||
CanCreateRecord bool `json:"canCreateRecord"`
|
||||
CanCreateOwnedRecord bool `json:"canCreateOwnedRecord"`
|
||||
}
|
||||
|
||||
moduleFieldPayload struct {
|
||||
@@ -49,6 +50,7 @@ type (
|
||||
CanUpdateModule(context.Context, *types.Module) bool
|
||||
CanDeleteModule(context.Context, *types.Module) bool
|
||||
CanCreateRecordOnModule(context.Context, *types.Module) bool
|
||||
CanCreateOwnedRecordOnModule(context.Context, *types.Module) bool
|
||||
CanReadRecord(context.Context, *types.Record) bool
|
||||
|
||||
CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool
|
||||
@@ -189,7 +191,9 @@ func (ctrl Module) makePayload(ctx context.Context, m *types.Module, err error)
|
||||
|
||||
CanUpdateModule: ctrl.ac.CanUpdateModule(ctx, m),
|
||||
CanDeleteModule: ctrl.ac.CanDeleteModule(ctx, m),
|
||||
CanCreateRecord: ctrl.ac.CanCreateRecordOnModule(ctx, m),
|
||||
|
||||
CanCreateRecord: ctrl.ac.CanCreateRecordOnModule(ctx, m),
|
||||
CanCreateOwnedRecord: ctrl.ac.CanCreateOwnedRecordOnModule(ctx, m),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
23
compose/service/access_control.gen.go
generated
23
compose/service/access_control.gen.go
generated
@@ -174,6 +174,11 @@ func (svc accessControl) List() (out []map[string]string) {
|
||||
"any": types.ModuleRbacResource(0, 0),
|
||||
"op": "record.create",
|
||||
},
|
||||
{
|
||||
"type": types.ModuleResourceType,
|
||||
"any": types.ModuleRbacResource(0, 0),
|
||||
"op": "owned-record.create",
|
||||
},
|
||||
{
|
||||
"type": types.ModuleResourceType,
|
||||
"any": types.ModuleRbacResource(0, 0),
|
||||
@@ -426,6 +431,13 @@ func (svc accessControl) CanCreateRecordOnModule(ctx context.Context, r *types.M
|
||||
return svc.can(ctx, "record.create", r)
|
||||
}
|
||||
|
||||
// CanCreateOwnedRecordOnModule checks if current user can create record with custom owner
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (svc accessControl) CanCreateOwnedRecordOnModule(ctx context.Context, r *types.Module) bool {
|
||||
return svc.can(ctx, "owned-record.create", r)
|
||||
}
|
||||
|
||||
// CanSearchRecordsOnModule checks if current user can list, search or filter records
|
||||
//
|
||||
// This function is auto-generated
|
||||
@@ -651,11 +663,12 @@ func rbacResourceOperations(r string) map[string]bool {
|
||||
}
|
||||
case types.ModuleResourceType:
|
||||
return map[string]bool{
|
||||
"read": true,
|
||||
"update": true,
|
||||
"delete": true,
|
||||
"record.create": true,
|
||||
"records.search": true,
|
||||
"read": true,
|
||||
"update": true,
|
||||
"delete": true,
|
||||
"record.create": true,
|
||||
"owned-record.create": true,
|
||||
"records.search": true,
|
||||
}
|
||||
case types.ModuleFieldResourceType:
|
||||
return map[string]bool{
|
||||
|
||||
@@ -72,6 +72,7 @@ type (
|
||||
|
||||
recordManageOwnerAccessController interface {
|
||||
CanManageOwnerOnRecord(context.Context, *types.Record) bool
|
||||
CanCreateOwnedRecordOnModule(context.Context, *types.Module) bool
|
||||
}
|
||||
|
||||
recordAccessController interface {
|
||||
@@ -661,10 +662,15 @@ func SetRecordOwner(ctx context.Context, ac recordManageOwnerAccessController, s
|
||||
}
|
||||
)
|
||||
|
||||
if (old != nil && curOwner != updOwner) || (old == nil && updOwner != invoker) {
|
||||
// check if ownership can be changed when:
|
||||
// a) updating (old != nil) and ownership changed
|
||||
// b) creating (old == nil) and ownership id not set to the invoking user
|
||||
if old == nil && updOwner != invoker {
|
||||
// Can be set on new records
|
||||
if !ac.CanCreateOwnedRecordOnModule(ctx, upd.GetModule()) {
|
||||
return mkError("accessDenied", "record.errors.ownershipChangeDenied")
|
||||
}
|
||||
}
|
||||
|
||||
if old != nil && curOwner != updOwner {
|
||||
// Can ownership be changed on existing record?
|
||||
if !ac.CanManageOwnerOnRecord(ctx, upd) {
|
||||
return mkError("accessDenied", "record.errors.ownershipChangeDenied")
|
||||
}
|
||||
@@ -929,19 +935,6 @@ func (svc record) procCreate(ctx context.Context, invokerID uint64, m *types.Mod
|
||||
new.DeletedAt = nil
|
||||
new.DeletedBy = 0
|
||||
|
||||
if new.OwnedBy == 0 {
|
||||
new.OwnedBy = invokerID
|
||||
}
|
||||
|
||||
if new.OwnedBy != invokerID {
|
||||
// we're creating record here and this check goes against current
|
||||
// RBAC implementation logic on record creation
|
||||
if !svc.ac.CanManageOwnerOnRecord(ctx, new) {
|
||||
// not permitted to change the owner
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if err := SetRecordOwner(ctx, svc.ac, svc.store, nil, new, invokerID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user