diff --git a/aspic.php b/aspic.php index 8b5e354..1cd2062 100644 --- a/aspic.php +++ b/aspic.php @@ -1,17 +1,24 @@ false, 'error' => 'Connexion base de données impossible']); + echo json_encode(['success' => false, 'error' => 'Connexion à MIRADOR impossible']); exit; } -// USR_Code est un code court (3 caractères) conventionnellement saisi en -// majuscules ; comparaison insensible à la casse sur l'identifiant, comme -// dans le prototype front (voir ASPIC_ecran_identification.html, -// trouverUtilisateurDemo). Le mot de passe, lui, reste comparé strictement -// (sensible à la casse). -$stmt = $pdo->prepare('SELECT USR_Code, USR_Nom, USR_MDP FROM ASP_Users WHERE UPPER(USR_Code) = UPPER(?)'); +// Comparaison directe sur l'email : la collation utf8mb4_0900_ai_ci déjà en +// place sur MIRADOR (comme sur les autres bases ASPIC) est nativement +// insensible à la casse et aux accents, pas besoin d'UPPER() ici. +$stmt = $pdoRouter->prepare( + 'SELECT MIR_Code, MIR_MDPHash, MIR_ServeurHost, MIR_ServeurPort, MIR_BaseNom + FROM MIR_Users WHERE MIR_Email = ? AND MIR_Actif = 1' +); $stmt->execute([$identifiant]); -$user = $stmt->fetch(); +$routage = $stmt->fetch(); -// hash_equals() plutôt que === : comparaison en temps constant, pour ne pas -// laisser une attaque par mesure de timing déduire des informations sur le -// mot de passe stocké. Mot de passe en clair (USR_MDP) assumé consciemment -// pour cette application interne (voir journal section 2) — cette précaution -// est un geste peu coûteux, pas une garantie de sécurité forte sur ce point. -if (!$user || !hash_equals($user['USR_MDP'], $motdepasse)) { +// Hash factice comparé même quand l'email est inconnu (password_verify() +// tourne alors quand même) : évite qu'une différence de temps de réponse +// laisse deviner qu'une adresse n'existe pas dans MIRADOR. Valeur sans +// signification, générée une fois pour toutes, jamais utilisée comme vrai +// mot de passe. +const HASH_FACTICE = '$2y$12$wni9cLq0BKttPzU0xAPM9uX/HMzu9UJhlOMj32H6/wLmkjlNfZ1cm'; +$hashAVerifier = $routage['MIR_MDPHash'] ?? HASH_FACTICE; + +if (!$routage || !password_verify($motdepasse, $hashAVerifier)) { // Message volontairement générique : ne pas révéler si c'est l'identifiant // ou le mot de passe qui est en cause. Le compteur d'essais / la sortie au // 3e échec sont gérés côté front, pas ici (voir en-tête de ce fichier). @@ -79,15 +94,37 @@ if (!$user || !hash_equals($user['USR_MDP'], $motdepasse)) { exit; } -// Session ouverte : les endpoints suivants (contacts.php, professions.php, -// statuts.php, realisations.php) exigent désormais $_SESSION['USR_Code'] -// (voir journal, section 15). -$_SESSION['USR_Code'] = $user['USR_Code']; +// Coordonnées de la base de travail propre à cet utilisateur : posées en +// session pour que getDbConnection() (db.php) route tous les prochains +// appels de CETTE session vers la bonne base, sans qu'il faille les +// repasser en paramètre à chaque endpoint. +$_SESSION['USR_Code'] = $routage['MIR_Code']; +$_SESSION['ASPIC_DB_HOST'] = $routage['MIR_ServeurHost']; +$_SESSION['ASPIC_DB_PORT'] = (int) $routage['MIR_ServeurPort']; +$_SESSION['ASPIC_DB_NAME'] = $routage['MIR_BaseNom']; + +// Nom affiché : toujours porté par ASP_Users de la base cible (MIRADOR ne +// connaît que l'email/code/mot de passe/routage, pas le nom complet). Un +// échec de connexion à cette base cible est remonté explicitement — plutôt +// que de laisser entrer un utilisateur dans une base injoignable, ce qui +// ferait échouer silencieusement tous les écrans suivants. +try { + $pdoCible = getDbConnection(); +} catch (PDOException $e) { + session_unset(); + http_response_code(500); + echo json_encode(['success' => false, 'error' => 'Connexion à la base de travail impossible']); + exit; +} + +$stmtNom = $pdoCible->prepare('SELECT USR_Nom FROM ASP_Users WHERE USR_Code = ?'); +$stmtNom->execute([$routage['MIR_Code']]); +$nom = $stmtNom->fetchColumn(); echo json_encode([ 'success' => true, 'user' => [ - 'USR_Code' => $user['USR_Code'], - 'USR_Nom' => $user['USR_Nom'], + 'USR_Code' => $routage['MIR_Code'], + 'USR_Nom' => $nom !== false ? $nom : null, ], ]); diff --git a/db.php b/db.php index 31aa4c2..f5f2b03 100644 --- a/db.php +++ b/db.php @@ -1,12 +1,39 @@ PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, @@ -14,3 +41,37 @@ function getDbConnection(): PDO return new PDO($dsn, $user, $pass, $options); } + +function getDbConnection(): PDO +{ + // Routage dynamique posé par aspic.php à l'identification (MIRADOR) : + // prioritaire dès qu'une session valide le porte. + if (session_status() === PHP_SESSION_ACTIVE && !empty($_SESSION['ASPIC_DB_HOST'])) { + return ouvrirConnexionPdo( + $_SESSION['ASPIC_DB_HOST'], + $_SESSION['ASPIC_DB_NAME'], + getenv('DB_USER') ?: 'crm_user', + getenv('DB_PASS') ?: '', + (int) ($_SESSION['ASPIC_DB_PORT'] ?? 3306) + ); + } + + // Repli : base par défaut du conteneur, inchangé depuis avant MIRADOR — + // utilisé par les scripts publics sans session (prospection). + $host = getenv('DB_HOST') ?: 'mysql'; + $db = getenv('DB_NAME') ?: 'crm'; + $user = getenv('DB_USER') ?: 'crm_user'; + $pass = getenv('DB_PASS') ?: ''; + + return ouvrirConnexionPdo($host, $db, $user, $pass); +} + +function getRouterConnection(): PDO +{ + $host = getenv('ROUTER_DB_HOST') ?: 'mysql2'; + $db = getenv('ROUTER_DB_NAME') ?: 'MIRADOR'; + $user = getenv('ROUTER_DB_USER') ?: 'crm_user'; + $pass = getenv('ROUTER_DB_PASS') ?: ''; + + return ouvrirConnexionPdo($host, $db, $user, $pass); +} diff --git a/identification.html b/identification.html index b8071a4..7bc6670 100644 --- a/identification.html +++ b/identification.html @@ -383,7 +383,7 @@