1

I'd like to access the security config as it's configured (by default) in security.yml, and in particular actually I need the route name or (even better) generated URL to login. When using FOS User (which I'm using right now) its called "fos_user_security_login" with "/login" URL. I need it to compare with an event's request's (requsted) URL on Kernel's listened events.

I could hardcode this setting check in my Kernel Listener class, like this:

public function onKernelResponse(\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event)
{
    if ($originalResponse->headers->has('location')
        && $originalResponse->headers->get('location') === $router->generate('fos_user_security_login', array(), true))
    {
       //...
    }
}

But what if I changed this setting in future to some another one, e.g. to some "/user/login" path with my custom login handler? This is why I'd like to read the security setting for login.

How can I do this in Symfony?

forsberg
  • 1,681
  • 1
  • 21
  • 27
  • Read this post: http://stackoverflow.com/questions/19831114/symfony2-get-to-the-access-control-parameters-located-in-the-security-yml – Frank B Oct 19 '15 at 15:43
  • The extra problem is it's not set explicitly in security.yml. The only sensible solution I'm thinking about is to double up config, and do something like having a new setting in parameters.yml: login_route: fos_user_security_login. But this means that when I replaced the login mechanism (abandoning FOS User Bundle), I will need to remember to change parameters.yml as well (it's just a better place to have this param set there, than to hardcode it directly in the listener class as shown above). Thx anyway. – forsberg Oct 19 '15 at 15:47
  • Yes i know what you mean. It would be better if you did not have to make an extra config parameter. But what could help is to make a comment in the yaml file. – Frank B Oct 19 '15 at 15:50

1 Answers1

2

If I were you I would refrain from reading the security settings for this as you can have multiple firewalls with multiple logins and your listener would thus have to listen to all of these (which might not be what you want) or artificially restrict to hardcoded firewalls. Also this will tie your implementation to Symfony's security-component, which you should avoid.

An easily reusable approach would be, to add the URL or route name you want to check for as argument to your listener and pass it via Symfony's Service Container and then just compare request with that value:

class LoginListener
{
    /**
     * @var string
     */
    protected $loginUrl;


    /**
     * @param string $loginUrl
     */
    public function __construct($loginUrl)
    {
        // You can even fallback to default if you like:
        if (empty($loginUrl)) {
            $loginUrl = '/login';
        }
        $this->loginUrl = $loginUrl;
    }

    // [...] your comparison just against $this->loginUrl
}

You can then use your bundle's configuration to pass the right argument to that listener.

This way you can easily reuse it outside of Symfony e.g. in Silex without being tied to Symfony's Security-component. Also if you want to check against multiple urls, you can just make it an array and specify the different login urls, e.g. when you have multiple login-mechanisms.

edit: In your bundle's Configuration you can check for parameters and define your fallbacks or an error message or whatever (see Getting and Setting Container Parameters).

edit:

in parameters.yml:

custom_login_path: /my_login

in security.yml:

    main:
        pattern: ^/
        form_login:
            provider: fos_userbundle
            csrf_provider: security.csrf.token_manager # Use form.csrf_provider instead for Symfony <2.4
            login_path: %custom_login_path%

in routing.yml:

fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"

# Make sure this follows "fos_user" so it takes precendece over the default
fos_user_security_login:
    path: %custom_login_path%
    defaults: { _controller: FOSUserBundle:Security:login }

in config.yml:

# config for listener in your bundle
my_bundle:
    login_path: %custom_login_path%
dbrumann
  • 16,803
  • 2
  • 42
  • 58
  • Thx, interesting solution. Your answer adds something to the issue: awareness of resuability beyond the SF's security-component. But let's back to my question: isn't it moving '/login' (or it's route name equivalent) hardcoded setting just to another place - to a listener's config in the DI config file? If not, how can I know the value of $loginUrl as used by SF security-component? – forsberg Oct 19 '15 at 16:03
  • Your loginUrl is a configuration. By default you set it in your security.yml under `firewalls.my_firewall.form_login.login_path` (/login is default, that's why FOSUserBundle doesn't show it in the security.yml in the docs). You can just set it as parameter and use it to set the value in your listener and security.yml. [FOSUserBundle has a route](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/config/routing/security.xml) you could overwrite in your app's routing.yml and things should still work. It's not hardcoding, it's configuration. You are overcomplicating things :) – dbrumann Oct 20 '15 at 08:55
  • Not really. If there was a general param in SF config named like, for example, "firewalls.my_firewall.form_login.login_path" :) then I could use it, and FOS User could use it, and any other bundle of part of app could rely on it as well. But according to your suggestion, I should either hardcode "/login", or am forced to overwrite it (e.g. with "/login"). It's really not flexible, and probably the easiest way in SF is to simply create a new param - thanks to which I won't have to use a "/login" string multiple times in an app. :) – forsberg Oct 20 '15 at 13:21
  • Acutally it works. I just tested it with symfony 2.7.5 in a fresh project, see updated answer. One value used for configuring multiple things. It's nothing like hardcoding ;) *drops mic* – dbrumann Oct 20 '15 at 13:58
  • Yeah, but it's the 2nd case: forcing to overwrite a param in case when there's no this param publically available. :) Thanx anyway, I upvoted your answer since it is a solution, but not exactly answering the question (it seems it's not possible in SF in normal way - yet another missing thing in SF). :) – forsberg Oct 20 '15 at 14:07
  • Actually overwriting the routing is how you would customize routes for FOSUserBundle: see [How to customize FOS UserBundle URLs](https://stackoverflow.com/questions/19608458/how-to-customize-fos-userbundle-urls). But if you don't like this approach depending on what you are trying to do you could use a [Voter](http://symfony.com/doc/master/cookbook/security/voters.html), a custom User- or AuthProvider. If this is not to your liking you can hook into [SecurityEvents::INTERACTIVE_LOGIN](http://api.symfony.com/master/Symfony/Component/Security/Http/SecurityEvents.html). – dbrumann Oct 21 '15 at 07:26