From 5402624e2083c2411ba8c333d7ccf9a15d7f2cf1 Mon Sep 17 00:00:00 2001 From: Spark Date: Fri, 6 Nov 2026 13:54:11 +0000 Subject: [PATCH] =?UTF-8?q?Kanbante=200.46.0=20:=20documentation=20?= =?UTF-8?q?=E2=80=94=20correspondance=20draco,=20JIT,=20liaison=20admin,?= =?UTF-8?q?=20amor=C3=A7age,=20non-r=C3=A9gressions=20(docs/correspondance?= =?UTF-8?q?-draco.md)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/correspondance-draco.md | 132 +++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 docs/correspondance-draco.md diff --git a/docs/correspondance-draco.md b/docs/correspondance-draco.md new file mode 100644 index 0000000..6415a04 --- /dev/null +++ b/docs/correspondance-draco.md @@ -0,0 +1,132 @@ +# 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-` 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.