src/EventSubscriber/InstallAccessSubscriber.php line 43

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use App\Entity\User;
  4. use Psr\Log\LoggerInterface;
  5. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  6. use Symfony\Component\HttpKernel\Event\RequestEvent;
  7. use Symfony\Component\HttpKernel\KernelEvents;
  8. use Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken;
  9. /**
  10.  * Steuert den Zugang zu /install/action/{tgaHash}:
  11.  *
  12.  * - Jeder neue tgaHash (neuer QR-Code) löscht die bestehende qrcode-Session,
  13.  *   damit alte Sitzungen nicht wiederverwendet werden können.
  14.  * - Dashboard-Benutzer (onlyQrCodeUser = false) werden automatisch in die
  15.  *   qrcode-Firewall eingeloggt, ohne AppCode eingeben zu müssen.
  16.  * - onlyQrCodeUser muss sich immer mit dem AppCode am QR-Login anmelden.
  17.  */
  18. class InstallAccessSubscriber implements EventSubscriberInterface
  19. {
  20.     private const SESSION_KEY_QRCODE '_security_qrcode';
  21.     private const SESSION_KEY_DEFAULT '_security_default';
  22.     private const SESSION_KEY_INSTALL_HASH '_install_tgaHash';
  23.     private const INSTALL_ENTRY_ROUTE 'install_chose_action';
  24.     private LoggerInterface $logger;
  25.     public function __construct(LoggerInterface $logger)
  26.     {
  27.         $this->logger $logger;
  28.     }
  29.     public static function getSubscribedEvents(): array
  30.     {
  31.         // Nach RouterListener (32) aber vor Security-Firewall (8)
  32.         return [
  33.             KernelEvents::REQUEST => ['onKernelRequest'9],
  34.         ];
  35.     }
  36.     public function onKernelRequest(RequestEvent $event): void
  37.     {
  38.         if (!$event->isMainRequest()) {
  39.             return;
  40.         }
  41.         $request $event->getRequest();
  42.         if ($request->attributes->get('_route') !== self::INSTALL_ENTRY_ROUTE) {
  43.             return;
  44.         }
  45.         if (!$request->hasSession()) {
  46.             return;
  47.         }
  48.         $tgaHash = (string) $request->attributes->get('tgaHash''');
  49.         $session $request->getSession();
  50.         $hasQrcodeSession = (bool) $session->get(self::SESSION_KEY_QRCODE);
  51.         $storedHash = (string) $session->get(self::SESSION_KEY_INSTALL_HASH'');
  52.         // Gültige qrcode-Session vorhanden (egal ob gleicher oder anderer tgaHash,
  53.         // auch nach remember_me-Re-Authentifizierung). Hash aktualisieren und
  54.         // durchlassen — der Controller prüft die Zugriffsberechtigung.
  55.         if ($hasQrcodeSession) {
  56.             if ($storedHash !== $tgaHash) {
  57.                 $session->set(self::SESSION_KEY_INSTALL_HASH$tgaHash);
  58.                 $this->logger->debug(sprintf(
  59.                     'InstallAccessSubscriber: tgaHash changed (%s → %s), updating stored hash.',
  60.                     $storedHash,
  61.                     $tgaHash
  62.                 ));
  63.             } else {
  64.                 $this->logger->debug('InstallAccessSubscriber: same tgaHash, passing through.');
  65.             }
  66.             return;
  67.         }
  68.         // Keine qrcode-Session → Hash-Kontext löschen und Dashboard-Session prüfen
  69.         $session->remove(self::SESSION_KEY_INSTALL_HASH);
  70.         // Prüfen ob Dashboard-Session vorhanden
  71.         $defaultTokenSerialized $session->get(self::SESSION_KEY_DEFAULT);
  72.         if (!$defaultTokenSerialized) {
  73.             $this->logger->debug('InstallAccessSubscriber: no default session, redirecting to QR login.');
  74.             return;
  75.         }
  76.         try {
  77.             $defaultToken unserialize($defaultTokenSerialized);
  78.             if (!is_object($defaultToken) || !method_exists($defaultToken'getUser')) {
  79.                 return;
  80.             }
  81.             $user $defaultToken->getUser();
  82.             if (!$user instanceof User) {
  83.                 return;
  84.             }
  85.             if ($user->getOnlyQrCodeUser()) {
  86.                 $this->logger->debug('InstallAccessSubscriber: onlyQrCodeUser, must use QR login.');
  87.                 return;
  88.             }
  89.             // Dashboard-Benutzer automatisch in qrcode-Firewall einloggen
  90.             $qrcodeToken = new PostAuthenticationToken($user'qrcode'$user->getRoles());
  91.             $session->set(self::SESSION_KEY_QRCODEserialize($qrcodeToken));
  92.             $session->set(self::SESSION_KEY_INSTALL_HASH$tgaHash);
  93.             $this->logger->debug(sprintf(
  94.                 'InstallAccessSubscriber: auto-login user %d (%s) into qrcode firewall for tgaHash=%s',
  95.                 $user->getId(),
  96.                 $user->getEmail(),
  97.                 $tgaHash
  98.             ));
  99.         } catch (\Throwable $e) {
  100.             $this->logger->warning('InstallAccessSubscriber: failed to process token: '.$e->getMessage());
  101.         }
  102.     }
  103. }