Files
xamxam/public/admin/login.php
Théophile Gervreau-Mercier 8613f71112 security: add PHP session auth guard for admin panel (item #2, CRITICAL)
- lib/AdminAuth.php: new class with requireLogin(), login(), logout(),
  isAuthenticated(); starts session with hardened cookie params
  (HttpOnly, SameSite=Strict, Secure, Path=/admin) — also resolves
  item #8 (session cookie hardening)
- requireLogin() auto-authenticates from nginx Basic Auth credentials
  ($_SERVER['PHP_AUTH_PW']) so the user only sees one browser prompt;
  falls back to /admin/login.php if the proxy is absent/misconfigured
- config/admin_credentials.php: gitignored credential store; define
  ADMIN_PASSWORD_HASH with a bcrypt hash to enable PHP auth
- config/admin_credentials.example.php: template for the above
- config/bootstrap.php: auto-loads admin_credentials.php if present
- .gitignore: exclude config/admin_credentials.php
- public/admin/login.php: fallback login form (shown only when nginx
  Basic Auth is bypassed / proxy absent)
- public/admin/logout.php: session destruction + redirect to login
- All 7 admin PHP files: replace session_start() with
  AdminAuth::requireLogin() (defence-in-depth behind nginx Basic Auth)
- public/admin/inc/head.php: Déconnexion button when ADMIN_PASSWORD_HASH
  is defined
- nginx/PHP_AUTH_LAYER.md: documents dual-auth architecture, UX flow,
  and setup instructions
- docs/TODO.SECURITY.md: items #2 and #8 moved to Resolved; priority
  order updated (all CRITICAL done)
2026-02-08 14:22:45 +01:00

61 lines
1.8 KiB
PHP

<?php
require_once __DIR__ . '/../../config/bootstrap.php';
require_once __DIR__ . '/../../lib/AdminAuth.php';
// If no password is configured, nothing to log into — go straight to admin.
if (!defined('ADMIN_PASSWORD_HASH')) {
header('Location: /admin/');
exit;
}
// Already authenticated — redirect to admin.
if (AdminAuth::isAuthenticated()) {
header('Location: /admin/');
exit;
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$password = $_POST['password'] ?? '';
if (AdminAuth::login($password)) {
header('Location: /admin/');
exit;
}
// Intentionally vague error — avoid user-enumeration.
$error = 'Mot de passe incorrect.';
}
$pageTitle = 'Connexion';
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($pageTitle); ?> — Post-ERG Admin</title>
<link rel="stylesheet" href="/assets/modern-normalize.min.css">
<link rel="stylesheet" href="/assets/admin.css">
<link rel="shortcut icon" href="/assets/admin_favicon.svg" type="image/svg+xml">
</head>
<body>
<header>
<h1><?php echo htmlspecialchars($pageTitle); ?></h1>
</header>
<main>
<?php if ($error): ?>
<div class="alert-error">
<strong>⚠️ <?php echo htmlspecialchars($error); ?></strong>
</div>
<?php endif; ?>
<form method="post" action="/admin/login.php">
<fieldset>
<legend>Authentification admin</legend>
<label for="password">Mot de passe</label>
<input type="password" id="password" name="password" required autofocus>
<button type="submit">Se connecter</button>
</fieldset>
</form>
</main>
</body>
</html>