Merge pull request #10 from tips-of-mine/fix/functional-perimeter-creation

Fix/functional perimeter creation
This commit is contained in:
tips-of-mine
2025-06-15 19:41:34 +02:00
committed by GitHub
7 changed files with 137 additions and 18 deletions

View File

@ -133,9 +133,38 @@ class CertificateController
}
$functionalPerimeterName = $perimeter['name'];
// Préparer la commande du script shell
// Important: utiliser escapeshellarg pour protéger les arguments
$command = escapeshellcmd(SCRIPTS_PATH . '/create_cert.sh') . ' ' .
// Extraire ROOT_DOMAIN du certificat CA racine pour SAN et OCSP
$rootCaCertPath = ROOT_CA_PATH . '/certs/ca.cert.pem';
if (!file_exists($rootCaCertPath)) {
$this->logService->log('error', "Certificat CA racine non trouvé pour extraction ROOT_DOMAIN lors de la création de cert feuille.", $userId, $ipAddress);
$_SESSION['error'] = $this->langService->__('cert_create_error_root_cert_missing'); // Needs this translation key
header('Location: /certificates/create');
exit();
}
$subjectCommand = "openssl x509 -noout -subject -in " . escapeshellarg($rootCaCertPath);
$subjectLine = shell_exec($subjectCommand);
$rootDomain = null;
if ($subjectLine && preg_match('/CN\s*=\s*ca\.([^\/,\s]+)/', $subjectLine, $matches)) {
$rootDomain = $matches[1];
}
if (empty($rootDomain)) {
$this->logService->log('error', "Impossible d'extraire ROOT_DOMAIN du cert CA racine (pour SAN). Regex: '/CN\s*=\s*ca\.([^\/,\s]+)/' Sujet: " . ($subjectLine ?: 'vide'), $userId, $ipAddress);
$_SESSION['error'] = $this->langService->__('cert_create_error_root_domain_extraction'); // Needs this translation key
header('Location: /certificates/create');
exit();
}
$this->logService->log('info', "ROOT_DOMAIN extrait pour SAN/OCSP: $rootDomain", $userId, $ipAddress);
// Construire la valeur SAN
$sanValue = "DNS:" . $subdomainName . "." . $functionalPerimeterName . "." . $rootDomain;
// Récupérer OCSP_URL
$ocspUrl = OCSP_URL; // Constante de app/src/config/app.php
// Préparer la commande du script shell avec les variables d'environnement
$scriptPath = SCRIPTS_PATH . '/create_cert.sh';
$command = "OCSP_URL=" . escapeshellarg($ocspUrl) . " SAN=" . escapeshellarg($sanValue) . " " .
escapeshellcmd($scriptPath) . ' ' .
escapeshellarg($subdomainName) . ' ' .
escapeshellarg($functionalPerimeterName);
@ -144,8 +173,11 @@ class CertificateController
// Exécuter le script shell
$output = shell_exec($command . ' 2>&1'); // Redirige stderr vers stdout
// Vérifier le résultat du script (simple vérification de chaîne, une meilleure parsage serait utile)
if (strpos($output, "Certificat '${subdomainName}.${functionalPerimeterName}.cert' créé avec succès") !== false) {
// Vérifier le résultat du script
// Le script create_cert.sh sort "Certificat '$CERT_BASE_NAME' créé avec succès : $CERT_FILE"
// où $CERT_BASE_NAME est "${SUBDOMAIN_OR_CN_NAME}.${FUNCTIONAL_PERIMETER_NAME}"
$certBaseNameForCheck = $subdomainName . '.' . $functionalPerimeterName;
if (strpos($output, "Certificat '" . $certBaseNameForCheck . "' créé avec succès :") !== false) {
// Extraire la date d'expiration du certificat créé (en lisant le fichier cert ou en estimant 1 an)
$certFileName = "{$subdomainName}.{$functionalPerimeterName}.cert.pem";
$fullCertPath = INTERMEDIATE_CA_PATH_BASE . "/{$functionalPerimeterName}/certs/{$certFileName}";

View File

@ -89,6 +89,10 @@ class PerimeterController
$perimeterName = trim($_POST['name'] ?? '');
$ipAddress = $_SERVER['REMOTE_ADDR'];
$userId = $this->authService->getUserId();
// La passphrase est optionnelle pour l'intermédiaire, mais le script attend l'argument.
// Le script create_intermediate_cert.sh a été modifié pour accepter "EMPTY_STRING"
// si aucune passphrase n'est fournie.
$passphrase = trim($_POST['intermediate_passphrase'] ?? ''); // Assumons que cela vient du formulaire
if (empty($perimeterName)) {
$_SESSION['error'] = $this->langService->__('perimeter_create_error_empty_name');
@ -105,14 +109,58 @@ class PerimeterController
exit();
}
// Extraire ROOT_DOMAIN du certificat CA racine
$rootCaCertPath = ROOT_CA_PATH . '/certs/ca.cert.pem';
$rootDomain = null;
if (!file_exists($rootCaCertPath)) {
$this->logService->log('error', "Certificat CA racine non trouvé à: $rootCaCertPath", $userId, $ipAddress);
$_SESSION['error'] = $this->langService->__('perimeter_create_error_root_cert_missing'); // Nouvelle clé de traduction
header('Location: /perimeters/create');
exit();
}
$subjectCommand = "openssl x509 -noout -subject -in " . escapeshellarg($rootCaCertPath);
$subjectLine = shell_exec($subjectCommand);
if ($subjectLine && preg_match('/CN\s*=\s*ca\.([^\/,\s]+)/', $subjectLine, $matches)) {
$rootDomain = $matches[1];
}
if (empty($rootDomain)) {
$this->logService->log('error', "Impossible d'extraire ROOT_DOMAIN du certificat CA racine. Regex: '/CN\s*=\s*ca\.([^\/,\s]+)/' Sujet obtenu: " . ($subjectLine ?: 'vide ou non recupere'), $userId, $ipAddress);
$_SESSION['error'] = $this->langService->__('perimeter_create_error_root_domain'); // Clé de traduction existante ou à ajouter
header('Location: /perimeters/create');
exit();
}
$this->logService->log('info', "ROOT_DOMAIN extrait avec succès: $rootDomain", $userId, $ipAddress);
// Appeler le script shell pour créer le certificat intermédiaire
$command = escapeshellcmd(SCRIPTS_PATH . '/create_intermediate_cert.sh') . ' ' . escapeshellarg($perimeterName);
// Retrieve OCSP_URL from defined constant
$ocspUrl = OCSP_URL; // This constant is defined in app/src/config/app.php
$sanValue = ''; // SAN is not typically needed for an intermediate CA, set to empty
$passphraseArg = !empty($passphrase) ? $passphrase : "EMPTY_STRING";
// Construct the shell command with environment variables
// Note: escapeshellcmd is applied to the script path.
// Environment variable values should also be safe.
// Using escapeshellarg for values assigned to env vars is a good practice.
$scriptPath = SCRIPTS_PATH . '/create_intermediate_cert.sh';
$command = "OCSP_URL=" . escapeshellarg($ocspUrl) . " SAN=" . escapeshellarg($sanValue) . " " .
escapeshellcmd($scriptPath) . ' ' .
escapeshellarg($perimeterName) . ' ' .
escapeshellarg($passphraseArg) . ' ' .
escapeshellarg($rootDomain);
$this->logService->log('info', "Tentative de création du périmètre '$perimeterName' et de son certificat intermédiaire. Commande: '$command'", $userId, $ipAddress);
$output = shell_exec($command . ' 2>&1');
if (strpos($output, "Certificat Intermédiaire CA pour '$perimeterName' créé avec succès") !== false) {
// La condition de succès doit correspondre à la sortie du script.
// Le script create_intermediate_cert.sh se termine par :
// echo "Certificat Intermédiaire CA pour '$FUNCTIONAL_PERIMETER_NAME' créé : $INTERMEDIATE_CERT"
// Nous allons donc chercher une partie de cette chaîne.
if (strpos($output, "Certificat Intermédiaire CA pour '$perimeterName' créé") !== false) {
// Enregistrer le périmètre dans la base de données
$stmt = $this->db->prepare("INSERT INTO functional_perimeters (name, intermediate_cert_name) VALUES (?, ?)");
$intermediateCertFileName = "intermediate.cert.pem"; // Nom générique du fichier pour l'intermédiaire