src/BackendBundle/Security/Authenticator/OAuth2Authenticator.php line 61

Open in your IDE?
  1. <?php
  2. namespace App\BackendBundle\Security\Authenticator;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Psr\Log\LoggerInterface;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpFoundation\RequestStack;
  7. use Symfony\Component\HttpFoundation\Response;
  8. use Symfony\Component\HttpFoundation\RedirectResponse;
  9. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  10. use Symfony\Component\Routing\RouterInterface;
  11. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  12. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  13. use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
  14. use Symfony\Component\Security\Core\Security;
  15. use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
  16. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  17. use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
  18. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  19. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  20. use App\BackendBundle\Helper\SecurityHelper;
  21. use App\BackendBundle\Helper\UserHelper;
  22. class OAuth2Authenticator extends AbstractLoginFormAuthenticator
  23. {
  24.     private UserHelper $userHelper;
  25.     private LoggerInterface $logger;
  26.     private RequestStack $requestStack;
  27.     private RouterInterface $router;
  28.     private SessionInterface $session;
  29.     private SecurityHelper $securityHelper;
  30.     private string $sessionOAuthKey 'oauth2_session_username';
  31.     private string $sessionEmail 'oauth2_session_email';
  32.     public function __construct(
  33.         UserHelper      $userHelper,
  34.         LoggerInterface $logger,
  35.         RouterInterface $router,
  36.         RequestStack    $requestStack,
  37.         SecurityHelper  $securityHelper
  38.     )
  39.     {
  40.         $this->userHelper $userHelper;
  41.         $this->logger $logger;
  42.         $this->requestStack $requestStack;
  43.         $this->session $this->requestStack->getSession();
  44.         $this->securityHelper $securityHelper;
  45.         $this->router $router;
  46.     }
  47.     public function supports(Request $request): bool
  48.     {
  49.         /*
  50.          * Important !!!
  51.          * The sessionOAuthKey contains the username after login success and 
  52.          * the symfony authenticator is called before the AuthorizationRequestResolverListener
  53.          * which access the TokenStorage
  54.          */
  55.         if ($this->session->has($this->sessionOAuthKey)) {
  56.             return true;
  57.         }
  58.         if (!$request->isMethod('POST')) {
  59.             return false;
  60.         }
  61.         $loginUrl $this->router->generate('oauth2_login'); // need to create url without parameter
  62.         $fullPath $request->getBaseUrl() . $request->getPathInfo();
  63.         if ($loginUrl !== $fullPath) {
  64.             return false;
  65.         }
  66.         return true;
  67.     }
  68.     protected function getLoginUrl(Request $request): string
  69.     {
  70.         $parameters $request->query->all();
  71.         return $this->router->generate('oauth2_login'$parameters);
  72.     }
  73.     public function authenticate(Request $request): Passport
  74.     {
  75.         $userIdentifier $this->session->get($this->sessionOAuthKey);
  76.         if (empty($userIdentifier)) {
  77.             return $this->passportLoginForm($request);
  78.         } else {
  79.             return new SelfValidatingPassport(new UserBadge($userIdentifier));
  80.         }
  81.     }
  82.     private function passportLoginForm(Request $request): Passport
  83.     {
  84.         $email $request->request->get('email''');
  85.         $plaintextPassword $request->request->get('password''');
  86.         if (empty($email) || empty($plaintextPassword)) {
  87.             throw new CustomUserMessageAuthenticationException('Benutzername oder Passwort wurden nicht ausgefüllt.');
  88.         }
  89.         $request->getSession()->set($this->sessionEmail$email);
  90.         return new Passport(new UserBadge($email), new PasswordCredentials($plaintextPassword));
  91.     }
  92.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  93.     {
  94.         $request->getSession()->remove(Security::AUTHENTICATION_ERROR);
  95.         if ($this->session->has($this->sessionOAuthKey)) {
  96.             // on success, let the request continue
  97.             return null;
  98.         }
  99.         /* get username and set in session */
  100.         $user $token->getUser();
  101.         $userName $user->getUsername();
  102.         $this->session->set($this->sessionOAuthKey$userName);
  103.         /* update last login */
  104.         $this->userHelper->updateLastLogin($user);
  105.         /* redirect back to oauth2 server */
  106.         $parameters $request->query->all();
  107.         $url $this->router->generate('oauth2_authorize'$parameters);
  108.         return new RedirectResponse($url);
  109.     }
  110.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): Response
  111.     {
  112.         if ($request->hasSession()) {
  113.             $errorText $this->securityHelper->getLoginErrorText($exception);
  114.             $request->getSession()->set(Security::AUTHENTICATION_ERROR$errorText);
  115.         }
  116.         $this->session->remove($this->sessionOAuthKey);
  117.         $url $this->getLoginUrl($request);
  118.         return new RedirectResponse($url);
  119.     }
  120. }