custom/plugins/IwvTwoFactorAuthentication/src/Subscriber/StoreFrontSubscriber.php line 74

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Iwv\IwvTwoFactorAuthentication\Subscriber;
  4. use League\OAuth2\Server\Exception\OAuthServerException;
  5. use Shopware\Core\Checkout\Customer\CustomerEntity;
  6. use Shopware\Core\PlatformRequest;
  7. use Shopware\Core\Framework\Context;
  8. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  11. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpKernel\KernelEvents;
  17. use Iwv\IwvTwoFactorAuthentication\Service\TwoFactorAdaptors\GoogleAuthenticatorAdaptor;
  18. use Iwv\IwvTwoFactorAuthentication\Service\TwoFactorAdaptors\YubicoAuthenticatorAdaptor;
  19. use Iwv\IwvTwoFactorAuthentication\Service\StoreFrontCookieHelperValidator;
  20. use Exception;
  21. class StoreFrontSubscriber implements EventSubscriberInterface
  22. {
  23.     /**
  24.      * @var EntityRepositoryInterface
  25.      */
  26.     private $userRepository;
  27.     /**
  28.      * @var EntityRepositoryInterface
  29.      */
  30.     private $customerRepository;
  31.     /**
  32.      * @var StoreFrontCookieHelperValidator
  33.      */
  34.     private $storeFrontCookieHelperValidator;
  35.     /**
  36.      * @var GoogleAuthenticatorAdaptor
  37.      */
  38.     private $googleAuthenticatorAdaptor;
  39.     /**
  40.      * @var YubicoAuthenticatorAdaptor
  41.      */
  42.     private $yubicoAuthenticatorAdaptor;
  43.     public function __construct(
  44.         EntityRepositoryInterface $userRepository,
  45.         EntityRepositoryInterface $customerRepository,
  46.         StoreFrontCookieHelperValidator $storeFrontCookieHelperValidator,
  47.         GoogleAuthenticatorAdaptor $googleAuthenticatorAdaptor,
  48.         YubicoAuthenticatorAdaptor $yubicoAuthenticatorAdaptor
  49.     ) {
  50.         $this->userRepository $userRepository;
  51.         $this->customerRepository $customerRepository;
  52.         $this->storeFrontCookieHelperValidator $storeFrontCookieHelperValidator;
  53.         $this->googleAuthenticatorAdaptor $googleAuthenticatorAdaptor;
  54.         $this->yubicoAuthenticatorAdaptor $yubicoAuthenticatorAdaptor;
  55.     }
  56.     public static function getSubscribedEvents()
  57.     {
  58.         return [
  59.             KernelEvents::RESPONSE => 'onResponse',
  60.         ];
  61.     }
  62.     public function onResponse(ResponseEvent $event): void
  63.     {
  64.         /** @var \Symfony\Component\HttpFoundation\Request $request */
  65.         $request $event->getRequest();
  66.         /** @var \Symfony\Component\HttpFoundation\JsonResponse $response */
  67.         $response $event->getResponse();
  68.         /* return on invalid requests */
  69.         if (!in_array($event->getResponse()->getStatusCode(), [200204])) {
  70.             return;
  71.         }
  72.         /* $event->getContext() does not exists */
  73.         $context $request->attributes->get(PlatformRequest::ATTRIBUTE_CONTEXT_OBJECT);
  74.         /* update cookie request on profiles change */
  75.         if ($request->attributes->get('_route') === 'frontend.account.iwvtwofactor.yubico' || 
  76.             $request->attributes->get('_route') === 'frontend.account.iwvtwofactor.yubico.disable' || 
  77.             $request->attributes->get('_route') === 'frontend.account.iwvtwofactor.otp' || 
  78.             $request->attributes->get('_route') === 'frontend.account.iwvtwofactor.otp.disable'
  79.         
  80.         {
  81.             /** @var SalesChannelContext $salesChannelContext */
  82.             $salesChannelContext $request->attributes->get('sw-sales-channel-context');
  83.             $customerId $salesChannelContext->getCustomer()->getId();
  84.             if ($customerId) {
  85.                 $customerDB $context->scope(Context::SYSTEM_SCOPE, fn(Context $systemContext) => $this->customerRepository->search(new Criteria([$customerId]), $systemContext)->first());
  86.                 $customFields $customerDB->getCustomFields();
  87.                 $twoFaParams $customFields['iwvTwoFactor'] ?? [];
  88.                 $response = !empty($twoFaParams) ? $this->storeFrontCookieHelperValidator->addTwoFaCookie($response$customerDB) : $this->storeFrontCookieHelperValidator->removeTwoFaCookie($response);
  89.                 $event->setResponse($response);
  90.             }
  91.             return;
  92.         }
  93.         if(!$request->attributes->get('_loginRequired')){
  94.             return;
  95.         }
  96.         $salesChannelContext $request->attributes->get('sw-sales-channel-context');
  97.         if(!$salesChannelContext){
  98.             return;
  99.         }
  100.         $customerId null;
  101.         if($salesChannelContext->getCustomer()){
  102.             $customerId $salesChannelContext->getCustomer()->getId();
  103.         }
  104.         
  105.         if(!$customerId){
  106.             return;
  107.         }
  108.          /** @var CustomerEntity $customerDB */
  109.         $customerDB $context->scope(Context::SYSTEM_SCOPE, fn(Context $systemContext) => $this->customerRepository->search((new Criteria())->addFilter(new EqualsFilter('id'$customerId)), $systemContext)->first());
  110.         if (!$customerDB || !($customFields $customerDB->getCustomFields()) || !isset($customFields['iwvTwoFactor']) || empty($customFields['iwvTwoFactor'])){
  111.             return;
  112.         }
  113.         try {
  114.             $response $this->storeFrontCookieHelperValidator->addTwoFaCookie($response$customerDB);
  115.             $event->setResponse($response);
  116.         } catch (\Exception $ex) {
  117.             throw new OAuthServerException('OTP is required'$ex->getCode(), 'iwv-request-otp'401array_keys($customFields['iwvTwoFactor']) ?? $customFields['iwvTwoFactor']);
  118.         }
  119.     }
  120. }