1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Security\Http\Firewall; 13 14use Psr\Log\LoggerInterface; 15use Symfony\Component\EventDispatcher\EventDispatcherInterface; 16use Symfony\Component\HttpFoundation\Request; 17use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; 18use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; 19use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 20use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; 21use Symfony\Component\Security\Core\Exception\BadCredentialsException; 22use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; 23use Symfony\Component\Security\Core\Security; 24use Symfony\Component\Security\Csrf\CsrfToken; 25use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; 26use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; 27use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; 28use Symfony\Component\Security\Http\HttpUtils; 29use Symfony\Component\Security\Http\ParameterBagUtils; 30use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; 31 32/** 33 * UsernamePasswordFormAuthenticationListener is the default implementation of 34 * an authentication via a simple form composed of a username and a password. 35 * 36 * @author Fabien Potencier <fabien@symfony.com> 37 */ 38class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener 39{ 40 private $csrfTokenManager; 41 42 public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = [], LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null) 43 { 44 parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge([ 45 'username_parameter' => '_username', 46 'password_parameter' => '_password', 47 'csrf_parameter' => '_csrf_token', 48 'csrf_token_id' => 'authenticate', 49 'post_only' => true, 50 ], $options), $logger, $dispatcher); 51 52 $this->csrfTokenManager = $csrfTokenManager; 53 } 54 55 /** 56 * {@inheritdoc} 57 */ 58 protected function requiresAuthentication(Request $request) 59 { 60 if ($this->options['post_only'] && !$request->isMethod('POST')) { 61 return false; 62 } 63 64 return parent::requiresAuthentication($request); 65 } 66 67 /** 68 * {@inheritdoc} 69 */ 70 protected function attemptAuthentication(Request $request) 71 { 72 if (null !== $this->csrfTokenManager) { 73 $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); 74 75 if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { 76 throw new InvalidCsrfTokenException('Invalid CSRF token.'); 77 } 78 } 79 80 if ($this->options['post_only']) { 81 $username = ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter']); 82 $password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']); 83 } else { 84 $username = ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter']); 85 $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); 86 } 87 88 if (!\is_string($username) && (!\is_object($username) || !method_exists($username, '__toString'))) { 89 throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($username))); 90 } 91 92 $username = trim($username); 93 94 if (\strlen($username) > Security::MAX_USERNAME_LENGTH) { 95 throw new BadCredentialsException('Invalid username.'); 96 } 97 98 $request->getSession()->set(Security::LAST_USERNAME, $username); 99 100 return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey)); 101 } 102} 103