Force HTTPS from the admin, with a probe before and after

System > HTTPS and cms:https switch the redirect lines in public/.htaccess
only when the site answers over HTTPS, and take them back on a loop. HSTS
is a separate second switch. The redirect block moves before the front
controller rules, where it never reached pages, and .well-known is no
longer denied, so the origin probe works on Apache. The Git updater keeps
switched-on lines like the archive update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5.5 committed 2026-10-12 17:22:56 +02:00
1 parent daad5a1740
commit 8b212d5cc9
15 files changed
+614 -24

No files matched your search

+27 -1
View File
@@ -9,6 +9,7 @@ use App\Domain\InvalidPage;
use App\Ops\ArchiveUpdate;
use App\Ops\Backup;
use App\Ops\Environment;
use App\Ops\HttpsRedirect;
use App\Ops\Installation;
use App\Ops\OriginCheck;
use App\Ops\SitePackage;
@@ -29,7 +30,7 @@ use Symfony\Component\Routing\Attribute\Route;
*/
final class SystemController extends AbstractController
{
public function __construct(private Updater $updater, private Backup $backup, private ArchiveUpdate $archive, private Installation $installation, private string $adminPath, private string $databaseUrl, private string $mediaDirectory, private string $projectDir, private string $siteOrigin, private OriginCheck $originCheck, private HttpKernelInterface $kernel, private PageRepository $pages, private SiteSettings $settings, private SitePackage $packages)
public function __construct(private Updater $updater, private Backup $backup, private ArchiveUpdate $archive, private Installation $installation, private string $adminPath, private string $databaseUrl, private string $mediaDirectory, private string $projectDir, private string $siteOrigin, private OriginCheck $originCheck, private HttpKernelInterface $kernel, private PageRepository $pages, private SiteSettings $settings, private SitePackage $packages, private HttpsRedirect $https)
{
}
@@ -67,6 +68,9 @@ final class SystemController extends AbstractController
// bekommt hier den Hinweis, dass die Website woanders eingetragen ist.
'origin' => $this->originFacts($request),
'originRejected' => $request->getSession()->remove('origin_rejected'),
// HTTPS erzwingen und HSTS (ADR 120): der Stand in public/.htaccess.
'https' => $this->https->state(),
'secure' => $request->isSecure(),
]);
}
@@ -494,6 +498,28 @@ final class SystemController extends AbstractController
), 'success');
}
/**
* HTTPS erzwingen oder HSTS schalten (ADR 120). Die Umleitung wird nur eingeschaltet, wenn
* HTTPS vorher und nachher hier ankommt; sonst bleibt public/.htaccess, wie sie war.
*/
#[Route('/%kant.admin_path%/system/https', name: 'admin_system_https', methods: ['POST'])]
public function https(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
if (!$this->isCsrfTokenValid('system', $request->request->getString('_csrf_token'))) {
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
}
$result = match ($request->request->getString('action')) {
'redirect-an' => $this->https->enableRedirect($this->siteOrigin),
'redirect-aus' => $this->https->disableRedirect(),
'hsts-an' => $this->https->switchHsts(true, $this->siteOrigin),
'hsts-aus' => $this->https->switchHsts(false, $this->siteOrigin),
default => ['ok' => false, 'message' => 'Unbekannte Aktion.'],
};
return $this->back($result['message'], $result['ok'] ? 'success' : 'error');
}
/** Die Gegenstelle zur Prüfung oben: öffentlich, und sie verrät nichts als diese Kennung. */
#[Route(OriginCheck::PATH, name: 'site_origin_probe', methods: ['GET'], priority: 10)]
public function originProbe(): Response