From 984fd05b7083071622603a6b9d4c90337f1452cb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 15 Jun 2025 17:49:37 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Fix:=20Aligner=20les=20boutons=20de=20t?= =?UTF-8?q?=C3=A9l=C3=A9chargement=20du=20certificat=20racine=20sur=20le?= =?UTF-8?q?=20Dashboard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les boutons "Download Certificate (.pem)" et "Download Private Key (.key)" pour le certificat racine dans la page Dashboard étaient affichés sur des lignes séparées. Cette modification les place sur la même ligne en les regroupant dans un unique élément
et ajoute une petite marge à gauche du second bouton pour une meilleure séparation visuelle. Ceci améliore l'interface utilisateur en rendant la section plus compacte et lisible. --- app/src/Views/dashboard/index.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/Views/dashboard/index.php b/app/src/Views/dashboard/index.php index 83fc9f5..54c5eef 100644 --- a/app/src/Views/dashboard/index.php +++ b/app/src/Views/dashboard/index.php @@ -40,9 +40,7 @@ require_once APP_ROOT_DIR . '/src/Views/shared/header.php'; = htmlspecialchars($translations['download_certificate_pem'] ?? 'Download Certificate (.pem)') ?> -
-- + = htmlspecialchars($translations['download_key_pem'] ?? 'Download Private Key (.key)') ?>
From 797267d41e0690473de720195790ebd41cf5c6ab Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 15 Jun 2025 18:01:13 +0000 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20Permettre=20la=20r=C3=A9vocation=20?= =?UTF-8?q?des=20certificats=20interm=C3=A9diaires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente la fonctionnalité de révocation pour les certificats de type 'intermédiaire'. Modifications principales : - CertificateController.php : - Suppression de l'interdiction de révoquer les certificats intermédiaires. - Ajout d'une logique spécifique pour révoquer un certificat intermédiaire en utilisant la configuration et la CRL du CA Racine. - Les certificats 'simple' continuent d'être révoqués via le script revoke_cert.sh. - app/src/Views/certificates/index.php : - Le bouton 'Révoquer' est maintenant affiché pour les certificats intermédiaires non révoqués. - app/src/Lang/fr.json : - Ajout de nouvelles clés de traduction pour les messages relatifs à la révocation des certificats intermédiaires. - Modification de la clé 'cert_revoke_error_ca_revocation' pour indiquer que seuls les certificats ROOT ne peuvent être révoqués via l'interface. Ces modifications permettent une gestion plus complète des certificats intermédiaires directement depuis l'interface utilisateur. --- app/src/Controllers/CertificateController.php | 94 ++++++++++++++----- app/src/Lang/fr.json | 7 +- app/src/Views/certificates/index.php | 4 +- 3 files changed, 78 insertions(+), 27 deletions(-) diff --git a/app/src/Controllers/CertificateController.php b/app/src/Controllers/CertificateController.php index b92b5e9..bbb5b9f 100644 --- a/app/src/Controllers/CertificateController.php +++ b/app/src/Controllers/CertificateController.php @@ -238,16 +238,14 @@ class CertificateController exit(); } - // Empêcher la révocation des certificats Root ou Intermédiaires via l'interface - if ($cert['type'] === 'root' || $cert['type'] === 'intermediate') { - $_SESSION['error'] = $this->langService->__('cert_revoke_error_ca_revocation'); + // Empêcher la révocation des certificats Root via l'interface + if ($cert['type'] === 'root') { + $_SESSION['error'] = $this->langService->__('cert_revoke_error_ca_revocation'); // Peut-être une clé dédiée pour root si le message doit être différent header('Location: /certificates'); exit(); } - // Préparer le nom de base du certificat pour le script (sans l'extension .pem) - $certBaseName = str_replace('.cert.pem', '.cert', $cert['name']); - $functionalPerimeterName = $cert['perimeter_name']; + $functionalPerimeterName = $cert['perimeter_name']; // Déjà récupéré plus haut, mais utile ici aussi // Vérifier si le certificat n'est pas déjà révoqué dans la DB if ($cert['is_revoked']) { @@ -256,29 +254,79 @@ class CertificateController exit(); } - // Appeler le script shell de révocation - $command = escapeshellcmd(SCRIPTS_PATH . '/revoke_cert.sh') . ' ' . - escapeshellarg($certBaseName) . ' ' . - escapeshellarg($functionalPerimeterName); + if ($cert['type'] === 'intermediate') { + // Logique de révocation pour les certificats intermédiaires + $intermediateCertPath = "/opt/tls/intermediate/" . $functionalPerimeterName . "/certs/" . $cert['name']; + $rootCaConfigPath = "/opt/tls/root/openssl.cnf"; // Chemin vers la configuration OpenSSL du CA Racine + $rootCaCrlPath = "/opt/tls/root/crl/crl.pem"; // Chemin vers la CRL du CA Racine - $this->logService->log('info', "Tentative de révocation du certificat '{$cert['name']}' pour le périmètre '$functionalPerimeterName'. Commande: '$command'", $userId, $ipAddress); + // Commande pour révoquer le certificat intermédiaire avec le CA Racine + $revokeCmd = sprintf( + "openssl ca -batch -config %s -revoke %s", + escapeshellarg($rootCaConfigPath), + escapeshellarg($intermediateCertPath) + ); - $output = shell_exec($command . ' 2>&1'); + $this->logService->log('info', "Tentative de révocation du certificat intermédiaire '{$cert['name']}' pour le périmètre '$functionalPerimeterName'. Commande: '$revokeCmd'", $userId, $ipAddress); + $outputRevoke = shell_exec($revokeCmd . ' 2>&1'); - if (strpos($output, "Certificat '$certBaseName' révoqué avec succès.") !== false) { - // Mettre à jour le statut du certificat dans la base de données - $stmt = $this->db->prepare("UPDATE certificates SET is_revoked = TRUE, revoked_at = NOW() WHERE id = ?"); - $stmt->execute([$certificateId]); + if (strpos($outputRevoke, "Data Base Updated") !== false || strpos($outputRevoke, "Successfully revoked certificate") !== false) { + // Commande pour régénérer la CRL du CA Racine + $generateCrlCmd = sprintf( + "openssl ca -batch -config %s -gencrl -out %s", + escapeshellarg($rootCaConfigPath), + escapeshellarg($rootCaCrlPath) + ); + + $this->logService->log('info', "Révocation réussie. Tentative de mise à jour de la CRL du CA Racine. Commande: '$generateCrlCmd'", $userId, $ipAddress); + $outputCrl = shell_exec($generateCrlCmd . ' 2>&1'); + + // Vérifier si la CRL a été générée et si le fichier existe + if ((strpos($outputCrl, "CRL Generated") !== false || strpos($outputCrl, "CRL generated") !== false) && file_exists($rootCaCrlPath)) { + // Mettre à jour le statut du certificat dans la base de données + $stmt_update = $this->db->prepare("UPDATE certificates SET is_revoked = TRUE, revoked_at = NOW() WHERE id = ?"); + $stmt_update->execute([$certificateId]); + + $this->logService->log('info', "Certificat intermédiaire '{$cert['name']}' révoqué et CRL du CA Racine mise à jour.", $userId, $ipAddress); + $_SESSION['success'] = $this->langService->__('cert_revoke_success_intermediate', ['name' => $cert['name']]); + } else { + $this->logService->log('error', "Échec de la mise à jour de la CRL du CA Racine pour le cert intermédiaire '{$cert['name']}'. Output CRL: $outputCrl. Output Revoke: $outputRevoke", $userId, $ipAddress); + $_SESSION['error'] = $this->langService->__('cert_revoke_warn_crl_update_failed_intermediate', ['name' => $cert['name']]); + } + } else { + $_SESSION['error'] = $this->langService->__('cert_revoke_error_intermediate', ['name' => $cert['name'], 'output' => htmlspecialchars($outputRevoke)]); + $this->logService->log('error', "Échec de la révocation du certificat intermédiaire '{$cert['name']}'. Output: $outputRevoke", $userId, $ipAddress); + } + header('Location: /certificates'); + exit(); - $this->logService->log('info', "Certificat '{$cert['name']}' révoqué et enregistré en DB.", $userId, $ipAddress); - $_SESSION['success'] = $this->langService->__('cert_revoke_success'); } else { - $_SESSION['error'] = $this->langService->__('cert_revoke_error', ['output' => htmlspecialchars($output)]); - $this->logService->log('error', "Échec révocation certificat '{$cert['name']}': $output", $userId, $ipAddress); - } + // Logique existante pour les certificats 'simple' + $certBaseName = str_replace('.cert.pem', '.cert', $cert['name']); - header('Location: /certificates'); - exit(); + // Appeler le script shell de révocation + $command = escapeshellcmd(SCRIPTS_PATH . '/revoke_cert.sh') . ' ' . + escapeshellarg($certBaseName) . ' ' . + escapeshellarg($functionalPerimeterName); + + $this->logService->log('info', "Tentative de révocation du certificat simple '{$cert['name']}' pour le périmètre '$functionalPerimeterName'. Commande: '$command'", $userId, $ipAddress); + + $output = shell_exec($command . ' 2>&1'); + + if (strpos($output, "Certificat '$certBaseName' révoqué avec succès.") !== false) { + // Mettre à jour le statut du certificat dans la base de données + $stmt_update = $this->db->prepare("UPDATE certificates SET is_revoked = TRUE, revoked_at = NOW() WHERE id = ?"); + $stmt_update->execute([$certificateId]); + + $this->logService->log('info', "Certificat simple '{$cert['name']}' révoqué et enregistré en DB.", $userId, $ipAddress); + $_SESSION['success'] = $this->langService->__('cert_revoke_success'); + } else { + $_SESSION['error'] = $this->langService->__('cert_revoke_error', ['output' => htmlspecialchars($output)]); + $this->logService->log('error', "Échec révocation certificat simple '{$cert['name']}': $output", $userId, $ipAddress); + } + header('Location: /certificates'); + exit(); + } } /** diff --git a/app/src/Lang/fr.json b/app/src/Lang/fr.json index 203b1bb..d1d0dcc 100644 --- a/app/src/Lang/fr.json +++ b/app/src/Lang/fr.json @@ -61,7 +61,7 @@ "cert_create_error": "Erreur lors de la création du certificat: {output}", "cert_revoke_error_id_missing": "ID du certificat manquant pour la révocation.", "cert_revoke_error_not_found": "Certificat introuvable pour la révocation.", - "cert_revoke_error_ca_revocation": "Les certificats ROOT et INTERMÉDIAIRES ne peuvent pas être révoqués via l'interface pour des raisons de sécurité PKI.", + "cert_revoke_error_ca_revocation": "Les certificats ROOT ne peuvent pas être révoqués via l'interface pour des raisons de sécurité PKI.", "cert_revoke_error_already_revoked": "Ce certificat est déjà révoqué.", "cert_revoke_success": "Certificat révoqué avec succès.", "cert_revoke_error": "Erreur lors de la révocation du certificat: {output}", @@ -80,5 +80,8 @@ "user_delete_success": "Utilisateur '{username}' supprimé avec succès.", "user_delete_error_not_found": "Utilisateur introuvable pour la suppression.", "user_delete_error_db": "Erreur lors de la suppression de l'utilisateur dans la base de données.", - "self_delete_not_allowed": "Vous ne pouvez pas vous supprimer vous-même." + "self_delete_not_allowed": "Vous ne pouvez pas vous supprimer vous-même.", + "cert_revoke_success_intermediate": "Le certificat intermédiaire '{name}' a été révoqué avec succès et la CRL du CA Racine a été mise à jour.", + "cert_revoke_warn_crl_update_failed_intermediate": "Le certificat intermédiaire '{name}' a été révoqué, mais la mise à jour de la CRL du CA Racine a rencontré un problème. Veuillez contacter un administrateur.", + "cert_revoke_error_intermediate": "Erreur lors de la révocation du certificat intermédiaire '{name}': {output}" } diff --git a/app/src/Views/certificates/index.php b/app/src/Views/certificates/index.php index d06a411..ba6d7a5 100644 --- a/app/src/Views/certificates/index.php +++ b/app/src/Views/certificates/index.php @@ -49,8 +49,8 @@ require_once APP_ROOT_DIR . '/src/Views/shared/header.php';