src/Platform/SecurityBundle/Service/Authenticator/OAuthLoginAuthenticator.php line 26

Open in your IDE?
  1. <?php
  2. namespace Platform\SecurityBundle\Service\Authenticator;
  3. use App\Util\Json;
  4. use Cms\ContainerBundle\Controller\DashboardController;
  5. use Cms\CoreBundle\Util\Doctrine\EntityManager;
  6. use Platform\SecurityBundle\Controller\LoginController;
  7. use Platform\SecurityBundle\Controller\SingleSignOnController;
  8. use Platform\SecurityBundle\Entity\Identity\Account;
  9. use Platform\SecurityBundle\Service\OAuth\OAuthProviderService;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  13. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  14. use Symfony\Component\Security\Core\Security;
  15. use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
  16. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  17. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  18. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  19. use Symfony\Component\Security\Http\HttpUtils;
  20. /**
  21.  *
  22.  */
  23. class OAuthLoginAuthenticator extends AbstractAuthenticator
  24. {
  25.     /**
  26.      * @var EntityManager
  27.      */
  28.     protected EntityManager $em;
  29.     /**
  30.      * @var OAuthProviderService
  31.      */
  32.     protected OAuthProviderService $oAuthProviderService;
  33.     /**
  34.      * @var HttpUtils
  35.      */
  36.     protected HttpUtils $httpUtils;
  37.     /**
  38.      * @param EntityManager $em
  39.      * @param OAuthProviderService $oAuthProviderService
  40.      * @param HttpUtils $httpUtils
  41.      */
  42.     public function __construct(
  43.         EntityManager $em,
  44.         OAuthProviderService $oAuthProviderService,
  45.         HttpUtils $httpUtils
  46.     )
  47.     {
  48.         $this->em $em;
  49.         $this->oAuthProviderService $oAuthProviderService;
  50.         $this->httpUtils $httpUtils;
  51.     }
  52.     /**
  53.      * {@inheritDoc}
  54.      */
  55.     public function supports(Request $request): ?bool
  56.     {
  57.         return $this->httpUtils->checkRequestPath($requestSingleSignOnController::ROUTES__FINISH);
  58.     }
  59.     /**
  60.      * {@inheritDoc}
  61.      */
  62.     public function authenticate(Request $request): Passport
  63.     {
  64.         // handle oauth issues
  65.         try {
  66.             // determine the provider
  67.             $provider $this->oAuthProviderService->getProvider(
  68.                 $this->getProvider($request),
  69.             );
  70.             // get the code
  71.             // one may not be given if the user rejected the access or there was some other problem
  72.             $code $this->getCode($request);
  73.             if ( ! $code) {
  74.                 throw new AuthenticationException(
  75.                     $request->query->get('error_description')
  76.                         ?: $request->query->get('error')
  77.                         ?: '',
  78.                 );
  79.             }
  80.             // read out the access token
  81.             $accessToken $provider->getAccessToken(
  82.                 $this->getCode($request),
  83.             );
  84.             // get the info from the provider using the access token
  85.             $identity $provider->getMe($accessToken);
  86.         } catch (\Exception $e) {
  87.             throw new AuthenticationException(
  88.                 ($e instanceof AuthenticationException) ? $e->getMessage() : '',
  89.                 0,
  90.                 ( ! $e instanceof AuthenticationException) ? $e null,
  91.             );
  92.         }
  93.         // try to obtain the account
  94.         // TODO: do we need to worry about tenant stuff here?
  95.         $account $this->em->getRepository(Account::class)->findOneByEmail(
  96.             $identity['email'],
  97.         );
  98.         if ( ! $account) {
  99.             throw new AuthenticationException();
  100.         }
  101.         // make a passport
  102.         $passport = new SelfValidatingPassport(
  103.             new UserBadge($account->getId())
  104.         );
  105.         // for debugging, add oauth information into the passport
  106.         $passport->setAttribute('oauth_identity'$identity);
  107.         $passport->setAttribute('oauth_provider'$provider->getId());
  108.         $passport->setAttribute('oauth_state'$this->getState($request));
  109.         $passport->setAttribute('oauth_data'$this->getData($request));
  110.         $passport->setAttribute('oauth_redirect'$this->getRedirect($request));
  111.         return $passport;
  112.     }
  113.     /**
  114.      * {@inheritDoc}
  115.      */
  116.     public function createToken(Passport $passportstring $firewallName): TokenInterface
  117.     {
  118.         $token parent::createToken(
  119.             $passport,
  120.             $firewallName
  121.         );
  122.         $token->setAttribute('redirect'$passport->getAttribute('oauth_redirect'));
  123.         return $token;
  124.     }
  125.     /**
  126.      * {@inheritDoc}
  127.      */
  128.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  129.     {
  130.         return $this->httpUtils->createRedirectResponse(
  131.             $request,
  132.             DashboardController::ROUTES__INDEX,
  133.         );
  134.     }
  135.     /**
  136.      * {@inheritDoc}
  137.      */
  138.     public function onAuthenticationFailure(
  139.         Request $request,
  140.         AuthenticationException $exception,
  141.     ): Response
  142.     {
  143.         $request->getSession()?->set(
  144.             Security::AUTHENTICATION_ERROR,
  145.             $exception,
  146.         );
  147.         return $this->httpUtils->createRedirectResponse(
  148.             $request,
  149.             LoginController::ROUTES__SELECT,
  150.         );
  151.     }
  152.     /**
  153.      * @param Request $request
  154.      * @return string|null
  155.      */
  156.     public function getProvider(Request $request): ?string
  157.     {
  158.         return $request->query->get('provider', []);
  159.     }
  160.     /**
  161.      * @param Request $request
  162.      * @return string|null
  163.      */
  164.     public function getCode(Request $request): ?string
  165.     {
  166.         return $request->query->get('code');
  167.     }
  168.     /**
  169.      * @param Request $request
  170.      * @return array
  171.      */
  172.     protected function getState(Request $request): array
  173.     {
  174.         return $request->query->has('state') ? Json::decode(
  175.             base64_decode($request->query->get('state', [])),
  176.             true,
  177.         ) : [];
  178.     }
  179.     /**
  180.      * @param Request $request
  181.      * @return array
  182.      */
  183.     protected function getData(Request $request): array
  184.     {
  185.         $state $this->getState($request);
  186.         return ( ! empty($state) && array_key_exists('data'$state)) ? $state['data'] : [];
  187.     }
  188.     /**
  189.      * @param Request $request
  190.      * @return string|null
  191.      */
  192.     protected function getRedirect(Request $request): ?string
  193.     {
  194.         $data $this->getData($request);
  195.         return ( ! empty($data) && array_key_exists('redirect'$data) && ! empty($data['redirect'])) ? $data['redirect'] : null;
  196.     }
  197. }