[Tutoriel] Permissions avancées (ACL) avec plusieurs profils utilisateurs

Préambule

Dans le cadre de projet touchant des publics variés, la gestion des droits d’accès est souvent un défi. Lorsqu’un tableau doit être consulté par plusieurs utilisateurs aux profils différents, avec des périmètres différents, les règles de filtrages basique ne suffisent plus. De plus, il est encore plus nécessaire dans ce cas d’être rigoureux dans la définition de la politique d’habilitation (i.e. qui voit quoi, et avec quels autorisations ?)

Ce tutoriel détaille la mise en place d’un contrôle d’accès granulaire (ACL) basé sur deux profils utilisateurs, mais on peut facilement l’étendre à autant de profils souhaités.

En prérequis, je vous invite à consulter l’excellent guide de @ailepet avant de lire celui-ci.


Présentation du cas d’étude

Imaginons la mise en place d’une diffusion sélective d’information sur deux populations aux périmètres distincts. Précisons, que dans ce guide on ferra un filtrage par ligne, mais il est possible de le faire également par colonne.

  • PROFIL « Responsable d’agence » affecté à une ou plusieurs agences. Il doit pouvoir accéder uniquement en lecture et écriture aux données qui correspondent aux agences de son périmètre.
  • PROFIL « Directeur régional » affecté à une ou plusieurs régions. Chaque région regroupe un ensemble d’agences locales. Le directeur régional accède en lecture aux lignes des agences de ses régions. Pour connaitre le périmètre des agences d’un directeur régional, il faut donc déterminer en premier à quel région il est affecté, puis listé les agences dans ses régions.

Création de tables utilisateurs par profil

Pour simplifier la gestion de plusieurs profils, on va créer une table par popultion.

La table SYSTEM_AUTORIZATION_RESPONSABLE_AGENCE contient la liste des directeurs de chaque agence, et leur périmètre (i.e. dans quel agence ils sont affectés). Remarquons qu’il est possible de construire une autre table AGENCES qui contient la liste des agences avec le code, le nom, le code région associé.

EMAIL PROFIL PERIMETRE_AGENCES
jean.dupont@entreprise.fr RESPONSABLE_AGENCE ['codeAgence1']
marie.curie@entreprise.fr RESPONSABLE_AGENCE ['codeAgence2']
paul.verlaine@entreprise.fr RESPONSABLE_AGENCE ['codeAgence3', 'codeAgence4']

On fait de même pour la population des directeurs régionales dans une autre table SYSTEM_AUTORIZATION_DIRECTEUR_REGIONAL. Cette table contient la liste des directeurs de région et leur affectation de région. A partir de cette affectation de région, on peut en déduire le périmètre des agences associés (on verra plus bas comment automatiser cette association).

EMAIL PROFIL PERIMETRE_REGIONS PERIMETRE_AGENCES
sophie.martin@entreprise.fr DIRECTEUR_REGION ['codeRegion1'] ['codeAgence1', 'codeAgence2', 'codeAgence3']
luc.bernard@entreprise.fr DIRECTEUR_REGION ['codeRegion1', 'codeRegion2'] ['codeAgence1', 'codeAgence2', 'codeAgence3', 'codeAgence4']
elodie.faure@entreprise.fr DIRECTEUR_REGION ['codeRegion2'] ['codeAgence3', 'codeAgence4']

Appairage des propriétés pour les ACL

Dans la vue des permissions avancées, on commence par définir les appairages suivant par profil. Remarquez que l’on définit les propriétés d’appairage par profil à l’aide des deux tables précédemment créées.

NAME PROPRIÉTÉ D’APPAIRAGE TABLE D’APPAIRAGE COLONNE_CIBLE
Team_RESPONSABLE_AGENCE user.Email SYSTEM_AUTORIZATION_RESPONSABLE_AGENCE EMAIL
Team_DIRECTEUR_REGION user.Email SYSTEM_AUTORIZATION_DIRECTEUR_REGIONAL EMAIL

