vendor/drenso/symfony-oidc-bundle/src/Security/OidcAuthenticator.php line 63

Open in your IDE?
  1. <?php
  2. namespace Drenso\OidcBundle\Security;
  3. use Drenso\OidcBundle\Exception\OidcException;
  4. use Drenso\OidcBundle\OidcClientInterface;
  5. use Drenso\OidcBundle\OidcJwtHelper;
  6. use Drenso\OidcBundle\OidcSessionStorage;
  7. use Drenso\OidcBundle\Security\Exception\OidcAuthenticationException;
  8. use Drenso\OidcBundle\Security\Exception\UnsupportedManagerException;
  9. use Drenso\OidcBundle\Security\Token\OidcToken;
  10. use Drenso\OidcBundle\Security\UserProvider\OidcUserProviderInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  14. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  15. use Symfony\Component\Security\Core\Exception\UserNotFoundException;
  16. use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
  17. use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
  18. use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface;
  19. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
  20. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  21. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  22. use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
  23. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  24. use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
  25. use Symfony\Component\Security\Http\HttpUtils;
  26. class OidcAuthenticator implements InteractiveAuthenticatorInterfaceAuthenticationEntryPointInterface
  27. {
  28.   public function __construct(
  29.     private readonly HttpUtils $httpUtils,
  30.     private readonly OidcClientInterface $oidcClient,
  31.     private readonly OidcSessionStorage $sessionStorage,
  32.     private readonly OidcUserProviderInterface $oidcUserProvider,
  33.     private readonly AuthenticationSuccessHandlerInterface $successHandler,
  34.     private readonly AuthenticationFailureHandlerInterface $failureHandler,
  35.     private readonly string $checkPath,
  36.     private readonly string $loginPath,
  37.     private readonly string $userIdentifierProperty,
  38.     private readonly bool $enableRememberMe,
  39.     private readonly bool $userIdentifierFromIdToken false,
  40.   ) {
  41.   }
  42.   public function supports(Request $request): ?bool
  43.   {
  44.     return
  45.         $this->httpUtils->checkRequestPath($request$this->checkPath)
  46.         && $request->query->has('code')
  47.         && $request->query->has('state');
  48.   }
  49.   public function start(Request $request, ?AuthenticationException $authException null): Response
  50.   {
  51.     return $this->httpUtils->createRedirectResponse($request$this->loginPath);
  52.   }
  53.   public function authenticate(Request $request): Passport
  54.   {
  55.     try {
  56.       // Try to authenticate the request
  57.       $authData $this->oidcClient->authenticate($request);
  58.       // Retrieve the user data with the authentication data
  59.       $userData $this->oidcClient->retrieveUserInfo($authData);
  60.       // Look for the user identifier in either the id_token or the userinfo endpoint
  61.       if ($this->userIdentifierFromIdToken) {
  62.         $userIdentifier OidcJwtHelper::parseToken($authData->getIdToken())
  63.           ->claims()
  64.           ->get($this->userIdentifierProperty);
  65.       } else {
  66.         $userIdentifier $userData->getUserDataString($this->userIdentifierProperty);
  67.       }
  68.       // Ensure the user exists
  69.       if (!$userIdentifier) {
  70.         throw new UserNotFoundException(
  71.           sprintf('User identifier property (%s) yielded empty user identifier'$this->userIdentifierProperty));
  72.       }
  73.       $this->oidcUserProvider->ensureUserExists($userIdentifier$userData);
  74.       // Create the passport
  75.       $passport = new SelfValidatingPassport(new UserBadge(
  76.         $userIdentifier,
  77.         fn (string $userIdentifier) => $this->oidcUserProvider->loadOidcUser($userIdentifier),
  78.       ));
  79.       $passport->setAttribute(OidcToken::AUTH_DATA_ATTR$authData);
  80.       $passport->setAttribute(OidcToken::USER_DATA_ATTR$userData);
  81.       if ($this->enableRememberMe && $this->sessionStorage->getRememberMe()) {
  82.         // Add remember me badge when enabled
  83.         $passport->addBadge((new RememberMeBadge())->enable());
  84.         $this->sessionStorage->clearRememberMe();
  85.       }
  86.       return $passport;
  87.     } catch (OidcException $e) {
  88.       throw new OidcAuthenticationException('OIDC authentication failed'$e);
  89.     }
  90.   }
  91.   public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  92.   {
  93.     return $this->successHandler->onAuthenticationSuccess($request$token);
  94.   }
  95.   public function onAuthenticationFailure(Request $requestAuthenticationException $exception): ?Response
  96.   {
  97.     return $this->failureHandler->onAuthenticationFailure($request$exception);
  98.   }
  99.   public function createToken(Passport $passportstring $firewallName): TokenInterface
  100.   {
  101.     return new OidcToken($passport$firewallName);
  102.   }
  103.   /**
  104.    * @todo: Remove when dropping support for Symfony 5.4
  105.    *
  106.    * @phan-suppress PhanUndeclaredTypeParameter
  107.    */
  108.   public function createAuthenticatedToken(
  109.     PassportInterface $passport,
  110.     string $firewallName): TokenInterface
  111.   {
  112.     throw new UnsupportedManagerException();
  113.   }
  114.   public function isInteractive(): bool
  115.   {
  116.     return true;
  117.   }
  118. }