1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys UserBundle package. 
   6  * (c) Raphaël Gertz <symfony@rapsys.eu> 
   8  * For the full copyright and license information, please view the LICENSE 
   9  * file that was distributed with this source code. 
  12 namespace Rapsys\UserBundle\Handler
; 
  14 use Psr\Log\LoggerInterface
; 
  15 use Symfony\Component\DependencyInjection\ContainerInterface
; 
  16 use Symfony\Component\HttpFoundation\RedirectResponse
; 
  17 use Symfony\Component\HttpFoundation\Request
; 
  18 use Symfony\Component\HttpFoundation\Response
; 
  19 use Symfony\Component\HttpKernel\HttpKernelInterface
; 
  20 use Symfony\Component\Routing\Exception\ResourceNotFoundException
; 
  21 use Symfony\Component\Routing\RequestContext
; 
  22 use Symfony\Component\Routing\RouterInterface
; 
  23 use Symfony\Component\Security\Core\Exception\AuthenticationException
; 
  24 use Symfony\Component\Security\Core\Exception\BadCredentialsException
; 
  25 use Symfony\Component\Security\Core\Exception\DisabledException
; 
  26 use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler
; 
  27 use Symfony\Component\Security\Http\HttpUtils
; 
  28 use Symfony\Component\Security\Http\ParameterBagUtils
; 
  30 use Rapsys\PackBundle\Util\SluggerUtil
; 
  31 use Rapsys\UserBundle\Exception\UnactivatedException
; 
  32 use Rapsys\UserBundle\RapsysUserBundle
; 
  37 class AuthenticationFailureHandler 