Exemples de règles ACL pour une table accessible à multi-profils

Prenons l’exemple de la table de données opérationnelle DATA_VENTES ci-dessous, pour laquelle on souhaite que

  • les responsables d’agence ne voient que les lignes de leurs agences
  • les directeurs de région ne voient que les lignes des agences qui appartiennent à leur région.
ID_VENTE CODE_AGENCE DATE_VENTE PRODUIT MONTANT_HT
V001 codeAgence1 2026-06-01 Licence Logiciel Pro 1200.00
V002 codeAgence2 2026-06-02 Maintenance Annuelle 450.00
V003 codeAgence3 2026-06-03 Pack Formation 2500.00
V004 codeAgence4 2026-06-04 Licence Logiciel Pro 1200.00
V005 codeAgence5 2026-06-05 Support Avancé 800.00

Pour filtrer l’affichage des ventes, selon la politique d’habilitation décrit plus haut, voila les règles ACL à créer.

Règle Droits Explication
user.Access in [OWNER] RUCD Accès en administration total pour les propriétaires du document.
user.Team_RESPONSABLE_AGENCE.PROFIL == 'RESPONSABLE_AGENCE' and rec.CODE_AGENCE in user.Team_RESPONSABLE_AGENCE.PERIMETRE_AGENCES Rxxx Lecture seule des ventes rattachées aux agences du responsable local.
user.Team_DIRECTEUR_REGION.PROFIL == 'DIRECTEUR_REGION' and rec.CODE_AGENCE in user.Team_DIRECTEUR_REGION.PERIMETRE_AGENCES Rxxx Lecture seule des ventes de toutes les agences rattachées aux régions du responsable régional.
Tous les autres xxxx Bloque l’accès dans tous les autres cas (stratégie deny by default)

Remarques

  • La stratégie deny by default fonctionne par liste blanche (whitelisting). L’accès est strictement interdit par défaut, et seules les exceptions explicitement listées viennent l’autoriser.
  • Pour que l’opérateur in utile dans le cas d’affectation multiple (ex: codeAgence1, codeAgence2), la colonne PERIMETRE_AGENCES utilisés dans les tables utilisateurs doivent être stockée sous forme de chaîne de caractères (i.e. pour des developpeurs Java c’ets comme un ToString d’une collection d’item = une serialisation string = transformation en chaîne de caractères).

Exemples de règles ACL pour une table accessible à un seul profil

Si vous disposez d’une autre table contenant des indicateurs consolidés à l’échelle de la région , par exemple une table DATA_RENTABILITE_REGIONS avec une colonne CODE_REGION, il suffit d’appliquer ces règles ACL.

Règle Droits Explication
user.Access in [OWNER] RUCD Accès administrateur total au propriétaire du document.
user.Team_DIRECTEUR_REGION.PROFIL == 'DIRECTEUR_REGION' and rec.CODE_REGION in user.Team_DIRECTEUR_REGION.PERIMETRE_REGIONS Rxxx Lecture seule restreinte aux lignes de la table macro correspondant aux régions affectées au responsable.
Tous les autres xxxx Bloque l’accès dans tous les autres cas (stratégie deny by default)

Remarque

Attention, on pourrait penser que le test boolean par profil dans l’ACL (user.Team_DIRECTEUR_REGION.PROFIL == 'DIRECTEUR_REGION') n’est pas nécessaire et que seule la condition sur les données (rec.CODE_REGION in user.Team_DIRECTEUR_REGION.PERIMETRE_REGIONS) suffit. C’est une erreur !

Si vous supprimez ce test boolean de profil, les utilisateurs n’ayant pas ce rôle verront tout de même la table s’afficher dans leur menu latéral gauche sous Grist. Même si la table apparaîtra vide à l’intérieur, cela nuit à la clarté de l’interface. Il est préférable que le responsable d’agence n’ai pas connaissance de la table DATA_RENTABILITE_REGIONS. L’ajout du test strict sur le profil au début de la règle permet de masquer complètement l’accès à la table pour les profils non concernés.


