Modèle d'accès — identités, rôles, délégation
Vous êtes ici : Référence — le contrat d’autorisation de toute la suite. Comment GS-Apps décide qui a le droit de faire quoi. Lecture 15 min. Audience : devs, auditeurs sécurité, et administrateurs de la Console UG (volet utilisateur en fin de page). Date : 2026-09-30 | Version : 1.9 — ADR-067 §8.quater, cinq garde-fous de D4 et « Voir comme » (D5 suspendu sous regard). (1.8, 2026-07-07 — précision véracité : le multi-tenant est porté par la validation backend (JWKS
/common+ allowlisttid) ; l’élargissementsignInAudiencede l’inscription Entra est une cible d’exploitation, plus affirmé comme fait accompli.) (1.7 : §6 extrait vers le guide, tenant-id retiré)
| Question | Réponse | Source de vérité |
|---|---|---|
| Qui es-tu ? | Un compte du tenant Workforce, ou un invité/membre d’un tenant autorisé | Azure AD (allowlist tid) |
| Que peux-tu faire dans l’app ? | Tes rôles (compagnie × module) |
BD ug.UserCompanyBcRoles |
| Qui administre les rôles ? | Le corporate délègue : un administrateur de compagnie gère les rôles de sa seule compagnie — scope borné, non re-délégable | Console UG |
| Qui peut tout voir (superuser) ? | Les administrateurs d’organisation, par octroi explicite (double-clé — pas l’appartenance, §3.bis) | ug.UserCompanyAccess + rôle ADM/ADMIN |
| Qui touche l’infra Azure ? | Une poignée d’humains, durcis par PIM/MFA/CA | Rôles d’annuaire Entra (plan séparé) |
Vue d’ensemble — la carte du système
Section intitulée « Vue d’ensemble — la carte du système »Avant les détails, le système en un coup d’œil. Trois plans : en haut qui gère les accès (Console UG), au milieu le flux identité → autorisation → apps, en bas l’infra Azure (plan séparé, qui n’accorde aucun droit applicatif). Les sections suivantes zooment sur chaque sous-ensemble.
1. Les deux plans
Section intitulée « 1. Les deux plans »ug, à droite) décide ce que tu peux faire.Le JWT prouve l’identité (signature + issuer exact-match v1/v2 + tid dans l’allowlist — ADR-063 D-N1). Tout le reste — ce que tu peux faire — se résout côté serveur depuis la BD ug. Conséquence directe : un superuser peut venir d’un autre tenant (membre ou invité d’un tenant autorisé), parce que son pouvoir est un grant ug, découplé du tenant.
2. Plan identité — multi-tenant Workforce
Section intitulée « 2. Plan identité — multi-tenant Workforce »Tenant unifié Workforce (ADR-055), trois populations :
| Population | userType Entra |
Auth | Statut |
|---|---|---|---|
| Corporate | Member | MSAL Azure AD | Actif |
| Terrain | Guest | Email OTP | En pause (Phase 2+) |
| Externes / B2B | Guest | OTP / OIDC fédéré | Phase 2+ |
La validation backend est multi-tenant par conception : JWKS /common, issuer exact-match v1/v2 substitué par le tid du jeton, audience double (l’élargissement signInAudience de l’inscription Entra vers multi-org est la cible — une étape d’exploitation, détail). Le backend valide JWT.tid contre l’allowlist ug.Companies.azure_tid (contrôle critique), puis résout l’utilisateur par (azure_tid, azure_oid). Une nouvelle compagnie s’onboarde par INSERT data (pas de re-déploiement de code).
L’identité est distribuée, l’accès est centralisé. Chaque compagnie a son tenant — ses comptes vivent là (Groupe Signalisation via SOFI ; BeancoLite demain dans le sien) — mais leurs rôles GS-Apps se gèrent tous dans la même Console UG. UG_CORPORATE est un chapeau sans tenant : on n’y connecte personne, on y élève au god-view par octroi explicite.
ug.Companies). UG_CORPORATE est un chapeau sans tenant — on n’y « habite » pas, on y est élevé par octroi.Le parcours de connexion — trois portes
Section intitulée « Le parcours de connexion — trois portes »Une connexion réussie franchit trois portes successives. Les deux premières sont Entra (plan identité, domaine de l’admin tenant) ; la troisième est l’application (plan autorisation, BD ug). Les trois doivent passer.
| # | Porte | Où | Échec typique |
|---|---|---|---|
| 1 | Authentification | Entra — jeton réel Microsoft, validé multi-tenant côté backend (JWKS /common) |
Compte inexistant / tenant non autorisé |
| 2 | Assignation à l’application | Entra — Applications d’entreprise → GS Apps → Utilisateurs et groupes | Pas assigné à l’app (code Microsoft AADSTS50105) : l’app est en « Attribution requise » → bloqué avant tout code |
| 3 | Autorisation applicative | App / BD ug — tid ∈ allowlist ug.Companies.azure_tid, mapping tid → compagnie, resolveOrProvisionUser, puis rôles/grants (Système C) |
Tenant inconnu → refus fail-closed ; aucun rôle → accès vide |
Identité ≠ assignation ≠ autorisation — trois gestes distincts. Inviter quelqu’un comme guest (identité, porte 1) ne l’assigne pas à l’app (porte 2) et ne lui donne aucun rôle (porte 3). Et le SSO n’a pas de lien magique : les courriels (invitation B2B Entra, invitation applicative) sont des notifications ; la personne se connecte simplement à l’URL avec son compte.
3. Plan autorisation — Système C
Section intitulée « 3. Plan autorisation — Système C »La source unique des rôles est la table ug.UserCompanyBcRoles (Système C). Les groupes Azure AD comme source d’authZ sont rejetés (ADR-063 §2 / SPEC-1 D-C1) : la BD est la seule vérité.
- Grain :
(user, compagnie, bc_key, rôle). Lebc_keyest un module (15 modules au catalogue, ADR-066) — vocabulaire MAJUSCULES post-nettoyage (ADM, pasADMIN; une contrainte CK le force). - Modèle : RBAC tenant-scoped + RLS (Row-Level Security). Pas de ReBAC (sur-ingénierie écartée).
- Scope cross-compagnie : le Cas 6 du prédicat RLS (
ug.UserCompanyAccess, ADR-064) autorise un user à voir plusieurs compagnies via un mapping aplati. Inerte tant qu’aucun seed.
Corporate-admin = donnée, jamais constante
Section intitulée « Corporate-admin = donnée, jamais constante »isCorporateAdmin est une propriété de l’utilisateur résolu, dérivée de la donnée ug (appartenance/grant au niveau de la company-parent UG, écrite par la Console UG) — jamais d’un compte de service, jamais en dur (ADR-063 D-N2). Elle mappe au bypass Cas 2 du prédicat RLS. Le hardcode adminReadClaims:true historique a été retiré (CH3) : injectCompanyId() dérive désormais companyId / isCorporateAdmin du user résolu, fail-closed si absent.
Vocabulaire canonique (ADR-070)
Section intitulée « Vocabulaire canonique (ADR-070) »ADR-070 fige un seul jeu de termes — à utiliser dans l’UI, la doc et le code neuf. Les valeurs d’enum internes restent inchangées :
| Terme (humain) | Sens | Interne consoleAccessVia |
|---|---|---|
| Administrateur d’organisation | god-view, toutes compagnies | uca (octroi explicite, double-clé) · corporate |
| Administrateur de compagnie | admin scopé à sa compagnie | delegated |
| Membre | rôles par module, pas d’administration | — |
Module ≠ niveau. ADM est un module (clé bc_key, ADR-066) ; ADMIN est un niveau de rôle (UTILISATEUR < GESTIONNAIRE < ADMIN). On écrit « rôle Administrateur sur le module Admin », jamais « ADM/ADMIN ». Désigner un admin est non délégable (anti-escalade : un administrateur de compagnie ne crée jamais d’admin).
4. Délégation à deux étages
Section intitulée « 4. Délégation à deux étages »ADR-067 tranche la frontière d’administration : le corporate ne micro-gère pas les rôles de chaque compagnie ; il délègue.
- Étage 1 (corporate) : compagnies, REACH, désigne l’admin de chaque compagnie, et fixe l’entitlement modules (quels modules une compagnie a le droit d’activer — non délégable).
- Étage 2 (admin délégué) : fait le finegrant — les rôles des users de sa compagnie, scopé à sa compagnie.
- Invariants : zéro double administration (D3) ; cinq garde-fous pour l’administrateur de compagnie — sa compagnie seulement, les modules activés pour elle seulement, jamais au-dessus de son propre niveau, jamais le rôle Administrateur sur le module Admin, et la personne à qui il accorde un rôle est membre de la compagnie (D4,
authorizeRoleWritesetfindNonMemberTargets,apps/ug/server/routes/roles.ts) ; le corporate garde la vue god de supervision / bris de glace (D5). - « Voir comme » (ADR-067 §8.quater, 2026-09-30) : l’administrateur d’organisation (double-clé
uca) regarde la Console UG comme l’administrateur d’une compagnie et y change les rôles, chaque changement signé à son nom. Le regard est un sélecteur, jamais une preuve : l’en-têteX-GS-Voir-Commeest revérifié par le serveur à chaque requête. Sous regard, D5 est suspendu — lecture de la seule compagnie regardée, écriture par les cinq garde-fous de D4, routes réservées à l’organisation refusées. Hors regard, D5 est intact.
Concrètement, la surface du finegrant délégué est la fiche compagnie scopée de la Console UG (CompanyDetailView en mode isDelegated, atterrissage sur l’onglet Membres), pas N écrans séparés. Le résolveur resolveConsoleAccess (@gs/auth-multi-tenant/console-access) rend un verdict 'corporate' | 'uca' | 'delegated' | null (fail-closed : god-view via la double-clé uca — le court-circuit corporate par appartenance a été retiré au §3.bis, valeur désormais inatteignable ; delegated exige ≥1 compagnie administrée). Sous regard « Voir comme », GET /api/me de la Console UG rend consoleAccessVia: 'delegated' et voirComme: { companyId } : une seconde source du verdict, que l’UI suit sans le re-dériver.
5. Superuser & accès privilégiés
Section intitulée « 5. Superuser & accès privilégiés »Le « superuser » de l’app = un corporate-admin. C’est un grant data ug (isCorporateAdmin), curé — on ne l’accorde qu’aux compétents. Deux portes le gardent : (1) identité dans un tenant autorisé (allowlist tid) + (2) le grant ug. Pas de groupe Entra parallèle comme source d’authZ (ce serait une 2e liste = double administration + contredit la source unique).
Distinct : les humains qui tiennent les clés Azure (App Regs, Conditional Access, SQL db_owner, provision-app.ps1). C’est un plan séparé, durci selon la règle de l’art 2026 (ADR-069) : MFA partout, PIM (rôles eligible/JIT), Conditional Access, < 5 Global Admins, compte break-glass. Avoir une adresse UG ne donne aucun de ces droits.
6. Gérer les accès au quotidien — le guide
Section intitulée « 6. Gérer les accès au quotidien — le guide »Les gestes concrets dans la Console UG (ug.groupesignalisation.ca) — donner un accès, désigner un administrateur de compagnie ou d’organisation, débloquer une connexion — vivent dans un guide dédié : Gérer les accès dans la Console UG. Cette page-ci reste la référence des concepts ; le guide est le pas-à-pas.
Pourquoi ces choix
Section intitulée « Pourquoi ces choix »Chaque décision structurante suit un standard reconnu (Microsoft Well-Architected, patrons SaaS multi-tenant, RBAC/RLS) — pas une préférence locale. Le détail et les alternatives écartées vivent dans les ADR ; voici le « pourquoi » en clair :
| Décision | Pourquoi (le standard) | ADR |
|---|---|---|
| Identité ≠ autorisation (deux plans) | Base des systèmes matures : on change l’un sans toucher l’autre ; un externe entre sans devenir un compte maison. | 061 / 063 |
Multi-tenant /common + allowlist tid, fail-closed |
Patron Microsoft documenté pour le SaaS multi-tenant. Onboarder une compagnie = une donnée, pas un déploiement. | 055 |
| RBAC tenant-scopé + RLS | Défense en profondeur : même une requête fautive reste bornée par la base. | 061 / 064 |
BD ug comme source unique d’authZ (pas les groupes Entra) |
Évite la double administration et le « group sprawl ». Choix assumé ; l’inverse existe, mais une seule vérité s’audite mieux. | 063 |
| Délégation à deux étages, non cascadable | « Delegated administration » de manuel : le corporate distribue des périmètres, l’admin de compagnie joue dedans sans l’élargir. | 067 |
| God-view par octroi explicite, révocable, audité | Moindre privilège : le pouvoir vient d’un octroi nommé, pas d’une appartenance. Retrait en un clic, tout est tracé. | 070 §3.bis |
| PIM / MFA / Conditional Access / break-glass (infra Azure) | Recommandation Microsoft Well-Architected pour les accès privilégiés. Une adresse UG ne donne aucun droit infra. | 069 |
| ADR + infra-as-code (bicep) | Les décisions et l’infra sont écrites et versionnées, pas dans une tête. Reproductible, auditable. | — |
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Gérer les accès dans la Console UG — le guide pas-à-pas (donner un accès, désigner un admin).
- Stratégie d’authentification (flux MSAL / PKCE / MI)
- Architecture de données — où vit la RLS qui borne ces accès.
ADRs (dépôt GitHub — le détail des décisions et des alternatives écartées) :
- ADR-055 — Workforce multi-tenant
- ADR-063 — Cible auth/authZ 2026 (corporate-admin data-driven, JWT)
- ADR-064 — Scope cross-compagnie (Cas 6)
- ADR-066 — Catalogue
bc_key - ADR-067 — Délégation d’administration des rôles
- ADR-069 — Hygiène des accès privilégiés Azure
- ADR-070 — Nomenclature d’accès (vocabulaire canonique)