Aller au contenu

PD-239 — Changement de mot de passe utilisateur

1. Objectif

Décrire le contrat canonique de l'endpoint backend permettant à un utilisateur authentifié de changer son mot de passe, avec re‑authentification préalable, validation de l'ancien mot de passe, validation de la politique de complexité et invalidation des sessions.

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

Inclus

  • Endpoint POST /user/password/change.
  • Authentification JWT obligatoire.
  • Re‑authentification obligatoire (reauth token PD‑238) avant exécution.
  • Vérification de l'ancien mot de passe côté serveur.
  • Validation du nouveau mot de passe selon la politique de complexité Keycloak.
  • Invalidation de toutes les sessions après changement réussi.
  • Format d'erreur contractuel : {error: "ERR-239-*", message: "..."}.
  • Délégation à Keycloak Admin API pour le changement effectif.
  • Compatibilité contractuelle avec PD‑106 (F‑106‑05, INV‑106‑12, CA‑106‑11/12).

Exclu

  • Changement de mot de passe sans re‑authentification.
  • Gestion MFA (PD‑238).
  • Gestion de profil (PD‑32).
  • Suppression de compte.
  • Logout interactif (hors invalidation sessions post‑change).
  • Réinitialisation de mot de passe « oublié ».

3. Définitions

  • Re‑authentification : preuve récente d'identité via reauth token PD‑238.
  • Reauth token : JWT signé avec sub, purpose="reauth", exp (TTL 5 minutes).
  • Ancien mot de passe : mot de passe actuel de l'utilisateur, requis pour le changement.
  • Nouveau mot de passe : mot de passe proposé, soumis à la politique de complexité Keycloak.
  • Confirmation : champ qui doit être identique au nouveau mot de passe (contrôle client PD‑106).
  • Politique de complexité : règles Keycloak actives au moment de l'appel.
  • Sessions : sessions actives de l'utilisateur (tokens/refresh) à invalider après succès.
  • Message exploitable : message utilisateur contenant un motif actionnable.
  • Hors périmètre : exigence non vérifiable via PD‑239 seul et devant être prouvée par un artefact externe.

4. Invariants (non négociables)

ID Règle Justification
INV-239-01 POST /user/password/change DOIT exiger un JWT valide. Empêche l'accès anonyme.
INV-239-02 POST /user/password/change DOIT exiger un reauth token valide. Protège opération critique (INV‑106‑05).
INV-239-03 L'ancien mot de passe DOIT être vérifié avant modification. Empêche la prise de contrôle par session volée.
INV-239-04 Le nouveau mot de passe DOIT respecter la politique de complexité Keycloak. Conformité sécurité.
INV-239-05 En cas de succès, toutes les sessions utilisateur DOIVENT être invalidées dans un délai de 30 secondes maximum. Empêche la persistance de sessions compromises.
INV-239-06 Le format d'erreur DOIT être {error: "ERR-239-*", message: "..."}. Compatibilité mobile PD‑106.
INV-239-07 Tout refus serveur DOIT retourner un motif exploitable. Exigence PD‑106 (INV‑106‑12).
INV-239-08 L'endpoint DOIT déléguer le changement effectif à Keycloak Admin API. Cohérence architecture (PD‑26).
INV-239-09 HORS PÉRIMÈTRE PD‑239 : preuve exhaustive de purge/retention RGPD doit être fournie par artefacts externes. Non prouvable via endpoints seuls.
INV-239-10 Un log structuré avec event=keycloak_password_change et userId=<sub> DOIT être émis lors de l’appel Keycloak Admin API. Permet l’observable de délégation.

5. Flux nominaux

F-239-01 — Changement de mot de passe nominal

L'utilisateur appelle POST /user/password/change avec JWT valide, reauth token valide, ancien mot de passe et nouveau mot de passe. Le système vérifie l'ancien mot de passe. Le système valide le nouveau mot de passe selon la politique Keycloak. Le système délègue la modification à Keycloak Admin API. En cas de succès, le système invalide toutes les sessions de l'utilisateur. Le système retourne un succès explicite.

5b. Diagrammes Mermaid

Diagramme de séquence — Changement de mot de passe (F-239-01)

