engine icon indicating copy to clipboard operation
engine copied to clipboard

RFC: entity access only through relations

Open matej21 opened this issue 1 year ago • 2 comments

Introduction

This RFC proposes enhancements to the Access Control List (ACL) system in Contember. The focus is on introducing a more nuanced control mechanism for non-root entities, like Image, allowing them to be accessible only through relations, and not by direct querying. This document outlines the proposed syntax and the logic for evaluating these rules.

Proposed Syntax

1. Explicit through Relation

Entities can have ACL rules that specify explicit relations through which they can be accessed:

@c.allow(publicRole, {
    read: ['url'],
    when: { deletedAt: { isNull: true } },
    through: ['articleCoverImage', 'userAvatar']
})
export class Image {
    // ...
    url = c.stringColumn().notNull()
    articleCoverImage = c.oneHasOneInverse(Article, 'coverImage')
    userAvatar = c.oneHasOneInverse(User, 'avatar')
}
  • through: Specifies an array of relation names through which the entity can be accessed. These relation names are defined on the side of the entity being accessed, usually on the inverse side of the relationship. This means that the specified relations in through should correspond to relation properties within the entity class.

2. Wildcard through Relation

A wildcard (*) can be used to denote that the entity is accessible through any relation, but not directly:

@c.allow(publicRole, {
    read: ['url'],
    when: { deletedAt: { isNull: true } },
    through: '*'
})
export class Image {
    // ...
}
  • through: '*': Indicates that access is allowed through any relation. In the context of this wildcard rule, it is not necessary for the inverse side of the relation to be explicitly present on the accessed entity. This provides flexibility in scenarios where the exact relations may not be directly defined or are numerous, making explicit enumeration impractical.

3. General allow Rules without through

For direct access without relation-based restrictions:

@c.allow(publicRole, {
    read: ['url'],
    when: {deletedAt: {isNull: true}},
})
export class Image {
    // ...
}
  • This is the standard rule for direct access. Also, it is the default rule if no other rules are defined.

Rule Evaluation Logic

Priority Order

  1. First Priority: Rules with explicit, named through relations.
  2. Second Priority: Rules with a wildcard through (*).
  3. Third Priority: General allow rules without through.

Rule Merging

  • Within each priority level, if multiple rules are defined, they are merged using an "OR" logic. Access is granted if any one of the rules within the same priority level is satisfied.

matej21 avatar Jan 08 '24 13:01 matej21

Perhaps we could use the same API for through as we do for CRUD, replacing the wildcard * with true.

2. Wildcard through Relation

@c.allow(publicRole, {
    read: ['url'],
    when: { deletedAt: { isNull: true } },
    through: true
})
export class Image {
    // ...
}

jonasnobile avatar Jan 08 '24 14:01 jonasnobile

I don't like the word through. I think it makes sense only when you understand deeply what it does. Don't have a better alternative handy though.

honzasladek avatar Jan 08 '24 14:01 honzasladek