vendor/scheb/2fa-bundle/Security/Authentication/Provider/AuthenticationProviderDecorator.php line 68

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Scheb\TwoFactorBundle\Security\Authentication\Provider;
  4. use Scheb\TwoFactorBundle\DependencyInjection\Factory\Security\TwoFactorFactory;
  5. use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorTokenInterface;
  6. use Scheb\TwoFactorBundle\Security\TwoFactor\AuthenticationContextFactoryInterface;
  7. use Scheb\TwoFactorBundle\Security\TwoFactor\Handler\AuthenticationHandlerInterface;
  8. use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
  9. use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\RequestStack;
  12. use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
  13. use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
  14. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  15. /**
  16.  * @final
  17.  */
  18. class AuthenticationProviderDecorator implements AuthenticationProviderInterface
  19. {
  20.     /**
  21.      * @var AuthenticationProviderInterface
  22.      */
  23.     private $decoratedAuthenticationProvider;
  24.     /**
  25.      * @var AuthenticationHandlerInterface
  26.      */
  27.     private $twoFactorAuthenticationHandler;
  28.     /**
  29.      * @var AuthenticationContextFactoryInterface
  30.      */
  31.     private $authenticationContextFactory;
  32.     /**
  33.      * @var FirewallMap
  34.      */
  35.     private $firewallMap;
  36.     /**
  37.      * @var RequestStack
  38.      */
  39.     private $requestStack;
  40.     public function __construct(
  41.         AuthenticationProviderInterface $decoratedAuthenticationProvider,
  42.         AuthenticationHandlerInterface $twoFactorAuthenticationHandler,
  43.         AuthenticationContextFactoryInterface $authenticationContextFactory,
  44.         FirewallMap $firewallMap,
  45.         RequestStack $requestStack
  46.     ) {
  47.         $this->decoratedAuthenticationProvider $decoratedAuthenticationProvider;
  48.         $this->twoFactorAuthenticationHandler $twoFactorAuthenticationHandler;
  49.         $this->authenticationContextFactory $authenticationContextFactory;
  50.         $this->firewallMap $firewallMap;
  51.         $this->requestStack $requestStack;
  52.     }
  53.     public function supports(TokenInterface $token): bool
  54.     {
  55.         return $this->decoratedAuthenticationProvider->supports($token);
  56.     }
  57.     public function authenticate(TokenInterface $token): TokenInterface
  58.     {
  59.         $wasAlreadyAuthenticated $token->isAuthenticated();
  60.         /** @psalm-suppress InternalMethod */
  61.         $token $this->decoratedAuthenticationProvider->authenticate($token);
  62.         // Only trigger two-factor authentication when the provider was called with an unauthenticated token. When we
  63.         // get an authenticated token passed, we're not doing a login, but the system refreshes the token. Then we don't
  64.         // want to start two-factor authentication or we're ending in an endless loop.
  65.         if ($wasAlreadyAuthenticated) {
  66.             return $token;
  67.         }
  68.         // AnonymousToken and TwoFactorTokenInterface can be ignored
  69.         if ($token instanceof AnonymousToken || $token instanceof TwoFactorTokenInterface) {
  70.             return $token;
  71.         }
  72.         $request $this->getRequest();
  73.         $firewallConfig $this->getFirewallConfig($request);
  74.         if (!\in_array(TwoFactorFactory::AUTHENTICATION_PROVIDER_KEY$firewallConfig->getListeners(), true)) {
  75.             return $token// This firewall doesn't support two-factor authentication
  76.         }
  77.         $context $this->authenticationContextFactory->create($request$token$firewallConfig->getName());
  78.         return $this->twoFactorAuthenticationHandler->beginTwoFactorAuthentication($context);
  79.     }
  80.     /**
  81.      * @return mixed
  82.      */
  83.     public function __call(string $method, array $arguments)
  84.     {
  85.         return ($this->decoratedAuthenticationProvider)->{$method}(...$arguments);
  86.     }
  87.     private function getRequest(): Request
  88.     {
  89.         // Compatibility for Symfony >= 5.3
  90.         if (method_exists(RequestStack::class, 'getMainRequest')) {
  91.             $request $this->requestStack->getMainRequest();
  92.         } else {
  93.             $request $this->requestStack->getMasterRequest();
  94.         }
  95.         if (null === $request) {
  96.             throw new \RuntimeException('No request available');
  97.         }
  98.         return $request;
  99.     }
  100.     private function getFirewallConfig(Request $request): FirewallConfig
  101.     {
  102.         $firewallConfig $this->firewallMap->getFirewallConfig($request);
  103.         if (null === $firewallConfig) {
  104.             throw new \RuntimeException('No firewall configuration available');
  105.         }
  106.         return $firewallConfig;
  107.     }
  108. }