Files
kanbante/docs/correspondance-draco.md

133 lines
6.2 KiB
Markdown

# Correspondance draco par utilisateur (HUB-16, 0.46.0)
Kanbante participe au SSO de la suite dracodev : ObsiGate émet le
cookie `draco_session` (JWS HS256, claims `sub`, `name`, `iat`,
`exp`, `jti`), Kanbante le valide localement (`app/draco.py`) et le
pont `GET /auth/draco` le convertit en session Kanbante native.
Depuis la 0.46.0, un jeton draco valide désigne **le compte
Kanbante de cette identité** — et aucun autre. L'ancienne
hypothèse mono-utilisateur (« un jeton valide = l'opérateur ») a
disparu. C'est ce qui fait tenir le critère de la suite : « un
compte créé fonctionne dans toutes les applications ».
## Où vit la correspondance
Dans le modèle existant des comptes : la colonne
**`users.draco_sub`** (texte, `UNIQUE`, présente depuis la 0.24.0)
porte le `sub` draco lié à chaque compte Kanbante.
`models.get_user_by_draco(sub)` est la résolution canonique ; la
règle de décision complète vit dans
`app.accounts.resolve_draco_user()`, seul point d'entrée du pont
et du contrôle draco de `/api/search`. La correspondance est donc
biunivoque : un `sub` ↔ un compte, garanti par la contrainte
d'unicité.
## Résolution d'une connexion draco (`/auth/draco`)
Dans l'ordre :
1. **Session native déjà ouverte** : si le navigateur porte à la
fois une session Kanbante et un cookie draco dont le `sub`
n'est lié à aucun compte, le `sub` est lié au compte de la
session (première visite doublement connectée — mécanisme
historique, inchangé, aussi appliqué à la connexion native
dans `login_submit`).
2. **Correspondance existante** : la session du compte lié est
ouverte. Un compte **désactivé** n'ouvre aucune session et
n'est jamais contourné (voir § Désactivation).
3. **Compte d'amorçage** : s'il n'existe qu'**un seul compte** et
que c'est un **admin actif sans liaison**, le premier `sub`
valide s'y lie et sa session est ouverte. C'est le cas du
compte créé à l'installation depuis l'environnement
(`KANBANTE_AUTH_USER` / `KANBANTE_AUTH_PASSWORD`, Bruno) : sa
correspondance s'établit au premier passage, sans le verrouiller
dehors. Ses autres accès restent inchangés dans tous les cas :
connexion native avec le mot de passe du compte, et repli
d'urgence par les identifiants d'environnement (formulaire et
Basic), qui ne dépendent pas de draco.
4. **Création JIT** : sinon, un compte Kanbante est créé pour
cette identité (détail ci-dessous) et sa session est ouverte.
Un `sub` inconnu n'ouvre **jamais** la session de l'opérateur
d'environnement ni celle d'un compte existant non lié — y compris
si le nom affiché draco ressemble au nom d'un compte local : le
JIT crée toujours un compte **nouveau** (nom suffixé `-2`, `-3`…
en cas de collision), jamais une adoption.
## Création JIT (juste-à-temps)
À la première connexion draco d'une identité sans correspondance :
- **nom d'utilisateur** : nom affiché des claims slugifié
(`Alice Exemple` → `alice-exemple`), libre ou suffixé ;
repli `draco-<sub>` si le nom est inexploitable ;
- **nom d'affichage** : le `name` des claims ;
- **rôle** : `member` (utilisateur standard) — jamais admin ;
- **mot de passe local** : secret aléatoire, haché (PBKDF2 comme
tous les comptes), **jamais divulgué** — l'accès normal passe
par draco. Un administrateur peut ensuite poser un mot de
passe local depuis `/admin` (bouton « Réinitialiser ») si un
accès local est voulu ;
- **espace** : le compte rejoint l'espace Principal comme membre,
comme tout utilisateur créé par l'administration ;
- le geste est journalisé (`draco.jit` dans le journal
d'administration).
## Liaison par l'administrateur (comptes préexistants)
Pour associer un compte Kanbante existant à une identité draco
sans attendre un premier passage :
1. Se connecter à Kanbante avec un compte **admin**.
2. Ouvrir **Administration** (`/admin`), section **Utilisateurs**.
3. Dans la colonne **Draco (sub)** du compte visé, saisir le
`sub` draco de l'identité (l'identifiant du compte de suite
chez l'émettrice, ObsiGate) et cliquer **Lier**.
4. La liaison est immédiate et journalisée (`draco.link.admin`).
Le bouton **Délier** de la même colonne la retire
(`draco.unlink.admin`).
Gardes : un `sub` déjà lié à un autre compte est refusé avec un
message d'erreur (délier l'autre compte d'abord). L'administrateur
peut lier **son propre** compte — c'est la voie manuelle pour le
compte d'amorçage si le premier passage ne l'a pas lié.
Chaque utilisateur peut aussi voir sa propre liaison dans
**Mon profil → Liaison draco (SSO)** et la délier lui-même.
> Le registre matriciel des rôles par application côté Hub
> (carte HUB-19) lira cette correspondance ; la présente carte ne
> livre que le côté Kanbante, qui est la source de vérité locale.
## Surfaces voisines
- **`GET /api/search`** (« Rechercher partout ») : le cookie draco
n'y est plus accepté « en tant qu'opérateur ». Il faut que le
`sub` désigne un compte (correspondance existante ou compte
d'amorçage lié au passage). Aucune création JIT sur cette
surface : la création a lieu à la première vraie connexion, par
le pont. Les autres modes d'accès à `/api/search` (session,
Basic, jeton `kbt_`) sont inchangés.
- **Désactivation** : désactiver un compte dans `/admin` coupe
tous ses accès — session native, pont draco (la correspondance
résout à « refusé ») et jetons `kbt_`. Réactiver le compte
rétablit la correspondance telle quelle.
## Non-régressions garanties
- **Jetons personnels `kbt_`** : création, usage sur `/mcp` et
`/api/`, révocation — inchangés ; un jeton n'ouvre toujours pas
l'interface web.
- **Sessions propres Kanbante** et **connexion native**
(formulaire, mot de passe de la base) : inchangées, y compris
la liaison automatique à la première visite doublement
connectée.
- **Authentification Basic** (identifiants d'environnement, pour
les scripts) : inchangée.
- **Pont inerte sans `DRACO_SESSION_SECRET`** : sans secret
configuré, `/auth/draco` renvoie au login, comme avant.
- La réconciliation Kanbante/Gitea par étiquettes (adoption d'une
colonne seulement si exactement une étiquette `kanban:*` est
reconnue) n'est pas touchée par cette carte.