Rôles et permissions
Un rôle dans Liberty est un nom + une liste de chaînes de permissions. Les utilisateurs reçoivent des rôles ; les rôles accordent ou refusent ce que les utilisateurs peuvent faire.
L'onglet Paramètres → Accès → Rôles est l'endroit où les construire. La page cache chaque détail des chaînes de permissions derrière un PermissionPicker — on ne tape pas sql:crm:customers_get ; on sélectionne Requête → customers → customers_get dans des listes déroulantes et le picker génère la chaîne.
L'onglet Rôles
Chaque carte montre l'identifiant du rôle, sa description et un décompte des règles d'autorisation / de refus (ou une pastille Accès complet quand la baseline est * sans restriction supplémentaire).
L'éditeur de rôle
Cliquer sur une ligne de rôle pour ouvrir l'éditeur. Il comporte trois parties :
| Section | Notes |
|---|---|
| Nom du rôle | En lecture seule après création. Renommer demande de supprimer et de recréer avec le nouveau nom (pas de renommage transversal pour les rôles — les références chez les utilisateurs se mettent à jour automatiquement puisque les utilisateurs portent les noms de rôles, pas les identifiants). |
| Description | Texte libre. Affichée sur la carte. |
| Permissions | Le PermissionPicker — baseline + règles d'autorisation / de refus. |
Le PermissionPicker — anatomie
La baseline
Deux boutons, mutuellement exclusifs :
| Baseline | Liste des permissions | Sémantique |
|---|---|---|
| Aucun accès | démarre vide | Rien n'est autorisé en dehors de ce qui est ajouté via des règles Autoriser. Le bon défaut pour les rôles moindre privilège. |
| Accès complet | démarre avec ["*"] | Tout est autorisé en dehors de ce qui est retiré via des règles Refuser. Le bon défaut pour les rôles proches du superutilisateur. |
L'indication sous l'interrupteur lit soit « rien, plus les autorisations ci-dessous » soit « tout, moins les refus ci-dessous » selon le choix.
La liste de règles
Chaque règle est une pastille colorée :
| Couleur de pastille | Signification |
|---|---|
| Vert | Une règle d'autorisation — sql:crm:customers_get, menu:crm:pipeline. |
| Rouge | Une règle de refus — les mêmes formes mais préfixées ! en stockage (!sql:crm:customers_delete). |
Le ✕ de chaque pastille supprime la règle. La liste en haut du Picker est triée par ordre d'ajout.
Ajouter une règle
Trois contrôles sous les pastilles :
| Contrôle | Ce qu'il fait |
|---|---|
| Effet (Autoriser / Refuser) | Interrupteur deux boutons. Autoriser ajoute la pastille sans préfixe ! ; Refuser l'ajoute avec !. |
| Type | Liste déroulante — Menu / Tableau de bord / Connecteur (toutes les requêtes) / Requête / Endpoint API / Assistant IA. Pilote les éléments disponibles dans la liste suivante. |
| Élément | Une recherche-sélection alimentée selon le Type. Pour Menu il liste chaque élément de menu de chaque application ; pour Connecteur il liste les connecteurs SQL ; pour Requête il liste chaque requête nommée ; pour Tableau de bord il liste chaque identifiant de tableau de bord ; pour Endpoint API il liste les endpoints de chaque connecteur API ; pour Assistant IA il y a une entrée unique. |
| + Ajouter | Résout l'élément choisi en un ou plusieurs motifs de permissions, préfixe ! si Refuser, ajoute à la liste de règles. |
Le picker prend en charge la composition des motifs afin d'éviter d'avoir à se rappeler la syntaxe sql:<c>:<q>. On raisonne en termes d'« autoriser ce menu » ou de « refuser cette requête » ; le stockage ressemble à menu:crm:reports ou !sql:crm:customers_delete.
Les règles de menu ont une expansion particulière
Quand on autorise une règle Menu, le picker l'étend en plusieurs motifs de permissions :
menu:<app>:<id>— pour que l'élément de menu apparaisse dans la navigation.menu:<app>:<descendant_id>— pour chaque feuille descendante (afin que les sous-menus apparaissent).sql:<connector>:<target>ouapi:<connector>:<target>— pour la requête / le endpoint sous-jacent de chaque feuille descendante, afin que les écrans / endpoints fonctionnent réellement.
Une règle Autoriser → Menu → Pipeline accorde donc à l'utilisateur tout le dossier Pipeline et chaque écran qu'il contient, d'un seul geste. La même expansion s'applique sur Refuser — refuser Menu → Admin cache le dossier et refuse chaque écran qu'il contient.
Sans cette expansion, il faudrait ajouter une autorisation pour le menu et une autorisation séparée pour chaque requête sous-jacente — une corvée manuelle source d'erreurs. Le picker s'en charge.
Ordre de résolution
Quand le framework vérifie une permission, il parcourt cet ordre :
- Vérification superutilisateur — si l'utilisateur a
is_superuser = true, tout est autorisé (règles de refus ignorées). - Refus explicite — si un
!<motif>parmi les permissions cumulées des rôles de l'utilisateur correspond, rejet. - Autorisation explicite — si un motif non préfixé
!correspond, autorisation. - Refus par défaut — sinon, rejet.
L'ordre compte. Une liste de permissions ["*", "!sql:crm:customers_delete"] :
sql:crm:customers_get→ correspond à*(autorisation), aucun refus ne correspond → autorisé.sql:crm:customers_delete→ correspond à*(autorisation) et correspond à!sql:crm:customers_delete(refus) → le refus l'emporte → rejeté.sql:reporting:*→ correspond à*(autorisation), aucun refus ne correspond → autorisé.
Syntaxe des motifs — la grammaire complète
Les chaînes de permissions utilisent des globs segmentés par deux-points :
| Opérateur | Signification | Exemple |
|---|---|---|
<mot> | Segment littéral. | sql, crm, customers_get. |
* (segment unique) | Correspond à un segment. | sql:*:customers_get correspond à sql:crm:customers_get et sql:reporting:customers_get. |
* (en fin) | Correspond au reste. | sql:crm:* correspond à tout sql:crm:<n'importe quoi>. |
!<motif> | Refus. | !sql:crm:customers_delete. |
* (seul) | Caractère générique pour tout. | La baseline Accès complet. |
!* | Refuser tout. | Rare ; en pratique un coupe-circuit. |
Les surfaces complètes :
| Motif | Accorde |
|---|---|
sql:<connector>:<query> | Exécuter une requête SQL. |
sql:<connector>:* | Exécuter toutes les requêtes SQL sur un connecteur. |
sql:* | Exécuter toutes les requêtes SQL partout. |
api:<connector>:<endpoint> | Appeler un endpoint API. |
api:<connector>:* | Appeler chaque endpoint sur un connecteur. |
menu:<app>:<id> | Voir un élément de menu (dossier ou feuille). |
menu:<app>:* | Voir chaque élément de menu d'une application. |
dashboard:<id> | Ouvrir un tableau de bord. |
ai:chat | Utiliser l'assistant IA. |
* | Tout. |
Recettes de rôles standard
| Rôle | Baseline | Règles |
|---|---|---|
| Superutilisateur | Accès complet | (vide) — équivalent à activer is_superuser sur l'utilisateur. |
| Lecteur sur l'application CRM | Aucun accès | Autoriser → Menu → CRM (qui s'étend en menu:crm:* + sql:crm:* pour les requêtes de lecture). |
| Utilisateur avancé CRM sauf suppression | Accès complet | Refuser → Requête → customers_delete, deals_delete, activities_delete. |
| Accès IA uniquement | Aucun accès | Autoriser → Assistant IA. L'utilisateur se connecte et obtient la surface de chat IA mais ni menu ni écrans. |
| Responsable des rapports | Aucun accès | Autoriser → Menu → Reports + Autoriser → Tableau de bord → revenue_overview / pipeline_health / etc. |
| Admin sans l'IA | Accès complet | Refuser → Assistant IA. Tout le reste autorisé. |
Le Permissions Picker traite chaque cas via la même cascade Autoriser / Refuser / Type / Élément.
Comment se composent les permissions effectives d'un utilisateur
Un utilisateur peut avoir plusieurs rôles. Le framework concatène les listes de permissions de chaque rôle — le refus l'emporte aussi entre rôles.
Exemple : Alice a à la fois analyst et reporter :
analyst.permissions = ["*", "!sql:crm:customers_delete"]reporter.permissions = ["sql:reporting:*", "menu:reporting:*"]
Les permissions effectives d'Alice :
sql:crm:customers_get→ autorisé par*dans analyst.sql:crm:customers_delete→ refusé par le!sql:crm:customers_deleted'analystmême si*l'autoriserait.sql:reporting:monthly_revenue→ autorisé à la fois par*(analyst) et parsql:reporting:*(reporter) — redondant mais sans conséquence.
Aucun rôle ne peut « passer outre » le refus d'un autre rôle — le refus est définitif sur l'ensemble des rôles de l'utilisateur.
Pièges courants
| Erreur | Symptôme | Correction |
|---|---|---|
| Autoriser un Menu sans réaliser qu'il accorde les requêtes sous-jacentes. | Un utilisateur a plus d'accès SQL qu'attendu. | Utiliser Autoriser → Requête pour un contrôle fin ; réserver Autoriser → Menu pour « accorder toute la section ». |
| Baseline Accès complet + quelques règles d'autorisation. | Les autorisations sont redondantes (la baseline les accorde déjà). | Choisir soit Accès complet (et refuser les exceptions), soit Aucun accès (et autoriser les spécificités). Pas les deux. |
!sql:crm:* en pensant qu'il passera outre une autorisation héritée. | Le refus fonctionne — mais l'utilisateur n'a aucun accès SQL sur crm même quand d'autres rôles l'accordent. | Les refus sont absolus. À utiliser délibérément. |
| Renommer un rôle en modifiant le nom. | Le nom est en lecture seule après création. | Supprimer le rôle et le recréer avec le nouveau nom. Réattribuer les utilisateurs. |
| Oublier que les changements de JWT sont décalés. | Un utilisateur reçoit un nouveau rôle mais ne le voit pas pendant une heure. | L'utilisateur se déconnecte puis se reconnecte, ou attend le TTL du jeton d'accès. |
Suite
- Utilisateurs — attribuer les rôles aux utilisateurs.
- Se connecter — comment les utilisateurs obtiennent leurs JWT.
- Secrets chiffrés — couche indépendante ; orthogonale au RBAC.