ADR-0003 — Identité fédérée : ActuaryLab adopte le standard du socle (Levier C)¶
| Statut | ✅ Accepté — 2026-06-09 |
| Portée | backend/ (SSO, RBAC, mapping persona), module ActuaryLab |
| Décision | ActuaryLab se conforme au modèle d'identité fédérée Levier C du socle Quantis ; il n'invente pas son propre modèle |
| Réf. normative | Quantis-app/docs/IDENTITE_FEDEREE.md (§4.2 Levier C, §5 politique persona) |
🎯 À retenir
ActuaryLab se conforme au modèle d'identité fédérée du socle (Levier C) et n'invente pas le sien : le jour des personas, il clonera le pattern d'EmpreinteCarbone (table sso_link, provisioning JIT au persona le plus bas, élévation par match d'email). Aujourd'hui l'ADR fixe la direction et trace l'écart — aucune table persona n'est créée (YAGNI).
Contexte¶
Le socle Quantis a déjà tranché son modèle d'identité fédérée — documenté dans
Quantis-app/docs/IDENTITE_FEDEREE.md (« L'identité fédérée dans l'écosystème Quantis »),
acté auprès de la Direction BFEV le 2026-05-22. C'est une chaîne SSO à trois niveaux
YODICORE (IdP) → Quantis (Consumer + IdP) → Module (SP), et le choix retenu est le
Levier C (hybride) :
- Quantis (IdP) ne transporte qu'un rôle binaire universel dans le SLT
(
tenant_admin|tenant_user) : il authentifie et nomme le tenant, sans RBAC métier. - Le module détient son propre RBAC : table de jointure
sso_link(provider, external_sub, persona, local_user_id, status) + écran d'admin. Provisioning JIT conservateur : un inconnu reçoit le persona le plus bas (active) ; l'élévation vers un persona puissant se fait uniquement par match d'email avec un compte pré-créé — jamais via le claimrole(anti-escalade cross-tenant, §5.1).
EmpreinteCarbone est l'implémentation de référence de ce modèle (Phase R, en production,
table sso_links + resolve_sso_persona, trois cookies de session par persona).
État actuel d'ActuaryLab. Le module est un SSO Consumer pur (backend/app/sso.py) :
il vérifie le SLT auprès de /verify/, crée le Tenant à la volée, ouvre une session signée.
Il porte le claim role dans la session (session.py) mais ne le mappe à aucun persona :
il n'a ni table sso_link ni tables persona (seul Tenant existe). Il est donc
conforme-mais-incomplet : conforme parce qu'il ne fait aucun mapping abusif (la règle
« ne pas auto-mapper role → persona » est respectée par le fait qu'il ne mappe rien) ;
incomplet parce qu'il n'a pas encore de RBAC métier.
Question à trancher : quand ActuaryLab aura besoin de personas distincts (actuaire junior / senior / externe / consultant client — cf. plan d'implémentation), quel modèle de mapping adopte-t-il ?
Options considérées¶
- A — Adopter le standard du socle (Levier C, pattern EC) : implémenter une table
sso_linket l'élévation par match d'email, en clonant le pattern déjà éprouvé sur EmpreinteCarbone. - B — Inventer un modèle propre à ActuaryLab : par exemple traduire mécaniquement le claim
roleen persona, ou un mapping ad-hoc spécifique au module. - C — Rester SSO Consumer pur indéfiniment : ne jamais introduire de personas ; un seul niveau d'accès pour tout utilisateur authentifié du tenant.
Comparatif pour / contre¶
| Critère | A — Standard socle (Levier C) | B — Modèle propre | C — Consumer pur |
|---|---|---|---|
| Conformité IDENTITE_FEDEREE.md | ✅ par construction | ❌ diverge du standard | ✅ (trivialement) |
| Sécurité (anti-escalade cross-tenant) | ✅ match d'email, éprouvé | ❌ risque si role→persona |
✅ (rien à mapper) |
| Réutilisation (pattern EC en prod) | ✅ clone direct, ~100 tests amont | ❌ tout réécrire | ✅ rien à écrire |
| Cohérence inter-modules Quantis | ✅ même grammaire que EC | ❌ deux modèles divergents | ⚠️ neutre |
| Couvre les personas du plan | ✅ junior/senior/externe/client | ⚠️ selon impl | ❌ impossible |
| Coût aujourd'hui | ⚠️ non nul (mais différé) | ❌ élevé + risqué | ✅ nul |
Décision¶
Option A — ActuaryLab adopte le standard d'identité fédérée du socle (Levier C). Il
n'invente pas son propre modèle (B écarté : divergence + risque d'escalade) et n'est pas
condamné au mono-accès (C écarté : le plan prévoit des personas distincts). Quand le besoin de
personas se concrétisera, le module clonera le pattern d'EmpreinteCarbone : table sso_link,
provisioning JIT conservateur (persona le plus bas par défaut), élévation par match d'email
avec compte pré-créé par un Admin du module — jamais par traduction du claim role.
Ce que cette décision tranche aujourd'hui (sans code) : la direction. Aucune table persona n'est créée maintenant (YAGNI : ActuaryLab n'a pas encore de feature différenciée par rôle). La valeur de cet ADR est de fixer le standard cible et de tracer l'écart, pour qu'on n'improvise pas un modèle divergent le jour venu.
Conséquences¶
- Écart tracé (dette de conformité, assumée). ActuaryLab porte
roledans la session mais ne l'exploite pas ; il n'a nisso_linkni RBAC métier. C'est volontaire au stade actuel (Jalon 0 + moteur DBO). L'écart à combler =sso_link+ élévation par email, le jour des personas. - Aucune dépendance directe à EC. On clone le pattern, pas le code (EC reste un dépôt séparé) — comme le déclencheur A→C des ADR-0001/0002, c'est une réutilisation de design, pas un couplage de build.
- Garde-fou de sécurité pré-acté. Le mapping
role → persona puissantest interdit ; seule l'élévation par match d'email est autorisée (cohérent avec la politique socle §5.1).
⚠️ Piège
Le claim role du SLT est tenant-scopé : le traduire mécaniquement en persona puissant ouvre une escalade cross-tenant. L'élévation passe uniquement par match d'email avec un compte pré-créé. Un inconnu reçoit toujours le persona le plus bas.
- Doc. L'Architecture renvoie à cet ADR pour la trajectoire d'auth ;
la note normative reste
Quantis-app/docs/IDENTITE_FEDEREE.md.
Déclencheur de réexamen (pré-enregistré)¶
Dès qu'ActuaryLab introduit une feature différenciée par rôle (≥ 2 personas, p. ex. un écran
réservé à l'actuaire senior, ou un parcours consultant client distinct), implémenter le pattern
sso_link du socle (cette décision passe alors de direction à code). Tant qu'un seul niveau
d'accès suffit, l'état « Consumer pur » reste conforme et il n'y a rien à construire.