vendor/symfony/security-http/Authenticator/FormLoginAuthenticator.php line 158

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  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 Symfony\Component\Security\Http\Authenticator;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  14. use Symfony\Component\HttpKernel\HttpKernelInterface;
  15. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  16. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  17. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  18. use Symfony\Component\Security\Core\Exception\BadCredentialsException;
  19. use Symfony\Component\Security\Core\Security;
  20. use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
  21. use Symfony\Component\Security\Core\User\UserProviderInterface;
  22. use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
  23. use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
  24. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
  25. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PasswordUpgradeBadge;
  26. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
  27. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  28. use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
  29. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  30. use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
  31. use Symfony\Component\Security\Http\HttpUtils;
  32. use Symfony\Component\Security\Http\ParameterBagUtils;
  33. /**
  34.  * @author Wouter de Jong <wouter@wouterj.nl>
  35.  * @author Fabien Potencier <fabien@symfony.com>
  36.  *
  37.  * @final
  38.  */
  39. class FormLoginAuthenticator extends AbstractLoginFormAuthenticator
  40. {
  41.     private $httpUtils;
  42.     private $userProvider;
  43.     private $successHandler;
  44.     private $failureHandler;
  45.     private $options;
  46.     private $httpKernel;
  47.     public function __construct(HttpUtils $httpUtilsUserProviderInterface $userProviderAuthenticationSuccessHandlerInterface $successHandlerAuthenticationFailureHandlerInterface $failureHandler, array $options)
  48.     {
  49.         $this->httpUtils $httpUtils;
  50.         $this->userProvider $userProvider;
  51.         $this->successHandler $successHandler;
  52.         $this->failureHandler $failureHandler;
  53.         $this->options array_merge([
  54.             'username_parameter' => '_username',
  55.             'password_parameter' => '_password',
  56.             'check_path' => '/login_check',
  57.             'post_only' => true,
  58.             'form_only' => false,
  59.             'enable_csrf' => false,
  60.             'csrf_parameter' => '_csrf_token',
  61.             'csrf_token_id' => 'authenticate',
  62.         ], $options);
  63.     }
  64.     protected function getLoginUrl(Request $request): string
  65.     {
  66.         return $this->httpUtils->generateUri($request$this->options['login_path']);
  67.     }
  68.     public function supports(Request $request): bool
  69.     {
  70.         return ($this->options['post_only'] ? $request->isMethod('POST') : true)
  71.             && $this->httpUtils->checkRequestPath($request$this->options['check_path'])
  72.             && ($this->options['form_only'] ? 'form' === $request->getContentType() : true);
  73.     }
  74.     public function authenticate(Request $request): Passport
  75.     {
  76.         $credentials $this->getCredentials($request);
  77.         // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0
  78.         $method 'loadUserByIdentifier';
  79.         if (!method_exists($this->userProvider'loadUserByIdentifier')) {
  80.             trigger_deprecation('symfony/security-core''5.3''Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.'get_debug_type($this->userProvider));
  81.             $method 'loadUserByUsername';
  82.         }
  83.         $passport = new Passport(
  84.             new UserBadge($credentials['username'], [$this->userProvider$method]),
  85.             new PasswordCredentials($credentials['password']),
  86.             [new RememberMeBadge()]
  87.         );
  88.         if ($this->options['enable_csrf']) {
  89.             $passport->addBadge(new CsrfTokenBadge($this->options['csrf_token_id'], $credentials['csrf_token']));
  90.         }
  91.         if ($this->userProvider instanceof PasswordUpgraderInterface) {
  92.             $passport->addBadge(new PasswordUpgradeBadge($credentials['password'], $this->userProvider));
  93.         }
  94.         return $passport;
  95.     }
  96.     /**
  97.      * @deprecated since Symfony 5.4, use {@link createToken()} instead
  98.      */
  99.     public function createAuthenticatedToken(PassportInterface $passportstring $firewallName): TokenInterface
  100.     {
  101.         trigger_deprecation('symfony/security-http''5.4''Method "%s()" is deprecated, use "%s::createToken()" instead.'__METHOD____CLASS__);
  102.         return $this->createToken($passport$firewallName);
  103.     }
  104.     public function createToken(Passport $passportstring $firewallName): TokenInterface
  105.     {
  106.         return new UsernamePasswordToken($passport->getUser(), $firewallName$passport->getUser()->getRoles());
  107.     }
  108.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  109.     {
  110.         return $this->successHandler->onAuthenticationSuccess($request$token);
  111.     }
  112.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): Response
  113.     {
  114.         return $this->failureHandler->onAuthenticationFailure($request$exception);
  115.     }
  116.     private function getCredentials(Request $request): array
  117.     {
  118.         $credentials = [];
  119.         $credentials['csrf_token'] = ParameterBagUtils::getRequestParameterValue($request$this->options['csrf_parameter']);
  120.         if ($this->options['post_only']) {
  121.             $credentials['username'] = ParameterBagUtils::getParameterBagValue($request->request$this->options['username_parameter']);
  122.             $credentials['password'] = ParameterBagUtils::getParameterBagValue($request->request$this->options['password_parameter']) ?? '';
  123.         } else {
  124.             $credentials['username'] = ParameterBagUtils::getRequestParameterValue($request$this->options['username_parameter']);
  125.             $credentials['password'] = ParameterBagUtils::getRequestParameterValue($request$this->options['password_parameter']) ?? '';
  126.         }
  127.         if (!\is_string($credentials['username']) && (!\is_object($credentials['username']) || !method_exists($credentials['username'], '__toString'))) {
  128.             throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.'$this->options['username_parameter'], \gettype($credentials['username'])));
  129.         }
  130.         $credentials['username'] = trim($credentials['username']);
  131.         if (\strlen($credentials['username']) > Security::MAX_USERNAME_LENGTH) {
  132.             throw new BadCredentialsException('Invalid username.');
  133.         }
  134.         $request->getSession()->set(Security::LAST_USERNAME$credentials['username']);
  135.         return $credentials;
  136.     }
  137.     public function setHttpKernel(HttpKernelInterface $httpKernel): void
  138.     {
  139.         $this->httpKernel $httpKernel;
  140.     }
  141.     public function start(Request $requestAuthenticationException $authException null): Response
  142.     {
  143.         if (!$this->options['use_forward']) {
  144.             return parent::start($request$authException);
  145.         }
  146.         $subRequest $this->httpUtils->createRequest($request$this->options['login_path']);
  147.         $response $this->httpKernel->handle($subRequestHttpKernelInterface::SUB_REQUEST);
  148.         if (200 === $response->getStatusCode()) {
  149.             $response->setStatusCode(401);
  150.         }
  151.         return $response;
  152.     }
  153. }