161 lines
5.1 KiB
PHP
161 lines
5.1 KiB
PHP
<?php
|
|
/**
|
|
* Keycloak SSO Callback - Handles the return from Keycloak authentication
|
|
*
|
|
* This file processes the OAuth2 callback, validates the user, and creates Vvveb session
|
|
*
|
|
* Direct access: /admin/keycloak-callback.php
|
|
* Or via routing: /admin/index.php?module=keycloak/callback
|
|
*/
|
|
|
|
// Suppress deprecation warnings from jumbojett library (PHP 8.5 compatibility)
|
|
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
|
|
|
|
// Prevent output buffering issues
|
|
if (ob_get_level()) {
|
|
ob_clean();
|
|
}
|
|
|
|
// Bootstrap Vvveb in admin mode
|
|
define('APP', 'admin');
|
|
define('DS', DIRECTORY_SEPARATOR);
|
|
define('DIR_ROOT', dirname(__DIR__) . DS);
|
|
define('DIR_SYSTEM', DIR_ROOT . 'system' . DS);
|
|
|
|
// Load environment
|
|
require_once DIR_ROOT . 'env.php';
|
|
|
|
// Load Vvveb bootstrap (autoload, functions, etc.)
|
|
// IMPORTANT: We do NOT call System\Core\start() here to avoid full front controller
|
|
require_once DIR_SYSTEM . 'core/startup.php';
|
|
|
|
// Load Composer autoload for Keycloak library
|
|
require_once DIR_ROOT . 'vendor/autoload.php';
|
|
|
|
use Jumbojett\OpenIDConnectClient;
|
|
use Vvveb\System\User\Admin;
|
|
use Vvveb\System\Session as VSession;
|
|
|
|
// Start PHP session for OpenIDConnectClient library
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
// Configuration Keycloak - MUST match keycloak-login.php
|
|
$keycloakUrl = 'https://connect.slm-lab.net/realms/cercle';
|
|
$keycloakClient = 'page.slm-lab.net';
|
|
$keycloakSecret = 'IGFw1QWDs9xQ7OyRp6YM8VRgQxn09tFF';
|
|
|
|
// Redirect URL - MUST match exactly the one configured in Keycloak
|
|
$redirectUrl = 'https://www.slm-lab.net/admin/index.php?page=keycloak-callback';
|
|
|
|
try {
|
|
// Create OpenID Connect client
|
|
$oidc = new OpenIDConnectClient(
|
|
$keycloakUrl,
|
|
$keycloakClient,
|
|
$keycloakSecret
|
|
);
|
|
|
|
$oidc->setRedirectURL($redirectUrl);
|
|
$oidc->addScope(['openid', 'profile', 'email']);
|
|
|
|
// Complete the OAuth2 flow (exchange code for tokens)
|
|
$oidc->authenticate();
|
|
|
|
// Get user information from Keycloak
|
|
$userInfo = $oidc->requestUserInfo();
|
|
|
|
// Extract email from Keycloak response
|
|
$email = $userInfo->email ?? null;
|
|
|
|
if (!$email) {
|
|
throw new \Exception('Keycloak did not return an email address.');
|
|
}
|
|
|
|
// Find admin user in Vvveb database using Vvveb API
|
|
// Only get active admins (status = 1)
|
|
$adminInfo = Admin::get([
|
|
'email' => $email,
|
|
'status' => 1,
|
|
]);
|
|
|
|
if (!$adminInfo) {
|
|
// User not found or not active
|
|
http_response_code(403);
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Access Denied</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; padding: 40px; text-align: center; }
|
|
.error { color: #d32f2f; background: #ffebee; padding: 20px; border-radius: 4px; margin: 20px auto; max-width: 600px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Access Denied</h1>
|
|
<div class="error">
|
|
<p>The email <strong><?php echo htmlspecialchars($email, ENT_QUOTES, 'UTF-8'); ?></strong> is not registered as an active admin in Vvveb.</p>
|
|
<p>Please contact your administrator to grant access.</p>
|
|
</div>
|
|
<p><a href="/admin/index.php?module=user/login">Return to login page</a></p>
|
|
</body>
|
|
</html>
|
|
<?php
|
|
exit;
|
|
}
|
|
|
|
// Create Vvveb admin session (same way Admin::login() does it)
|
|
$session = VSession::getInstance();
|
|
$session->regenerateId(true);
|
|
|
|
// Remove password hash from session data
|
|
if (isset($adminInfo['password'])) {
|
|
unset($adminInfo['password']);
|
|
}
|
|
|
|
// Optionally store Keycloak user info for reference
|
|
// $adminInfo['keycloak_sub'] = $userInfo->sub ?? null;
|
|
// $adminInfo['keycloak_username'] = $userInfo->preferred_username ?? null;
|
|
|
|
// Set admin session (namespace 'admin' is used by Vvveb\System\User\Admin)
|
|
$session->set('admin', $adminInfo);
|
|
|
|
// Redirect to admin dashboard
|
|
// Use adminPath() helper if available, otherwise hardcode
|
|
$adminPath = \Vvveb\adminPath() ?: '/admin/';
|
|
header('Location: ' . $adminPath . 'index.php');
|
|
exit;
|
|
|
|
} catch (\Exception $e) {
|
|
// Log error (if logging is available)
|
|
if (function_exists('error_log')) {
|
|
error_log('Keycloak SSO Error: ' . $e->getMessage());
|
|
}
|
|
|
|
// Show error page
|
|
http_response_code(500);
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Authentication Error</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; padding: 40px; text-align: center; }
|
|
.error { color: #d32f2f; background: #ffebee; padding: 20px; border-radius: 4px; margin: 20px auto; max-width: 600px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Authentication Error</h1>
|
|
<div class="error">
|
|
<p><strong>Keycloak authentication failed:</strong></p>
|
|
<p><?php echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'); ?></p>
|
|
</div>
|
|
<p><a href="/admin/index.php?module=user/login">Return to login page</a></p>
|
|
</body>
|
|
</html>
|
|
<?php
|
|
exit;
|
|
}
|