78 lines
4.0 KiB
Markdown
78 lines
4.0 KiB
Markdown
# #228 — HUB-19 : propagation des rôles du Hub à ObsiGate
|
|
|
|
**Carte :** suite de HUB-19 (plan Hub v2 §2.2, décision D3(a)) — le pilote
|
|
ShaarIt (0.7.0, en production) a posé le contrat ; ObsiGate le consomme à
|
|
son tour, comme hôte à la fois **émettrice** et **consommatrice** du SSO.
|
|
**Version cible :** 2.85.1 (branche depuis le main 2.84.1 ; hypothèse : à
|
|
rebaser après la PR « API sessions HUB-22 » — 2.85.0 — si elle fusionne
|
|
d'abord).
|
|
|
|
## Contrat consommé (D3(a))
|
|
|
|
À l'ouverture de session draco — chez ObsiGate : la validation locale du
|
|
cookie partagé, `draco_session.user_for_draco()` (ACC-3.2, #217), appelée
|
|
par le repli draco de `get_current_user` — consultation du registre :
|
|
|
|
- `GET {hub}/api/roles/obsigate`, en-tête **Cookie complet** de la requête
|
|
relayé tel quel, `Accept: application/json`, délai **2 s** ;
|
|
- réponse 200 : `{"app", "sub", "role", "explicite", "ttl_secondes": 60}`,
|
|
`role` ∈ {`aucun`, `utilisateur`, `administrateur`} ;
|
|
- **URL du Hub** : `draco_config.app_url("hub")`, la résolution de la
|
|
barre commune (#223) — `DRACO_HUB_URL` explicite d'abord, dérivation
|
|
par l'hôte sœur (suffixe d'environnement de l'hôte de l'agent)
|
|
ensuite, défaut officiel enfin. Jamais d'URL dev figée.
|
|
|
|
## Client — `backend/hub_roles.py`
|
|
|
|
Sur le patron du pilote (`src/hub_roles.rs` de ShaarIt) :
|
|
|
|
- cache mémoire par `sub`, TTL **60 s** ;
|
|
- horodatage posé **avant** l'appel : un échec conserve l'ancien cache
|
|
et ne déclenche pas de rafale vers un Hub en panne ;
|
|
- toute erreur (réseau, délai, statut ≠ 200, JSON illisible, rôle hors
|
|
contrat) → rôle **inconnu** (`None`) → l'appelant garde son
|
|
comportement actuel. Le registre ne crée jamais un verrouillage
|
|
nouveau.
|
|
|
|
## Effets (sessions établies par draco seulement)
|
|
|
|
1. **Niveau connu `aucun`** → `user_for_draco` refuse : pas de session
|
|
établie par draco. `require_auth` répond alors **403** avec un
|
|
message explicite en français (niveau « aucun », matrice des rôles
|
|
du Hub, accès natif toujours possible), consigné via
|
|
`request.state.role_hub_refuse`. L'**authentification native**
|
|
d'ObsiGate (son propre login — c'est l'émettrice, son accès propre
|
|
est le secours) n'est **jamais** touchée.
|
|
2. **Routes d'administration `/api/auth/admin/*`** (CRUD des comptes,
|
|
`backend/auth/router.py`) : nouvelle garde `require_admin_hub`
|
|
(`backend/auth/middleware.py`) = `require_admin` + , quand la
|
|
requête est authentifiée par le **canal draco** (`_draco_sub`
|
|
présent, `_hub_role` joint par `user_for_draco`) et que le rôle est
|
|
**connu**, exigence du niveau `administrateur` du registre.
|
|
Sessions natives → règles actuelles inchangées ; rôle inconnu →
|
|
règles actuelles inchangées. Le registre n'élève aucun privilège :
|
|
un compte local non admin reste refusé par la règle locale, quel
|
|
que soit son niveau au Hub.
|
|
3. **Inchangés** : validation locale du jeton, émission du cookie,
|
|
révocations (`jti`), renouvellement glissant. **Aucun rôle dans le
|
|
jeton** (claims minimaux de #216 préservés).
|
|
|
|
Périmètre assumé : la garde du registre vise les routes nommées par la
|
|
carte, `/api/auth/admin/*`. Les autres surfaces gardées par
|
|
`require_admin` (configuration, vaults, coffres…) gardent leurs règles
|
|
actuelles ; les y soumettre serait un changement d'une ligne par
|
|
surface (`require_admin_hub` est réutilisable tel quel) si Bruno le
|
|
décide.
|
|
|
|
## Tests
|
|
|
|
`tests/test_hub_roles.py` : parsing du contrat (URL, Cookie relayé,
|
|
`Accept`, délai 2 s), rôles reconnus / hors contrat, JSON illisible,
|
|
erreurs HTTP et réseau → inconnu ; résolution de l'URL du Hub
|
|
(explicite, dérivée `-dev`, défaut officiel) ; cache par `sub`, TTL,
|
|
échec sans rafale avec ancien cache conservé ; intégration sur le
|
|
chemin draco (refus « aucun » explicite, login natif intact sous
|
|
« aucun », rôle inconnu = comportement actuel, `utilisateur` Hub
|
|
refusé sur `/api/auth/admin/*`, `administrateur` Hub accepté, compte
|
|
local non admin non élevé, session native jamais bloquée par le Hub).
|