Simplifier la gestion des périmètres

Pour s’affranchir d’une saisie manuelle des codes des agences dans la table des responsables régionaux, il est possible d’automatiser la jointure à partir d’une table de référence REGIONS_AGENCES qui structure ce rattachement hiérarchique. Evidement, vous pouvez ajouter deux autres tables AGENCES et REGIONS pour décrire avec d’autres colonnes ces entités… mais ce n’est pas le propos ici des jointures de références multiples dans Grist.

Faisons plus simple avec cette table qui modélise l’affectation des agences dans chaque région.

CODE_REGION CODE_AGENCE
codeRegion1 codeAgence1
codeRegion1 codeAgence2
codeRegion1 codeAgence3
codeRegion2 codeAgence4
codeRegion2 codeAgence5

On modifie alors dans la table SYSTEM_AUTORIZATION_DIRECTEUR_REGIONAL de la manière suivante

  1. Ajout de la colonne REGIONS_AFFECTEES de type référence multiple pointant vers la table de correspondance des régions REGIONS_AGENCES.

  2. Ajout de la colonne AGENCES_AFFECTEES, qui va servir à agréger les agences de chaque région présente dans la colonne REGIONS_AFFECTEES. Pour ce faire, on utilise la fonction lookupRecords en python pour rechercher les agences.

     resultats = []
    
     for region in $REGIONS_AFFECTEES:
         agences = REGIONS_AGENCES.lookupRecords(CODE_REGION=region.CODE_REGION)
     resultats.extend(agences)
    
     return resultats`
    

    Ainsi, chaque fois qu’on ajoute une région dans la colonne REGIONS_AFFECTEES, le système calcul et met à jour automatiquement le contenu de la colonne AGENCES_AFFECTEES !

  3. En guise de contrôle, on peut ajouter une formule pour compter le nombre d’agences affectés à un directeur régional avec la formule suivante.

    return len($AGENCES_AFFECTEES ) if $AGENCES_AFFECTEES else 0
    
  4. Comme dit précédemment, pour pouvoir utiliser ces périmètres dans la définition des règles ACL avec l’opérateur in il est nécessaire de transformer ces collections en chaîne de caractère. Cela se fait simplement dans une formule Python avec la fonction repr(*array*). Pour cela, on modifie la colonne PERIMETRE_REGIONS avec la formule suivante :

    codesToString = [region.CODE_REGION for region in $REGIONS_AFFECTEES] if $REGIONS_AFFECTEES else []
    return repr(codesToString)
    
  5. On fait de même pour les codes dans la colonne PERIMETRE_AGENCES

    codesToString = [agence.CODE_AGENCE for agence in $AGENCES_AFFECTEES] if $AGENCES_AFFECTEES else []
    return repr(codesToString)
    

Le poids des mots, le choc des photos.

Ca sera peut être plus parlant avec une capture d’écran, avec 4 profils utilisateurs.

Dans cet exemple, on a 4 profils utilisateurs : directeur d’école, ERUN, IEN de circonscription du premier degré et équipe en DSDEN.

La table DEC est :

  • Accessible avec tous les droits pour les propriétaires de l’espace.
  • Accessible en lecture seule (Rxxx) aux utilisateurs avec le profil « DEC », et ces derniers ne peuvent voir que les lignes qui correspondent à leur écoles (rec.UAI in ...). La table DEC a donc une colonne UAI qui contient le code de l’école.
  • Accessible en lecture seule aux utilisateurs avec le profil « ERUN ». Le perimètre des ERUN est différent. Il est calculé par l’affectation de l’ERUN à une ou plusieurs circonscriptions duquel on en déduit le périmètre des écoles rattachés aux circos (de la même manière que le directeur de région dans l’exemple de ce guide).

Enjoy ^^..

1 « J'aime »