Skip to content

feat(ra-console): connexion par nom, login/begin et login/finish (1c-1) - #34

Merged
PhilippeVienne merged 1 commit into
devfrom
feat/ra-console-login-begin-finish
Sep 25, 2026
Merged

PhilippeVienne merged 1 commit into
devfrom
feat/ra-console-login-begin-finish

Conversation

@PhilippeVienne

Copy link
Copy Markdown
Contributor

Contexte

Étape 1c du plan WEBUI §15 (ra-console), premier des deux morceaux convenus : la connexion. ra-console vérifie elle-même l'assertion WebAuthn contre le registre en lecture seule — aucun aller-retour vers ca-server pour une connexion, une session n'étant jamais une ancre de confiance (ca-server re-vérifie chaque action, §16). Reste (1c-2, PR suivante) : sessions, cookie, /api/v1/me, déconnexion, purge, limitation de débit.

Empilée sur #33 (fix/operators-load-without-hsm).

Contenu

  • POST /api/v1/webauthn/login/begin {name} : options WebAuthn de même forme que le nom existe ou non ("connexion par nom, réponses uniformes", §16). Un nom inconnu, désactivé ou sans clé active reçoit un défi factice à une clé, dont l'identifiant dérive de HMAC-SHA256(secret du service, nom). oe-webauthn expose ce constructeur (decoy_authentication_challenge), testé contre un défi réel produit par le même vérificateur (même RP ID, délai, userVerification, hints, nombre de clés proposées).
  • POST /api/v1/webauthn/login/finish {challenge_id, credential} : consomme le challenge dans webauthn_challenges (usage unique, 5 min), vérifie l'assertion et met à jour login_counters — le compteur anti-clonage propre à ra-console, jamais webauthn_credentials.sign_count qu'elle ne peut pas écrire (rôle PostgreSQL en lecture seule, §16). Une seule erreur pour tout refus après begin : nom inconnu, leurre, challenge périmé/consommé, clé révoquée, opérateur désactivé, signature refusée, compteur en régression ne se distinguent jamais de l'extérieur.
  • oe-actions::Registry::operator_by_name, en lecture seule.

Un piège rencontré et son correctif

oe-actions et oe-webauthn passent de dev-dependencies à dependencies de ra-console. oe-ca-core désactive désormais les fonctionnalités par défaut de son lien vers oe-hsm (elle n'utilise que le trait SigningToken, jamais Pkcs11Token) : sans ce réglage, la dépendance transitive oe-actions → oe-raflow → oe-ca-core → oe-hsm aurait relié cryptoki au binaire de ra-console, contrairement à docs/WEBUI.md §16. tests/no_pkcs11.rs l'a détecté immédiatement ; ca-server, qui redemande oe-hsm directement avec ses fonctionnalités par défaut, n'est pas affecté.

Limite assumée

Le défi factice ne propose toujours qu'une seule clé (le cas le plus courant d'un opérateur) : un opérateur qui en porterait plusieurs resterait distinguable par le nombre de clés proposées. Documenté dans le code (oe_webauthn::decoy).

Vérifications

  • cargo fmt --check
  • cargo clippy --workspace --all-targets -- -D warnings (toolchain 1.97 et 1.98.1, celle de la CI)
  • cargo test --workspace (avec OE_CASTORE_TEST_DSN) : vert, y compris les nouveaux tests d'intégration de bout en bout (bin/ra-console/tests/login.rs) et les tests unitaires d'oe-webauthn (aller-retour JSON de l'état d'authentification, forme du défi factice)
  • cargo audit --ignore RUSTSEC-2023-0071 : rien à signaler
  • Contrôle par mutation : le contrôle de révocation et le rejet d'une clé d'un autre opérateur échouent chacun pour la bonne raison quand on retire le contrôle correspondant (la régression du compteur anti-clonage protège aussi, indépendamment, contre le rejeu d'une assertion identique)

ra-console vérifie elle-même l'assertion WebAuthn contre le registre en
lecture seule (docs/WEBUI.md §15 étape 1c, §16) : aucun aller-retour vers
ca-server pour une connexion. Une session n'est jamais une ancre de
confiance (ca-server re-vérifie chaque action) ; cette tranche ne rend donc
que l'identité vérifiée, la session (cookie, /api/v1/me, déconnexion,
purge, débit) est 1c-2.

- POST /api/v1/webauthn/login/begin {name} : options WebAuthn de même forme
  que le nom existe ou non ("connexion par nom, réponses uniformes"). Un
  nom inconnu, désactivé ou sans clé active reçoit un défi factice à une
  clé, dont l'identifiant dérive de HMAC-SHA256(secret du service, nom) —
  stable pour un même nom, imprévisible sans le secret. oe-webauthn expose
  ce constructeur (decoy_authentication_challenge), testé contre un défi
  réel produit par le même vérificateur.
- POST /api/v1/webauthn/login/finish {challenge_id, credential} : consomme
  le challenge dans webauthn_challenges (usage unique, 5 min), vérifie
  l'assertion et met à jour login_counters, le compteur anti-clonage propre
  à ra-console (jamais webauthn_credentials.sign_count, que ra-console ne
  peut pas écrire). Une seule erreur pour tout refus après begin : nom
  inconnu, leurre, challenge périmé/consommé, clé révoquée, opérateur
  désactivé, signature refusée, compteur en régression ne se distinguent
  jamais de l'extérieur.
- oe-actions::Registry::operator_by_name, en lecture seule.
- oe-actions et oe-webauthn passent de dev-dependencies à dependencies de
  ra-console. oe-ca-core désactive les fonctionnalités par défaut de son
  lien vers oe-hsm (elle n'utilise que le trait SigningToken) : sans ce
  réglage, la dépendance transitive par oe-actions -> oe-raflow ->
  oe-ca-core aurait relié cryptoki au binaire de ra-console (tests/no_pkcs11.rs
  l'a détecté).

Vérifications : cargo fmt --check, cargo clippy --workspace --all-targets
(1.97 et 1.98.1), cargo test --workspace (avec OE_CASTORE_TEST_DSN), cargo
audit. Contrôle par mutation : le compteur anti-clonage, le contrôle de
révocation et le rejet d'une clé d'un autre opérateur échouent chacun pour
la bonne raison quand on retire le contrôle correspondant.
@PhilippeVienne
PhilippeVienne changed the base branch from fix/operators-load-without-hsm to dev September 25, 2026 09:04
@PhilippeVienne
PhilippeVienne force-pushed the feat/ra-console-login-begin-finish branch from ab615f9 to 79b34b4 Compare September 25, 2026 09:04
@PhilippeVienne
PhilippeVienne merged commit 0530043 into dev Sep 25, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant