vendor/league/oauth2-server-bundle/src/Security/Authenticator/OAuth2Authenticator.php line 90

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace League\Bundle\OAuth2ServerBundle\Security\Authenticator;
  4. use League\Bundle\OAuth2ServerBundle\Security\Authentication\Token\OAuth2Token;
  5. use League\Bundle\OAuth2ServerBundle\Security\Exception\OAuth2AuthenticationException;
  6. use League\Bundle\OAuth2ServerBundle\Security\Exception\OAuth2AuthenticationFailedException;
  7. use League\Bundle\OAuth2ServerBundle\Security\Passport\Badge\ScopeBadge;
  8. use League\Bundle\OAuth2ServerBundle\Security\User\NullUser;
  9. use League\OAuth2\Server\Exception\OAuthServerException;
  10. use League\OAuth2\Server\ResourceServer;
  11. use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  15. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  16. use Symfony\Component\Security\Core\User\UserInterface;
  17. use Symfony\Component\Security\Core\User\UserProviderInterface;
  18. use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
  19. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  20. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  21. use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
  22. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  23. use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
  24. /**
  25.  * @author Mathias Arlaud <mathias.arlaud@gmail.com>
  26.  */
  27. final class OAuth2Authenticator implements AuthenticatorInterfaceAuthenticationEntryPointInterface
  28. {
  29.     /**
  30.      * @psalm-suppress UndefinedTrait
  31.      * @psalm-suppress MethodSignatureMismatch
  32.      */
  33.     use ForwardCompatAuthenticatorTrait;
  34.     private HttpMessageFactoryInterface $httpMessageFactory;
  35.     private ResourceServer $resourceServer;
  36.     private UserProviderInterface $userProvider;
  37.     private string $rolePrefix;
  38.     public function __construct(
  39.         HttpMessageFactoryInterface $httpMessageFactory,
  40.         ResourceServer $resourceServer,
  41.         UserProviderInterface $userProvider,
  42.         string $rolePrefix
  43.     ) {
  44.         $this->httpMessageFactory $httpMessageFactory;
  45.         $this->resourceServer $resourceServer;
  46.         $this->userProvider $userProvider;
  47.         $this->rolePrefix $rolePrefix;
  48.     }
  49.     public function supports(Request $request): ?bool
  50.     {
  51.         return str_starts_with($request->headers->get('Authorization'''), 'Bearer ');
  52.     }
  53.     public function start(Request $request, ?AuthenticationException $authException null): Response
  54.     {
  55.         return new Response(''401, ['WWW-Authenticate' => 'Bearer']);
  56.     }
  57.     /**
  58.      * @return Passport
  59.      */
  60.     public function doAuthenticate(Request $request/* : Passport */
  61.     {
  62.         try {
  63.             $psr7Request $this->resourceServer->validateAuthenticatedRequest($this->httpMessageFactory->createRequest($request));
  64.         } catch (OAuthServerException $e) {
  65.             throw OAuth2AuthenticationFailedException::create('The resource server rejected the request.'$e);
  66.         }
  67.         /** @var string $userIdentifier */
  68.         $userIdentifier $psr7Request->getAttribute('oauth_user_id''');
  69.         /** @var string $accessTokenId */
  70.         $accessTokenId $psr7Request->getAttribute('oauth_access_token_id');
  71.         /** @var list<string> $scopes */
  72.         $scopes $psr7Request->getAttribute('oauth_scopes', []);
  73.         /** @var string $oauthClientId */
  74.         $oauthClientId $psr7Request->getAttribute('oauth_client_id''');
  75.         /** @psalm-suppress MixedInferredReturnType */
  76.         $userLoader = function (string $userIdentifier): UserInterface {
  77.             if ('' === $userIdentifier) {
  78.                 return new NullUser();
  79.             }
  80.             if (!method_exists($this->userProvider'loadUserByIdentifier')) {
  81.                 /**
  82.                  * @psalm-suppress DeprecatedMethod
  83.                  * @psalm-suppress MixedReturnStatement
  84.                  */
  85.                 return $this->userProvider->loadUserByUsername($userIdentifier);
  86.             }
  87.             return $this->userProvider->loadUserByIdentifier($userIdentifier);
  88.         };
  89.         $passport = new SelfValidatingPassport(new UserBadge($userIdentifier$userLoader), [
  90.             new ScopeBadge($scopes),
  91.         ]);
  92.         $passport->setAttribute('accessTokenId'$accessTokenId);
  93.         $passport->setAttribute('oauthClientId'$oauthClientId);
  94.         return $passport;
  95.     }
  96.     /**
  97.      * @return OAuth2Token
  98.      *
  99.      * @psalm-suppress DeprecatedInterface
  100.      * @psalm-suppress UndefinedClass
  101.      * @psalm-suppress MixedInferredReturnType
  102.      * @psalm-suppress RedundantCondition
  103.      */
  104.     public function createAuthenticatedToken(PassportInterface $passportstring $firewallName): TokenInterface
  105.     {
  106.         if (!$passport instanceof Passport) {
  107.             throw new \RuntimeException(sprintf('Cannot create a OAuth2 authenticated token. $passport should be a %s'Passport::class));
  108.         }
  109.         $token $this->createToken($passport$firewallName);
  110.         /**
  111.          * @psalm-suppress TooManyArguments
  112.          * @psalm-suppress UndefinedMethod
  113.          */
  114.         $token->setAuthenticated(true);
  115.         return $token;
  116.     }
  117.     /**
  118.      * @return OAuth2Token
  119.      */
  120.     public function createToken(Passport $passportstring $firewallName): TokenInterface
  121.     {
  122.         /** @var string $accessTokenId */
  123.         $accessTokenId $passport->getAttribute('accessTokenId');
  124.         /** @var ScopeBadge $scopeBadge */
  125.         $scopeBadge $passport->getBadge(ScopeBadge::class);
  126.         /** @var string $oauthClientId */
  127.         $oauthClientId $passport->getAttribute('oauthClientId''');
  128.         $token = new OAuth2Token($passport->getUser(), $accessTokenId$oauthClientId$scopeBadge->getScopes(), $this->rolePrefix);
  129.         if (method_exists(AuthenticatorInterface::class, 'createAuthenticatedToken') && !method_exists(AuthenticatorInterface::class, 'createToken')) {
  130.             // symfony 5.4 only
  131.             /**
  132.              * @psalm-suppress TooManyArguments
  133.              * @psalm-suppress UndefinedMethod
  134.              */
  135.             $token->setAuthenticated(truefalse);
  136.         }
  137.         return $token;
  138.     }
  139.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  140.     {
  141.         return null;
  142.     }
  143.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): ?Response
  144.     {
  145.         if ($exception instanceof OAuth2AuthenticationException) {
  146.             return new Response($exception->getMessage(), $exception->getStatusCode(), $exception->getHeaders());
  147.         }
  148.         throw $exception;
  149.     }
  150. }