sequenceDiagram
    participant C as Client (PD-106)
    participant B as Backend
    participant KC as Keycloak Admin API

    C->>B: POST /user/password/change<br/>Authorization: Bearer <JWT><br/>X-Reauth-Token: <reauth_token><br/>{oldPassword, newPassword}

    Note over B: Vérification JWT (INV-239-01)
    alt JWT absent ou invalide
        B-->>C: 401 ERR-239-UNAUTHENTICATED
    end

    Note over B: Vérification reauth token (INV-239-02)
    alt Reauth token absent/invalide/expiré
        B-->>C: 401 ERR-239-UNAUTHORIZED-REAUTH
    end

    Note over B: Vérification ancien mot de passe (INV-239-03)
    B->>KC: Validate oldPassword (user credentials grant)
    alt Ancien mot de passe invalide
        KC-->>B: 401/404
        B-->>C: 400 ERR-239-PWD-INVALID
    end
    KC-->>B: 200 OK

    Note over B: Délégation changement à Keycloak (INV-239-08)
    B->>KC: PUT /admin/realms/{realm}/users/{id}/reset-password<br/>{type: "password", value: newPassword}
    Note over B: Log event=keycloak_password_change (INV-239-10)

    alt Politique de complexité non respectée (INV-239-04)
        KC-->>B: 400 (policy violation)
        B-->>C: 400 ERR-239-PWD-POLICY<br/>(message générique, INV-239-07)
    end
    KC-->>B: 204 No Content

    Note over B: Invalidation sessions ≤ 30s (INV-239-05)
    B->>KC: POST /admin/realms/{realm}/users/{id}/logout
    alt Invalidation échouée
        KC-->>B: 5xx
        B-->>C: 500 ERR-239-SESSION-INVALIDATION-FAILED
    end
    KC-->>B: 204 No Content

    B-->>C: 200 {success: true}<br/>(format INV-239-06)

Diagramme d'états — Cycle de vie de la requête de changement

stateDiagram-v2
    [*] --> AuthCheck: POST /user/password/change

    AuthCheck --> ReauthCheck: JWT valide (INV-239-01)
    AuthCheck --> Rejected: JWT invalide

    ReauthCheck --> OldPwdVerify: Reauth token valide (INV-239-02)
    ReauthCheck --> Rejected: Reauth token invalide

    OldPwdVerify --> KeycloakDelegate: Ancien mdp correct (INV-239-03)
    OldPwdVerify --> Rejected: Ancien mdp invalide

    KeycloakDelegate --> SessionInvalidation: Changement OK (INV-239-08)
    KeycloakDelegate --> Rejected: Politique non conforme (INV-239-04)

    SessionInvalidation --> Success: Sessions invalidées (INV-239-05)
    SessionInvalidation --> PartialFailure: Invalidation échouée

    Rejected --> [*]
    Success --> [*]
    PartialFailure --> [*]

6. Cas d'erreur

Code erreur Condition Comportement attendu
ERR-239-UNAUTHENTICATED JWT absent/invalide Refus explicite ; aucune opération effectuée.
ERR-239-UNAUTHORIZED-REAUTH Reauth token absent/invalide/expiré Refus explicite ; aucune opération effectuée.
ERR-239-PWD-INVALID Ancien mot de passe invalide Message exploitable ; aucune modification.
ERR-239-PWD-POLICY Nouveau mot de passe non conforme Message exploitable ; aucune modification.
ERR-239-SESSION-INVALIDATION-FAILED Invalidation sessions échouée après changement Message explicite ; changement déjà effectué.
ERR-239-INTERNAL Erreur interne non métier Refus explicite ; aucun succès affiché.

Normalisation des erreurs Keycloak en ERR-239-* : - Erreur Keycloak 400 (politique/validation) → ERR-239-PWD-POLICY - Erreur Keycloak 401/403 (reauth invalide) → ERR-239-UNAUTHORIZED-REAUTH - Erreur Keycloak 404 (utilisateur introuvable) → ERR-239-PWD-INVALID - Erreur Keycloak 5xx → ERR-239-INTERNAL

Motif de politique de complexité : le message associé à ERR-239-PWD-POLICY DOIT être générique et ne pas exposer le détail de la règle (ex : « Le mot de passe ne respecte pas la politique de complexité »).

7. Critères d'acceptation (testables)

