Files
geo/api/docs/FIX_USER_CREATION_400_ERRORS.md
Pierre 0687900564 fix: Récupérer l'opération active depuis la table operations
- Corrige l'erreur SQL 'Unknown column fk_operation in users'
- L'opération active est récupérée depuis operations.chk_active = 1
- Jointure avec users pour filtrer par entité de l'admin créateur
- Query: SELECT o.id FROM operations o INNER JOIN users u ON u.fk_entite = o.fk_entite WHERE u.id = ? AND o.chk_active = 1
2026-01-26 16:57:08 +01:00

5.6 KiB
Executable File

Correction des erreurs 400 lors de la création d'utilisateurs

Problème identifié

Un administrateur (fk_role=2) rencontrait des erreurs 400 répétées lors de tentatives de création de membre, menant à un bannissement par fail2ban :

  • 17:09:39 - POST /api/users HTTP/1.1 400 (Bad Request)
  • 17:10:44 - POST /api/users/check-username HTTP/1.1 400 (Bad Request)
  • 17:11:21 - POST /api/users HTTP/1.1 400 (Bad Request)

Causes identifiées

1. Conflit de routage (CRITIQUE)

Problème: La route /api/users/check-username était déclarée APRÈS la route générique /api/users dans Router.php, causant une mauvaise interprétation où "check-username" était traité comme un ID utilisateur.

Solution: Déplacer la déclaration de la route spécifique AVANT les routes avec paramètres.

2. Messages d'erreur non informatifs

Problème: Les erreurs 400 retournaient des messages génériques sans détails sur le champ problématique.

Solution: Ajout de messages d'erreur détaillés incluant :

  • Le champ en erreur (field)
  • La valeur problématique (value)
  • Le format attendu (format)
  • La raison de l'erreur (reason)

3. Manque de logs de débogage

Problème: Aucun log n'était généré pour tracer les erreurs de validation.

Solution: Ajout de logs détaillés à chaque point de validation.

Modifications apportées

1. Router.php (ligne 36-44)

// AVANT (incorrect)
$this->post('users', ['UserController', 'createUser']);
$this->post('users/check-username', ['UserController', 'checkUsername']);

// APRÈS (correct)
$this->post('users/check-username', ['UserController', 'checkUsername']);  // Route spécifique en premier
$this->post('users', ['UserController', 'createUser']);

2. UserController.php - Amélioration des validations

Validation de l'email

// Réponse améliorée
Response::json([
    'status' => 'error',
    'message' => 'Email requis',
    'field' => 'email'  // Indique clairement le champ problématique
], 400);

Validation du username manuel

// Réponse améliorée
Response::json([
    'status' => 'error',
    'message' => 'Le nom d\'utilisateur est requis pour cette entité',
    'field' => 'username',
    'reason' => 'L\'entité requiert la saisie manuelle des identifiants'
], 400);

Format du username

// Réponse améliorée
Response::json([
    'status' => 'error',
    'message' => 'Format du nom d\'utilisateur invalide',
    'field' => 'username',
    'format' => '10-30 caractères, commence par une lettre, caractères autorisés: a-z, 0-9, ., -, _',
    'value' => $username  // Montre la valeur soumise
], 400);

3. Ajout de logs détaillés

Chaque point de validation génère maintenant un log avec :

  • Le type d'erreur
  • L'utilisateur qui fait la requête
  • Les données reçues (sans données sensibles)
  • Le contexte de l'erreur

Exemple :

LogService::log('Erreur création utilisateur : Format username invalide', [
    'level' => 'warning',
    'createdBy' => $currentUserId,
    'email' => $email,
    'username' => $username,
    'username_length' => strlen($username)
]);

Cas d'erreur 400 possibles

Pour /api/users (création)

  1. Email manquant ou vide

    • Message: "Email requis"
    • Field: "email"
  2. Nom manquant ou vide

    • Message: "Nom requis"
    • Field: "name"
  3. Format email invalide

    • Message: "Format d'email invalide"
    • Field: "email"
    • Value: [email soumis]
  4. Username manuel requis mais manquant (si chk_username_manuel=1)

    • Message: "Le nom d'utilisateur est requis pour cette entité"
    • Field: "username"
    • Reason: "L'entité requiert la saisie manuelle des identifiants"
  5. Format username invalide

    • Message: "Format du nom d'utilisateur invalide"
    • Field: "username"
    • Format: "10-30 caractères, commence par une lettre..."
    • Value: [username soumis]
  6. Mot de passe manuel requis mais manquant (si chk_mdp_manuel=1)

    • Message: "Le mot de passe est requis pour cette entité"
    • Field: "password"
    • Reason: "L'entité requiert la saisie manuelle des mots de passe"

Pour /api/users/check-username

  1. Username manquant

    • Message: "Username requis pour la vérification"
    • Field: "username"
  2. Format username invalide

    • Message: "Format invalide"
    • Field: "username"
    • Format: "10-30 caractères, commence par une lettre..."
    • Value: [username soumis]

Test de la solution

Un script de test a été créé : /tests/test_user_creation.php

Il teste tous les cas d'erreur possibles et vérifie que :

  1. Les codes HTTP sont corrects
  2. Les messages d'erreur sont informatifs
  3. Les champs en erreur sont identifiés

Recommandations pour éviter le bannissement fail2ban

  1. Côté client (application Flutter) :

    • Valider les données AVANT l'envoi
    • Afficher clairement les erreurs à l'utilisateur
    • Implémenter un délai entre les tentatives (rate limiting côté client)
  2. Côté API :

    • Les messages d'erreur détaillés permettent maintenant de corriger rapidement les problèmes
    • Les logs permettent de diagnostiquer les problèmes récurrents
  3. Configuration fail2ban :

    • Considérer d'augmenter le seuil pour les erreurs 400 (ex: 5 tentatives au lieu de 3)
    • Exclure certaines IP de confiance si nécessaire

Suivi des logs

Les logs sont maintenant générés dans :

  • /logs/geosector-[environment]-[date].log : Logs généraux avec détails des erreurs

Format des logs :

timestamp;browser;os;client_type;level;metadata;message

Les erreurs de validation sont loggées avec le niveau "warning" pour permettre un suivi sans être critiques.