Aller au contenu

6. Les droits

Trois niveaux, du plus large au plus fin. Les trois s’appliquent dans la couche d’accès aux données, jamais dans l’écran ni dans l’API : un point d’entrée oublié ne peut pas ouvrir une brèche, et un utilisateur qui appelle l’API directement obtient exactement ce que l’interface lui montrerait.

Niveau 1 : qui peut toucher au modèle

acl.json, à la racine du module.

{
"library_title": {
"read": ["library_reader", "library_librarian", "kws_admin"],
"create": ["library_librarian", "kws_admin"],
"write": ["library_librarian", "kws_admin"],
"unlink": ["library_librarian", "kws_admin"]
},
"library_member": {
"read": ["library_librarian", "kws_admin"],
"create": ["library_librarian", "kws_admin"],
"write": ["library_librarian", "kws_admin"],
"unlink": ["kws_admin"]
}
}

Notez la deuxième entrée : un lecteur ne voit pas la liste des adhérents. Ce n’est pas un écran caché, c’est un droit absent, et l’API le refuse aussi.

Quatre verbes : lire, créer, modifier, supprimer. Un groupe absent d’une liste n’a pas le droit.

Niveau 2 : quelles lignes

Une règle d’enregistrement filtre les lignes visibles, par groupe.

from kewos.security import RecordRule
from kewos.auth.context import current_user_id
def _own_loans(cls):
"""A reader sees the loans they took out, and no one else's."""
return cls.created_by_id == current_user_id()
_LOAN_RULES = (
RecordRule(
name="library_loan_own",
domain=_own_loans,
groups=("library_reader",),
),
)

Puis on l’attache au modèle :

registry.register_model(
"library_loan",
module="library",
fields=[...],
record_rules=_LOAN_RULES,
)

Deux propriétés à connaître, et elles surprennent :

  • Une règle ne s’applique qu’aux porteurs de ses groupes. Un utilisateur sans le groupe visé n’est pas filtré par cette règle.
  • Plusieurs règles applicables se combinent par ET. Un utilisateur qui porte deux groupes visés par deux règles voit l’intersection. C’est volontairement restrictif : le résultat d’une erreur est qu’on voit moins, jamais plus.

Si vous voulez qu’une condition élargisse la visibilité, mettez-la dans un OU à l’intérieur d’une seule règle, jamais dans une seconde règle.

Niveau 3 : quels champs

Une règle de champ cache ou verrouille une colonne.

from kewos.security import FieldRule
_MEMBER_FIELD_RULES = (
FieldRule(field="email", read=("library_librarian", "kws_admin"),
write=("library_librarian", "kws_admin")),
)

Attachée de la même façon, par field_rules=.

Un utilisateur sans le droit de lecture ne reçoit pas la colonne, ni dans l’API ni dans l’écran. Il ne la voit pas grisée : elle n’existe pas pour lui.

Déclarer les groupes

Les groupes de votre module doivent exister. Déclarez-les avec leurs libellés, et donnez-leur une clé de traduction group.<nom>.

Un utilisateur reçoit ses groupes dans Paramètres → Utilisateurs. En développement :

Fenêtre de terminal
kewos access grant --user <login> --group library_librarian --database-url "$KEWOS_DATABASE_URL"

Les trois niveaux, en KM

Les mêmes trois niveaux, dans le fichier du module :

group library_reader "group.library_reader"
group library_librarian "group.library_librarian"
# Niveau 1 : qui peut toucher au modèle.
access library_title {
library_reader read
library_librarian read, create, write, unlink
kws_admin read, create, write, unlink
}
# Niveau 3 : quels champs. Le champ reste, sa valeur est masquée.
restrict library_loan.note read library_librarian write library_librarian
# Niveau 2 : quelles lignes. La condition est celle du langage d'expressions.
rule library_loan for library_reader where member_id.name == user.name

Quatre mots-clés pour quatre choses que le noyau garde volontairement séparées : une identité, un droit sur un modèle, un champ masqué, une ligne filtrée. Les confondre, c’est le moment où un modèle de sécurité se met à mentir.

Vérifier

Le seul test qui vaut est celui-ci : connectez-vous avec un compte qui ne porte que library_reader et regardez. Un administrateur voit toujours tout, donc tester en administrateur ne prouve rien.

Et ensuite

Les états.