ID Critère Observable
CA-239-01 POST /user/password/change sans JWT est refusé. Réponse d'erreur auth.
CA-239-02 POST /user/password/change sans reauth token est refusé. Réponse d'erreur reauth.
CA-239-03 L'ancien mot de passe invalide est refusé avec motif exploitable. Code ERR-239-PWD-INVALID.
CA-239-04 Nouveau mot de passe non conforme est refusé avec motif exploitable. Code ERR-239-PWD-POLICY.
CA-239-05 En succès, toutes les sessions sont invalidées. Rejet d'un token précédent.
CA-239-06 Format d'erreur {error, message} respecté. Inspection réponse JSON.
CA-239-07 Les refus serveur renvoient un motif exploitable. Présence message actionnable.
CA-239-08 HORS PÉRIMÈTRE PD‑239 : preuve RGPD exhaustive via artefact externe. Présence artefact externe.
CA-239-09 La délégation Keycloak est prouvable par présence du log event=keycloak_password_change. Log structuré observable.

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

Scenario 1 — Changement de mot de passe nominal

GIVEN utilisateur authentifié avec JWT valide et reauth token valide. WHEN POST /user/password/change avec ancien mot de passe correct et nouveau mot de passe conforme. THEN le changement est effectué et toutes les sessions sont invalidées.

Scenario 2 — Rejet sans JWT

GIVEN aucun JWT valide. WHEN POST /user/password/change. THEN refus explicite (ERR-239-UNAUTHENTICATED).

Scenario 3 — Rejet sans reauth token

GIVEN JWT valide, reauth token absent. WHEN POST /user/password/change. THEN refus explicite (ERR-239-UNAUTHORIZED-REAUTH).

Scenario 4 — Ancien mot de passe invalide

GIVEN JWT valide, reauth token valide. WHEN POST /user/password/change avec ancien mot de passe invalide. THEN refus explicite (ERR-239-PWD-INVALID) et aucune modification.

Scenario 5 — Nouveau mot de passe non conforme

GIVEN JWT valide, reauth token valide. WHEN POST /user/password/change avec nouveau mot de passe non conforme. THEN refus explicite (ERR-239-PWD-POLICY) et aucune modification.

Scenario 6 — Format d'erreur

GIVEN condition d'erreur. WHEN l'API renvoie une erreur. THEN le format {error, message} est respecté.

Scenario 7 — Invalidations des sessions échoue

GIVEN changement effectué. WHEN l'invalidation des sessions échoue. THEN ERR-239-SESSION-INVALIDATION-FAILED est retourné et le changement n'est pas annulé.

Scenario 8 — Hors périmètre RGPD

GIVEN périmètre PD‑239. WHEN preuve RGPD exhaustive demandée. THEN référence artefact externe.

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-239-01 Keycloak Admin API permet le changement de mot de passe. Endpoint inopérant.
H-239-02 Le backend peut valider le reauth token PD‑238. Opération non sécurisable.
H-239-03 La politique de complexité Keycloak est accessible/renvoyée en erreur exploitable. CA-239-04 non atteignable.
H-239-04 Le backend peut invalider toutes les sessions utilisateur. INV-239-05 non garanti.
H-239-05 L'artefact RGPD est géré hors PD‑239. CA-239-08 non démontrable.

10. Points à clarifier

Format d’erreurs Keycloak normalisé selon la section 6. Invalidation des sessions via Keycloak Admin API : POST /admin/realms/{realm}/users/{id}/logout avec prise d’effet ≤ 30 secondes. Motif de refus de politique de complexité : message générique, non détaillant la règle.

11. Contrat API

  • Endpoint : POST /user/password/change
  • Headers requis :
  • Authorization: Bearer <JWT>
  • X-Reauth-Token: <reauth_token>
  • Body JSON :
  • { "oldPassword": string, "newPassword": string }
  • Note : le champ confirmation n'est PAS attendu côté backend (validation client uniquement).
  • Réponse succès :
  • 200 OK avec { "success": true }
  • Réponses erreur :
  • 401 (ERR-239-UNAUTHENTICATED, ERR-239-UNAUTHORIZED-REAUTH)
  • 400 (ERR-239-PWD-INVALID, ERR-239-PWD-POLICY)
  • 500 (ERR-239-INTERNAL, ERR-239-SESSION-INVALIDATION-FAILED)

Références

Epic : PD-182 AUTH JIRA : PD-239 Repos concernés : ProbatioVault-backend Documents associés : PD-106-specification.md (F‑106‑05, INV‑106‑12, CA‑106‑11/12), PD‑238 (reauth)