vendor/hwi/oauth-bundle/Security/Http/Authenticator/OAuthAuthenticator.php line 39

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the HWIOAuthBundle package.
  4.  *
  5.  * (c) Hardware Info <opensource@hardware.info>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace HWI\Bundle\OAuthBundle\Security\Http\Authenticator;
  11. use HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface;
  12. use HWI\Bundle\OAuthBundle\OAuth\State\State;
  13. use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
  14. use HWI\Bundle\OAuthBundle\Security\Core\Exception\OAuthAwareExceptionInterface;
  15. use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface;
  16. use HWI\Bundle\OAuthBundle\Security\Http\ResourceOwnerMapInterface;
  17. use Symfony\Component\HttpFoundation\RedirectResponse;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpFoundation\Response;
  20. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  21. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  22. use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
  23. use Symfony\Component\Security\Core\Exception\LazyResponseException;
  24. use Symfony\Component\Security\Core\User\UserInterface;
  25. use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
  26. use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
  27. use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
  28. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  29. use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
  30. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  31. use Symfony\Component\Security\Http\HttpUtils;
  32. /**
  33.  * @author Vadim Borodavko <vadim.borodavko@gmail.com>
  34.  */
  35. final class OAuthAuthenticator implements AuthenticatorInterface
  36. {
  37.     /**
  38.      * @var HttpUtils
  39.      */
  40.     private $httpUtils;
  41.     /**
  42.      * @var OAuthAwareUserProviderInterface
  43.      */
  44.     private $userProvider;
  45.     /**
  46.      * @var ResourceOwnerMapInterface
  47.      */
  48.     private $resourceOwnerMap;
  49.     /**
  50.      * @var string[]
  51.      */
  52.     private $checkPaths;
  53.     /**
  54.      * @var AuthenticationSuccessHandlerInterface
  55.      */
  56.     private $successHandler;
  57.     /**
  58.      * @var AuthenticationFailureHandlerInterface
  59.      */
  60.     private $failureHandler;
  61.     /**
  62.      * @var mixed[]
  63.      */
  64.     private $rawToken;
  65.     /**
  66.      * @var string
  67.      */
  68.     private $resourceOwnerName;
  69.     /**
  70.      * @var string
  71.      */
  72.     private $refreshToken;
  73.     /**
  74.      * @var string
  75.      */
  76.     private $createdAt;
  77.     public function __construct(
  78.         HttpUtils $httpUtils,
  79.         OAuthAwareUserProviderInterface $userProvider,
  80.         ResourceOwnerMapInterface $resourceOwnerMap,
  81.         array $checkPaths,
  82.         AuthenticationSuccessHandlerInterface $successHandler,
  83.         AuthenticationFailureHandlerInterface $failureHandler
  84.     ) {
  85.         $this->failureHandler $failureHandler;
  86.         $this->successHandler $successHandler;
  87.         $this->checkPaths $checkPaths;
  88.         $this->resourceOwnerMap $resourceOwnerMap;
  89.         $this->userProvider $userProvider;
  90.         $this->httpUtils $httpUtils;
  91.     }
  92.     public function supports(Request $request): bool
  93.     {
  94.         foreach ($this->checkPaths as $checkPath) {
  95.             if ($this->httpUtils->checkRequestPath($request$checkPath)) {
  96.                 return true;
  97.             }
  98.         }
  99.         return false;
  100.     }
  101.     /**
  102.      * @throws AuthenticationException
  103.      * @throws LazyResponseException
  104.      */
  105.     public function authenticate(Request $request): PassportInterface
  106.     {
  107.         [$resourceOwner$checkPath] = $this->resourceOwnerMap->getResourceOwnerByRequest($request);
  108.         if (!$resourceOwner instanceof ResourceOwnerInterface) {
  109.             throw new AuthenticationException('No resource owner match the request.');
  110.         }
  111.         if (!$resourceOwner->handles($request)) {
  112.             throw new AuthenticationException('No oauth code in the request.');
  113.         }
  114.         // If resource owner supports only one url authentication, call redirect
  115.         if ($request->query->has('authenticated') && $resourceOwner->getOption('auth_with_one_url')) {
  116.             $request->attributes->set('service'$resourceOwner->getName());
  117.             throw new LazyResponseException(new RedirectResponse(sprintf('%s?code=%s&authenticated=true'$this->httpUtils->generateUri($request'hwi_oauth_connect_service'), $request->query->get('code'))));
  118.         }
  119.         $resourceOwner->isCsrfTokenValid(
  120.             $this->extractCsrfTokenFromState($request->get('state'))
  121.         );
  122.         $accessToken $resourceOwner->getAccessToken(
  123.             $request,
  124.             $this->httpUtils->createRequest($request$checkPath)->getUri()
  125.         );
  126.         $token = new OAuthToken($accessToken);
  127.         $token->setResourceOwnerName($resourceOwner->getName());
  128.         if ($token->isExpired()) {
  129.             $token $this->refreshToken($token$resourceOwner);
  130.         }
  131.         $userResponse $resourceOwner->getUserInformation($token->getRawToken());
  132.         try {
  133.             $user $this->userProvider->loadUserByOAuthUserResponse($userResponse);
  134.         } catch (OAuthAwareExceptionInterface $e) {
  135.             $e->setToken($token);
  136.             $e->setResourceOwnerName($token->getResourceOwnerName());
  137.             throw $e;
  138.         }
  139.         if (!$user instanceof UserInterface) {
  140.             throw new AuthenticationServiceException('loadUserByOAuthUserResponse() must return a UserInterface.');
  141.         }
  142.         $this->rawToken $token->getRawToken();
  143.         $this->resourceOwnerName $resourceOwner->getName();
  144.         $this->refreshToken $token->getRefreshToken();
  145.         $this->createdAt $token->getCreatedAt();
  146.         return new SelfValidatingPassport(
  147.             class_exists(UserBadge::class)
  148.                 ? new UserBadge(
  149.                     method_exists($user'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(),
  150.                     static function () use ($user) { return $user; }
  151.                 )
  152.                 : $user
  153.         );
  154.     }
  155.     public function createToken(PassportInterface $passportstring $firewallName): TokenInterface
  156.     {
  157.         return $this->createAuthenticatedToken($passport$firewallName);
  158.     }
  159.     public function createAuthenticatedToken(PassportInterface $passportstring $firewallName): TokenInterface
  160.     {
  161.         $token = new OAuthToken($this->rawToken$passport->getUser()->getRoles());
  162.         $token->setResourceOwnerName($this->resourceOwnerName);
  163.         $token->setUser($passport->getUser());
  164.         $token->setRefreshToken($this->refreshToken);
  165.         $token->setCreatedAt($this->createdAt);
  166.         $this->rawToken null;
  167.         $this->resourceOwnerName null;
  168.         $this->refreshToken null;
  169.         $this->createdAt null;
  170.         return $token;
  171.     }
  172.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  173.     {
  174.         return $this->successHandler->onAuthenticationSuccess($request$token);
  175.     }
  176.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): ?Response
  177.     {
  178.         return $this->failureHandler->onAuthenticationFailure($request$exception);
  179.     }
  180.     private function refreshToken(OAuthToken $expiredTokenResourceOwnerInterface $resourceOwner): OAuthToken
  181.     {
  182.         if (!$expiredToken->getRefreshToken()) {
  183.             return $expiredToken;
  184.         }
  185.         $token = new OAuthToken($resourceOwner->refreshAccessToken($expiredToken->getRefreshToken()));
  186.         $token->setRefreshToken($expiredToken->getRefreshToken());
  187.         return $token;
  188.     }
  189.     private function extractCsrfTokenFromState(?string $stateParameter): ?string
  190.     {
  191.         $state = new State($stateParameter);
  192.         return $state->getCsrfToken() ?: $stateParameter;
  193.     }
  194. }