Aller au contenu

PD-238 — Endpoints de gestion MFA utilisateur

1. Objectif

Décrire le contrat canonique des endpoints backend permettant a un utilisateur authentifie de : - consulter l'etat MFA ; - activer le MFA TOTP (init + verification) ; - desactiver le MFA ; - regenerer les codes de recuperation ; - se re-authentifier pour operations sensibles.

2. Périmètre / Hors périmètre

Inclus

  • Endpoint GET /user/mfa/status.
  • Endpoint POST /user/mfa/totp/init.
  • Endpoint POST /user/mfa/totp/verify.
  • Endpoint POST /user/mfa/disable.
  • Endpoint POST /user/mfa/recovery/regenerate.
  • Endpoint POST /auth/reauth.
  • Authentification JWT obligatoire pour /user/mfa/*.
  • Authentification JWT obligatoire pour POST /auth/reauth.
  • Re-authentification obligatoire pour la desactivation MFA et la regeneration des codes.
  • Delegation a Keycloak Admin API pour la gestion MFA.
  • Contrat d'API compatible avec PD-106.
  • Rate limiting applique aux endpoints MFA.

Exclu

  • Validation MFA a l'authentification (PD-27).
  • Gestion de profil (PD-32).
  • Changement de mot de passe.
  • Suppression de compte.
  • Logout / gestion de session.
  • MFA par SMS, email ou WebAuthn.
  • Implementation TOTP native cote ProbatioVault.
  • Stockage de secrets MFA cote ProbatioVault.

3. Définitions

  • MFA : authentification multi-facteur.
  • TOTP : mot de passe a usage unique base sur le temps (RFC 6238, gere par Keycloak).
  • Etat MFA : etat du MFA pour l'utilisateur courant (enabled, method, configuredAt).
  • method : type de MFA configure. Valeurs possibles : TOTP. Extensible ulterieurement.
  • configuredAt : date d'activation du MFA, format ISO 8601 UTC (ex: 2026-02-06T14:30:00Z).
  • Re-authentification : preuve recente d'identite pour operation sensible via POST /auth/reauth.
  • Reauth token : JWT signe avec claims sub, purpose="reauth", exp (5 minutes).
  • Operations sensibles : desactivation MFA, regeneration des codes de recuperation.
  • Codes de recuperation : codes a usage unique emis par Keycloak (15 codes par defaut).
  • Affichage unique : les codes de recuperation ne sont retournes qu'une seule fois apres generation/regeneration.
  • Compatibilite PD-106 : endpoints et payloads conformes aux formats attendus par PD-106.
  • Hors perimetre : exigence non verifiable dans PD-238 seul et devant etre prouvee par un artefact externe.

4. Invariants (non négociables)

ID Règle Justification
INV-238-01 Tous les endpoints /user/mfa/* DOIVENT exiger un JWT valide. Empêche l'acces anonyme.
INV-238-02 Un utilisateur NE DOIT pouvoir consulter/modifier que son propre MFA. Empêche l'acces croise.
INV-238-03 GET /user/mfa/status DOIT retourner {enabled, method, configuredAt} et method DOIT valoir TOTP (seule valeur supportée dans PD-238). Compatibilite PD-106.
INV-238-04 POST /user/mfa/totp/init DOIT retourner secret, qrCodeUri, expiresAt. Activation TOTP conforme.
INV-238-05 POST /user/mfa/totp/verify DOIT activer le MFA uniquement si le code est valide. Evite activation sans preuve.
INV-238-06 POST /user/mfa/disable DOIT exiger un reauth token valide. Protege operations sensibles.
INV-238-07 POST /user/mfa/recovery/regenerate DOIT exiger un reauth token valide et invalider les anciens codes. Protege operation sensible et evite coexistence codes.
INV-238-08 Les codes de recuperation DOIVENT etre retournes uniquement apres activation/regeneration (affichage unique). Reduit exposition des codes.
INV-238-09 Le secret TOTP et les codes de recuperation NE DOIVENT jamais etre loggues. Protection des secrets.
INV-238-10 Le backend ProbatioVault NE DOIT pas stocker les secrets MFA. Conformite PD-27 §I3.
INV-238-11 Les endpoints MFA DOIVENT etre soumis au rate limiting global. Prevention brute force.
INV-238-12 POST /auth/reauth DOIT retourner un reauthToken JWT avec sub, purpose="reauth", exp = 5 minutes. Garantit reauth stateless.
INV-238-13 Toute erreur metier/validation/auth DOIT retourner un echec explicite sans effet partiel silencieux. Auditabilite.
INV-238-14 HORS PERIMETRE PD-238 : preuve juridique exhaustive RGPD et audit Keycloak admin doivent etre fournis par artefacts conformite. Non prouvable via endpoints seuls.
INV-238-15 POST /auth/reauth DOIT exiger un JWT valide. Empêche l'acces anonyme.

5. Flux nominaux

F-238-01 — Lecture etat MFA

  1. L'utilisateur appelle GET /user/mfa/status avec JWT valide.
  2. Le systeme identifie l'utilisateur courant.
  3. Le systeme interroge Keycloak et retourne l'etat MFA.

F-238-02 — Initialisation TOTP

  1. L'utilisateur appelle POST /user/mfa/totp/init avec JWT valide.
  2. Le systeme initie la configuration TOTP via Keycloak.
  3. Le systeme retourne secret, qrCodeUri, expiresAt.

F-238-03 — Verification TOTP

  1. L'utilisateur appelle POST /user/mfa/totp/verify avec JWT valide et code.
  2. Le systeme verifie le code via Keycloak.
  3. En cas de succes, le MFA est active et les codes de recuperation sont retournes une seule fois.

F-238-04 — Desactivation MFA

  1. L'utilisateur appelle POST /user/mfa/disable avec JWT valide et X-Reauth-Token valide.
  2. Le systeme desactive le MFA via Keycloak.
  3. La reponse indique enabled: false.

F-238-05 — Regeneration codes de recuperation

  1. L'utilisateur appelle POST /user/mfa/recovery/regenerate avec JWT valide et X-Reauth-Token valide.
  2. Le systeme regenere les codes via Keycloak et invalide les anciens.
  3. Les nouveaux codes sont retournes une seule fois.

F-238-06 — Re-authentification

  1. L'utilisateur appelle POST /auth/reauth avec son mot de passe.
  2. Le systeme verifie l'identite et retourne un reauthToken avec expiresAt.

5bis. Diagrammes Mermaid

D-238-01 — Diagramme d'etats MFA utilisateur

Etats du MFA pour un utilisateur donne. Transitions gouvernees par INV-238-05 (activation uniquement si code valide), INV-238-06 (desactivation exige reauth), INV-238-07 (regeneration exige reauth et invalide anciens codes).

stateDiagram-v2
    [*] --> MFA_DISABLED

    MFA_DISABLED --> TOTP_INIT_PENDING : POST /user/mfa/totp/init\n[INV-238-04: retourne secret, qrCodeUri, expiresAt]

    TOTP_INIT_PENDING --> MFA_ENABLED : POST /user/mfa/totp/verify (code valide)\n[INV-238-05: activation + recoveryCodes]
    TOTP_INIT_PENDING --> MFA_DISABLED : expiresAt depasse\nou POST /user/mfa/totp/verify (code invalide, abandon)
    TOTP_INIT_PENDING --> TOTP_INIT_PENDING : POST /user/mfa/totp/verify (code invalide)\n[INV-238-13: echec explicite, pas d'effet partiel]

    MFA_ENABLED --> MFA_DISABLED : POST /user/mfa/disable + reauth token\n[INV-238-06]
    MFA_ENABLED --> MFA_ENABLED : POST /user/mfa/recovery/regenerate + reauth token\n[INV-238-07: anciens codes invalides]

D-238-02 — Diagramme de sequence : activation TOTP (F-238-02 + F-238-03)

Flux multi-service couvrant l'initialisation et la verification TOTP. Le backend ne stocke aucun secret MFA (INV-238-10), Keycloak est la source de verite.

sequenceDiagram
    participant U as Utilisateur
    participant B as Backend ProbatioVault
    participant KC as Keycloak Admin API

    Note over U,KC: Phase 1 — Initialisation TOTP (F-238-02)

    U->>B: POST /user/mfa/totp/init [JWT]
    activate B
    B->>B: Valider JWT [INV-238-01]
    B->>B: Identifier utilisateur courant [INV-238-02]
    B->>KC: Initier config TOTP (userId)
    activate KC
    KC-->>B: secret, qrCodeUri, expiresAt
    deactivate KC
    B-->>U: 200 {secret, qrCodeUri, expiresAt} [INV-238-04]
    deactivate B

    Note over U: L'utilisateur scanne le QR code<br/>dans son app TOTP

    Note over U,KC: Phase 2 — Verification TOTP (F-238-03)

    U->>B: POST /user/mfa/totp/verify {code} [JWT]
    activate B
    B->>B: Valider JWT [INV-238-01]
    B->>KC: Verifier code TOTP (userId, code)
    activate KC
    alt Code valide
        KC-->>B: OK + recoveryCodes (15 codes)
        B-->>U: 200 {enabled: true, recoveryCodes} [INV-238-05, INV-238-08]
    else Code invalide
        KC-->>B: INVALID
        B-->>U: 400 ERR-238-TOTP-INVALID [INV-238-13]
    end
    deactivate KC
    deactivate B

    Note over B: Secret TOTP et recoveryCodes<br/>jamais loggues [INV-238-09]<br/>Jamais stockes cote backend [INV-238-10]

D-238-03 — Diagramme de sequence : re-authentification + operation sensible (F-238-06 + F-238-04)

Flux de re-authentification prealable a une operation sensible (desactivation MFA). Applicable aussi a la regeneration des codes (F-238-05).

sequenceDiagram
    participant U as Utilisateur
    participant B as Backend ProbatioVault
    participant KC as Keycloak Admin API

    Note over U,KC: Phase 1 — Re-authentification (F-238-06)

    U->>B: POST /auth/reauth {password} [JWT]
    activate B
    B->>B: Valider JWT [INV-238-15]
    B->>B: Verifier mot de passe
    alt Mot de passe valide
        B->>B: Signer reauthToken JWT<br/>{sub, purpose="reauth", exp=5min} [INV-238-12]
        B-->>U: 200 {reauthToken, expiresAt}
    else Mot de passe invalide
        B-->>U: 401 ERR-238-REAUTH-FAILED
    end
    deactivate B

    Note over U,KC: Phase 2 — Desactivation MFA (F-238-04)

    U->>B: POST /user/mfa/disable [JWT + X-Reauth-Token]
    activate B
    B->>B: Valider JWT [INV-238-01]
    B->>B: Valider reauthToken (purpose, exp) [INV-238-06]
    B->>KC: Desactiver MFA (userId)
    activate KC
    KC-->>B: OK
    deactivate KC
    B-->>U: 200 {enabled: false}
    deactivate B

6. Cas d'erreur

Code erreur Condition Comportement attendu
ERR-238-UNAUTHENTICATED JWT absent/invalide Refus d'acces ; aucune operation effectuee.
ERR-238-UNAUTHORIZED-REAUTH Reauth token absent/invalide/expire Refus operation sensible.
ERR-238-FORBIDDEN-CROSS-ACCESS Tentative d'acces MFA d'un autre utilisateur Refus explicite ; aucune fuite.
ERR-238-TOTP-INIT-FAILED Echec initialisation TOTP Keycloak Message explicite ; aucune activation.
ERR-238-TOTP-INVALID Code TOTP invalide Message explicite ; MFA non active.
ERR-238-MFA-DISABLE-FAILED Echec desactivation MFA Message explicite ; MFA reste actif.
ERR-238-RECOVERY-REGEN-FAILED Echec regeneration codes Message explicite ; anciens codes restent valides.
ERR-238-RATE-LIMIT Seuil global depasse Refus explicite ; aucune operation effectuee.
ERR-238-INTERNAL Erreur interne non metier Refus explicite ; aucun succes affiche.
ERR-238-REAUTH-FAILED Mot de passe invalide Message explicite ; aucun token emis.

7. Critères d'acceptation (testables)

ID Critère Observable
CA-238-01 GET /user/mfa/status sans JWT est refuse. Reponse erreur auth.
CA-238-02 POST /user/mfa/totp/init sans JWT est refuse. Reponse erreur auth.
CA-238-03 POST /user/mfa/totp/verify sans JWT est refuse. Reponse erreur auth.
CA-238-04 POST /user/mfa/disable sans reauth token est refuse. Reponse erreur reauth.
CA-238-05 POST /user/mfa/recovery/regenerate sans reauth token est refuse. Reponse erreur reauth.
CA-238-06 GET /user/mfa/status retourne {enabled, method, configuredAt}. Inspection reponse JSON.
CA-238-07 POST /user/mfa/totp/init retourne secret, qrCodeUri, expiresAt. Inspection reponse JSON.
CA-238-08 POST /user/mfa/totp/verify active MFA uniquement si code valide. Etat MFA + reponse enabled: true.
CA-238-09 Codes de recuperation retournes uniquement apres activation/regeneration. Absence en dehors de ces reponses.
CA-238-10 Regeneration invalide anciens codes. Ancien code refuse.
CA-238-11 Desactivation MFA exige reauth token valide. Operation refusee sans reauth.
CA-238-12 Secrets TOTP et recovery codes ne figurent pas dans les logs. Audit logs.
CA-238-13 Endpoints MFA soumis au rate limiting. Reponse rate limit.
CA-238-14 Reauth token retourne sub, purpose="reauth", exp (5 min). Inspection JWT.
CA-238-15 HORS PERIMETRE PD-238 : preuve RGPD/Keycloak admin via artefacts externes. Presence artefact externe.
CA-238-16 POST /auth/reauth sans JWT est refuse. Reponse erreur auth.

8. Scénarios de test (Given / When / Then)

Scenario 1 — Etat MFA nominal

GIVEN utilisateur authentifie. WHEN GET /user/mfa/status. THEN la reponse contient enabled, method, configuredAt.

Scenario 2 — Init TOTP nominale

GIVEN utilisateur authentifie. WHEN POST /user/mfa/totp/init. THEN la reponse contient secret, qrCodeUri, expiresAt.

Scenario 3 — Verify TOTP nominal

GIVEN utilisateur authentifie et secret init. WHEN POST /user/mfa/totp/verify avec code valide. THEN MFA devient actif et recoveryCodes sont retournes une seule fois.

Scenario 4 — Verify TOTP invalide

GIVEN utilisateur authentifie. WHEN POST /user/mfa/totp/verify avec code invalide. THEN MFA reste inactif et erreur explicite.

Scenario 5 — Disable MFA avec reauth

GIVEN utilisateur authentifie avec MFA actif et reauth token valide. WHEN POST /user/mfa/disable. THEN MFA est desactive.

Scenario 6 — Regen recovery codes avec reauth

GIVEN utilisateur authentifie avec MFA actif et reauth token valide. WHEN POST /user/mfa/recovery/regenerate. THEN nouveaux codes retournes, anciens invalides.

Scenario 7 — Reauth nominal

GIVEN utilisateur authentifie. WHEN POST /auth/reauth avec mot de passe valide. THEN reauthToken valide est retourne avec exp 5 min.

Scenario 8 — Rate limit

GIVEN utilisateur authentifie. WHEN depassement seuil requetes MFA. THEN reponse ERR-238-RATE-LIMIT.

Scenario 9 — Cross-access

GIVEN U1 et U2. WHEN U1 tente action MFA sur U2. THEN refus explicite.

Scenario 10 — Hors perimetre RGPD

GIVEN perimetre PD-238. WHEN preuve RGPD requise. THEN reference artefact externe.

Scenario 11 — Reauth mot de passe invalide

GIVEN utilisateur authentifie. WHEN POST /auth/reauth avec mot de passe invalide. THEN erreur explicite et aucun reauthToken emis.

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-238-01 Keycloak Admin API est disponible et authentifiable via service account. Endpoints MFA inoperants.
H-238-02 Les claims OIDC permettent d'identifier l'utilisateur courant. Acces croise possible.
H-238-03 Le backend peut valider un reauth token JWT signe. Operations sensibles non securisables.
H-238-04 Le rate limiting global est actif sur /user/mfa/*. CA-238-13 non atteignable.
H-238-05 Keycloak retourne 15 recovery codes par defaut. Incoherence avec contrat PD-106.
H-238-06 L'artefact RGPD/Keycloak admin est gere hors PD-238. CA-238-15 non demonstrable.

10. Points à clarifier

  1. Format exact des erreurs Keycloak a normaliser en ERR-238-*.
  2. Delai de validite du qrCodeUri (expiresAt) si different de Keycloak par defaut.
  3. Format exact du configuredAt retourne par Keycloak.
  4. Politique de rotation des recovery codes (regeneration illimitee ou seuil).

Références

  • Epic : EPIC-182
  • JIRA : PD-238
  • Repos concernés : ProbatioVault-backend
  • Documents associés : PD-27, PD-106, PD-32