extends DefaultAuthenticationFailureHandler 
{ 
  43     protected $defaultOptions = [ 
  44         'failure_path' => null, 
  45         'failure_forward' => false, 
  46         'login_path' => '/login', 
  47         'failure_path_parameter' => '_failure_path', 
  63     public function __construct(HttpKernelInterface 
$httpKernel, HttpUtils 
$httpUtils, array $options = [], LoggerInterface 
$logger, ContainerInterface 
$container, RouterInterface 
$router, SluggerUtil 
$slugger) { 
  65                 $this->config 
= $container->getParameter(self
::getAlias()); 
  68                 $this->router 
= $router; 
  71                 $this->slugger 
= $slugger; 
  73                 //Call parent constructor 
  74                 parent
::__construct($httpKernel, $httpUtils, $options, $logger); 
  78          * This is called when an interactive authentication attempt fails 
  80          * User may retrieve mail + field + hash for each unactivated/locked accounts 
  84         public function onAuthenticationFailure(Request 
$request, AuthenticationException 
$exception): Response 
{ 
  85                 //With bad credential exception 
  86                 if ($exception instanceof BadCredentialsException
) { 
  87                         //With parent exception 
  88                         if ($parent = $exception->getPrevious()) { 
  90                                 //TODO: check form _token validity ??? 
  92                                         $request->request
->has('login') && 
  93                                         !empty($login = $request->request
->get('login')) && 
  94                                         !empty($mail = $login['mail']) 
  96                                         //Redirect on register 
  97                                         if ($parent instanceof UnactivatedException 
|| $parent instanceof DisabledException
) { 
  98                                                 //Set extra parameters 
  99                                                 $extra = ['mail' => $smail = $this->slugger
->short($mail), 'field' => $sfield = $this->slugger
->serialize([]), 'hash' => $this->slugger
->hash($smail.$sfield)]; 
 101                                                 //With failure target path option 
 102                                                 if (!empty($failurePath = $this->options
['failure_path'])) { 
 104                                                         if ($failurePath[0] == '/') { 
 105                                                                 //Create login path request instance 
 106                                                                 $req = Request
::create($failurePath); 
 108                                                                 //Get login path pathinfo 
 109                                                                 $path = $req->getPathInfo(); 
 112                                                                 $path = str_replace($request->getScriptName(), '', $path); 
 114                                                                 //Try with login path path 
 117                                                                         $oldContext = $this->router
->getContext(); 
 119                                                                         //Force clean context 
 120                                                                         //XXX: prevent MethodNotAllowedException on GET only routes because our context method is POST 
 121                                                                         //XXX: see vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +42 
 122                                                                         $this->router
->setContext(new RequestContext()); 
 124                                                                         //Retrieve route matching path 
 125                                                                         $route = $this->router
->match($path); 
 128                                                                         $this->router
->setContext($oldContext); 
 134                                                                         if ($name = $route['_route']) { 
 135                                                                                 //Remove route and controller from route defaults 
 136                                                                                 unset($route['_route'], $route['_controller'], $route['_canonical_route']); 
 139                                                                                 $url = $this->router
->generate($name, $extra+
$route); 
 141                                                                                 //Return redirect to url response 
 142                                                                                 return new RedirectResponse($url, 302); 
 145                                                                 } catch (ResourceNotFoundException 
$e) { 
 146                                                                         //Unset default path, name and route 
 147                                                                         unset($failurePath, $name, $route); 
 151                                                                 //Try with login path route 
 153                                                                         //Retrieve route matching path 
 154                                                                         $url = $this->router
->generate($failurePath, $extra); 
 156                                                                         //Return redirect to url response 
 157                                                                         return new RedirectResponse($url, 302); 
 158                                                                 //Route not found, missing parameter or invalid parameter 
 159                                                                 } catch (RouteNotFoundException
|MissingMandatoryParametersException
|InvalidParameterException 
$e) { 
 160                                                                         //Unset default path and url 
 161                                                                         unset($failurePath, $url); 
 166                                                 //With index route from config 
 167                                                 if (!empty($name = $this->config
['route']['register']['name']) && is_array($context = $this->config
['route']['register']['context'])) { 
 171                                                                 $url = $this->router
->generate($name, $extra+
$context); 
 173                                                                 //Return generated route 
 174                                                                 return new RedirectResponse($url, 302); 
 176                                                         } catch (ResourceNotFoundException 
$e) { 
 177                                                                 //Unset name and context 
 178                                                                 unset($name, $context); 
 182                                                 //With login target path option 
 183                                                 if (!empty($loginPath = $this->options
['login_path'])) { 
 185                                                         if ($loginPath[0] == '/') { 
 186                                                                 //Create login path request instance 
 187                                                                 $req = Request
::create($loginPath); 
 189                                                                 //Get login path pathinfo 
 190                                                                 $path = $req->getPathInfo(); 
 193                                                                 $path = str_replace($request->getScriptName(), '', $path); 
 195                                                                 //Try with login path path 
 198                                                                         $oldContext = $this->router
->getContext(); 
 200                                                                         //Force clean context 
 201                                                                         //XXX: prevent MethodNotAllowedException on GET only routes because our context method is POST 
 202                                                                         //XXX: see vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +42 
 203                                                                         $this->router
->setContext(new RequestContext()); 
 205                                                                         //Retrieve route matching path 
 206                                                                         $route = $this->router
->match($path); 
 209                                                                         $this->router
->setContext($oldContext); 
 215                                                                         if ($name = $route['_route']) { 
 216                                                                                 //Remove route and controller from route defaults 
 217                                                                                 unset($route['_route'], $route['_controller'], $route['_canonical_route']); 
 220                                                                                 $url = $this->router
->generate($name, $extra+
$route); 
 222                                                                                 //Return redirect to url response 
 223                                                                                 return new RedirectResponse($url, 302); 
 226                                                                 } catch (ResourceNotFoundException 
$e) { 
 227                                                                         //Unset default path, name and route 
 228                                                                         unset($loginPath, $name, $route); 
 232                                                                 //Try with login path route 
 234                                                                         //Retrieve route matching path 
 235                                                                         $url = $this->router
->generate($loginPath, $extra); 
 237                                                                         //Return redirect to url response 
 238                                                                         return new RedirectResponse($url, 302); 
 239                                                                 //Route not found, missing parameter or invalid parameter 
 240                                                                 } catch (RouteNotFoundException
|MissingMandatoryParametersException
|InvalidParameterException 
$e) { 
 241                                                                         //Unset default path and url 
 242                                                                         unset($loginPath, $url); 
 251                 //Call parent function 
 252                 return parent
::onAuthenticationFailure($request, $exception); 
 258         public function getAlias(): string { 
 259                 return RapsysUserBundle
::getAlias();