Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding the authentication failure handler - Symfony2

Tags:

php

symfony

I am extending the authentication failure handler and everything is mainly working ok, but for one small problem.

This is my services.yml:

  http.utils.class:
    class: Symfony\Component\Security\Http\HttpUtils
  auth.fail:
    class: Acme\MyBundle\AuthenticationFailure
    arguments:
      - @http_kernel
      - @http.utils.class
      - []

I have set this to be used in security.yml:

failure_handler: auth.fail

This is my Acme\MyBundle\AuthenticationFailure.php:

namespace Acme\MyBundle;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
use Symfony\Component\HttpFoundation\Response;

class AuthenticationFailure extends DefaultAuthenticationFailureHandler
{

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {

        //do something

    }

}

The problem is that the options I've set in security.yml are ignored. I know the third parameter of the _construct method of the class is the $options array, and I've not passed anything in as the third parameter (in services.yml), so I'm guessing this is the problem and a solution could be to just pass the values in. I'm guessing I could also do something like this:

arguments:
  - @http_kernel
  - @http.utils.class
  - %security.firewalls.secure_area.form_login%

....I've not tested as the problem is this is hard-coding that in services.yml and it isn't ideal as if I changed the name of secure_area it would break. Surely these values are available in a better way?

like image 682
user2143356 Avatar asked Jul 09 '13 10:07

user2143356


1 Answers

I see you're trying to pass the login_path to your authentication failure handler...

... you should inject @router, adapt the __construct method and generate the url with the route name ( not pattern ) used by your firewall inside the auth failure handler. then redirect the user there...

login_path: your_login_route_name # <- not a pattern like /login

this way changing the name of the firewall will not break your application!


if you don't even want to break the application when changing the route name you can make this configurable aswell:

config.yml

parameters:
   login.route_name: my_login_route_name

routing.yml

%login.route_name%:
     pattern: /login

security.yml

security:
    firewalls:
        your_firewall_name:
             failure_handler: auth.fail
             login_path:      %login.route_name%

services.yml

auth.fail:
     arguments:
         - # ...
         - @router
         - %login.route_name%

Acme\MyBundle\AuthenticationFailure

use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

// ...

protected $router;

protected $loginRoute;

public function __construct( 
    /** ... other arguments **/, 
    RouterInterface $router, 
    $loginRoute
) 
{ 
    // ..
    $this->router     = $router;
    $this->loginRoute = $loginRoute;
}

public function onAuthenticationFailure(
    Request $request, 
    AuthenticationException $exception
)
{

    // ...

    return new RedirectResponse( $this->router->generate($this->loginRoute) ); 
}

Tip regarding your suggestion

( ... using something like %security.firewalls.secure_area.form_login% )

you cannot access the security configuration directly ( these are not parameters - you can't use %security.firewall.whatever% ! ) ...

The the default $options passed to __construct has to be an array ...

... so you might need to surround your passed parameters by [] if those parameters are not an array.

arguments:
    - [ %parameter1% , %parameter2% ]
like image 185
Nicolai Fröhlich Avatar answered Sep 22 '22 10:09

Nicolai Fröhlich