8000 Retrieve the current firewall name for a Request · Issue #14435 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content
8000

Retrieve the current firewall name for a Request #14435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
trsteel88 opened this issue Apr 21, 2015 · 10 comments
Closed

Retrieve the current firewall name for a Request #14435

trsteel88 opened this issue Apr 21, 2015 · 10 comments

Comments

@trsteel88
Copy link
Contributor

I am trying to determine the current firewall name for a Request (application has multiple firewalls). Is this possible?

I can see a map is creating in SecurityExtension.php

However, I can't use this map as it is only available to the Firewall which doesn't expose a way to get the map. Secondly, from what I can see, the firewall name isn't stored anywhere for me to retrieve this as everything references services.

I can see that a ProviderKey() is available for some tokens (e.g UsernamePasswordToken). However, this method is not on the TokenInterface so I cannot rely on it.

Basically I want to add a generic EventListener for Authentication successes/failures. It needs to store the firewall name so it can be determined which firewall a user was trying to login to.

@hacfi
Copy link
Contributor
hacfi commented Apr 21, 2015

@trsteel88 Just debugged this issue and I think you’re right..the firewall name is not accessible directly.

If you urgently need this you can create a very ugly hack:
Add a compiler pass which "steals" the security firewall map:

        $map = $container->getDefinition('security.firewall.map');

        $maps = $map->getArgument(1);

        $refs = [];

        foreach ($maps as $serviceName => $firewall) {
            $refs[substr($serviceName, 30)] = $firewall;
        }

then you add $refs to a service which contains the same logic as Symfony\Bundle\SecurityBundle\Security\FirewallMap: https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php#L38-42

and make the result available.

I agree that this should be exposed :).

@trsteel88
Copy link
Contributor Author

Thanks for getting back to me @hacfi. I considered that but it felt very hacky.

I thought it may have been exposed somewhere so I was trying to avoid it. Since it isn't, I will have to use this method.

Would love to see a public method made available.

@linaori
Copy link
Contributor
linaori commented Apr 22, 2015

The new logout function of twig in 2.7 has support for a specific firewall, maybe that can point you in the right direction.

@jaytaph
Copy link
Contributor
jaytaph commented Apr 22, 2015

That code is actually inside the logout generator:

if (null === $key && null !== $this->tokenStorage) {

It will try and fetch the providerKey from the current token. It assumes that each firewall has a providerkey that matches the firewall name (this doesn't have to be the case though, sometime you have multiple firewalls all using the same provider key).

@ghost
Copy link
ghost commented May 26, 2015

Another use case: SonataUserBundle checks, whether it should render an "impersonate" button in the user admin:
https://github.com/sonata-project/SonataUserBundle/blob/master/Admin/Model/UserAdmin.php#L68

The role necessary however is configurable. So it would be necessary to retrieve not only the name of the current firewall but the configuration of the current firewall.

It would be good to have the active firewall available as a service so one could retrieve informations as necessary.

@linaori
Copy link
Contributor
linaori commented May 26, 2015

What about a FirewallAwareTokenInterface that has the getProviderKey method? I would vote to rename it though, provider key is very confusing because we're talking about a firewall (context) identifier.

On a side note, would this be something to store in the token attributes instead? Maybe @stof knows this.

@ghost
Copy link
ghost commented Jun 8, 2015

I think more useful (and consistent with the name FirewallAwareTokenInterface) would be a method getFirewall that returns an object representing the firewall that can be questioned. That's easier than trying to lookup all informations from the configuration by the providerKey.

As of Symfony 2.6 we have Symfony\Component\Security\Http\Firewall which is actually a listener and Symfony\Bundle\SecurityBundle\Security\FirewallContext. But we don't have a class / inteface representing a Firewall:

interface Firewall
{
  function getKey();
  function getContext();
  function getRequestMatcher():
  function getProvider();
  /**
   * This function can be used to lookup firewall configuration
   * values that are not exposed with more specific methods.
   * @return array map of the firewall configuration
   */
  function getConfig();
}

@trsteel88
Copy link
Contributor Author

fyi, this is how I am retrieving the firewall name:

Utility to retrieve firewall name:

<?php

namespace Vivo\SecurityBundle\Util;

use Symfony\Component\HttpFoundation\Request;

class FirewallManager
{
    /**
     * @var \Symfony\Component\HttpFoundation\RequestMatcher[]
     */
    private $map;

    /**
     * @param \Symfony\Component\HttpFoundation\RequestMatcher[] $map
     */
    public function __construct(array $map)
    {
        $this->map = $map;
    }

    /**
     * @param  Request     $request
     * @return string|null
     */
    public function getFirewallNameForRequest(Request $request)
    {
        foreach ($this->map as $firewallName => $requestMatcher) {
            if (null === $requestMatcher || $requestMatcher->matches($request)) {
                return $firewallName;
            }
        }

        return null;
    }
}

Compiler pass to inject firewall map:

<?php

namespace Acme\DemoBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

class FirewallManagerCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (false === $container->hasAlias('acme_demo.util.firewall_manager') && false === $container->hasDefinition('acme_demo.util.firewall_manager')) {
            return;
        }

        $map = $container->getDefinition('security.firewall.map');
        $maps = $map->getArgument(1);

        $refs = [];
        foreach ($maps as $serviceName => $firewall) {
            $refs[substr($serviceName, 30)] = $firewall;
        }

        $firewallManagerDef = $container->getDefinition('acme_demo.util.firewall_manager');
        $firewallManagerDef->replaceArgument(0, $refs);
    }
}

@caponica
Copy link
Contributor

👍

@javiereguiluz
Copy link
Member

Closing it in favor of #15294, which would not only provide the name of the firewall but more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants
0