diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
index 544e1de1921af..7904fa889e852 100644
--- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\SecurityBundle\DataCollector;
+use Symfony\Bundle\SecurityBundle\Security\FirewallConfigRegistry;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -21,8 +22,6 @@
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authorization\DebugAccessDecisionManager;
use Symfony\Component\VarDumper\Cloner\Data;
-use Symfony\Component\Security\Http\FirewallMapInterface;
-use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
/**
* SecurityDataCollector.
@@ -35,7 +34,7 @@ class SecurityDataCollector extends DataCollector
private $roleHierarchy;
private $logoutUrlGenerator;
private $accessDecisionManager;
- private $firewallMap;
+ private $firewallConfigRegistry;
/**
* Constructor.
@@ -44,15 +43,15 @@ class SecurityDataCollector extends DataCollector
* @param RoleHierarchyInterface|null $roleHierarchy
* @param LogoutUrlGenerator|null $logoutUrlGenerator
* @param AccessDecisionManagerInterface|null $accessDecisionManager
- * @param FirewallMapInterface|null $firewallMap
+ * @param FirewallConfigRegistry|null $firewallConfigRegistry
*/
- public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null, FirewallMapInterface $firewallMap = null)
+ public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null, FirewallConfigRegistry $firewallConfigRegistry = null)
{
$this->tokenStorage = $tokenStorage;
$this->roleHierarchy = $roleHierarchy;
$this->logoutUrlGenerator = $logoutUrlGenerator;
$this->accessDecisionManager = $accessDecisionManager;
- $this->firewallMap = $firewallMap;
+ $this->firewallConfigRegistry = $firewallConfigRegistry;
}
/**
@@ -140,9 +139,8 @@ public function collect(Request $request, Response $response, \Exception $except
// collect firewall context information
$this->data['firewall'] = null;
- if ($this->firewallMap instanceof FirewallMap) {
- $firewallConfig = $this->firewallMap->getFirewallConfig($request);
- if (null !== $firewallConfig) {
+ if (null !== $this->firewallConfigRegistry) {
+ if (null !== $firewallConfig = $this->firewallConfigRegistry->fromRequest($request)) {
$this->data['firewall'] = array(
'name' => $firewallConfig->getName(),
'allows_anonymous' => $firewallConfig->allowsAnonymous(),
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
index 5c88548bcff1d..ba48030725940 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
@@ -236,8 +236,10 @@ private function createFirewalls($config, ContainerBuilder $container)
// load firewall map
$mapDef = $container->getDefinition('security.firewall.map');
$map = $authenticationProviders = array();
+ $firewallConfigs = array();
+ $matchers = array();
foreach ($firewalls as $name => $firewall) {
- $configId = 'security.firewall.map.config.'.$name;
+ $configId = 'security.firewall.config.'.$name;
list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId);
@@ -246,10 +248,11 @@ private function createFirewalls($config, ContainerBuilder $container)
$context
->replaceArgument(0, $listeners)
->replaceArgument(1, $exceptionListener)
- ->replaceArgument(2, new Reference($configId))
;
$map[$contextId] = $matcher;
+ $matchers[$name] = $matcher;
+ $firewallConfigs[] = new Reference($configId);
}
$mapDef->replaceArgument(1, $map);
@@ -261,6 +264,11 @@ private function createFirewalls($config, ContainerBuilder $container)
->getDefinition('security.authentication.manager')
->replaceArgument(0, $authenticationProviders)
;
+
+ $container->getDefinition('security.firewall.config_registry')
+ ->replaceArgument(0, $firewallConfigs)
+ ->replaceArgument(1, $matchers)
+ ;
}
private function createFirewall(ContainerBuilder $container, $id, $firewall, &$authenticationProviders, $providerIds, $configId)
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml
index f812a9d790bb8..f726d7e46ea37 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
index 8def320482486..8cd6b1b8be574 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
@@ -103,6 +103,12 @@
+
+
+
+
+
+
@@ -111,7 +117,6 @@
-
diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfigRegistry.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfigRegistry.php
new file mode 100644
index 0000000000000..a7dc62d8923b1
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfigRegistry.php
@@ -0,0 +1,119 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\SecurityBundle\Security;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestMatcher;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * Stores firewall config objects.
+ *
+ * @author Maxime Steinhausser
+ */
+class FirewallConfigRegistry
+{
+ private $firewallConfigs;
+ private $requestStack;
+ private $requestMatchers;
+
+ /**
+ * @param FirewallConfig[] $firewallConfigs
+ * @param RequestMatcher[] $requestMatchers Indexed by firewall name
+ * @param RequestStack|null $requestStack To get the current firewall config
+ */
+ public function __construct(array $firewallConfigs = array(), array $requestMatchers = array(), RequestStack $requestStack = null)
+ {
+ $this->firewallConfigs = $firewallConfigs;
+ $this->requestStack = $requestStack;
+ $this->requestMatchers = $requestMatchers;
+ }
+
+ /**
+ * @param string $name The firewall name
+ *
+ * @return FirewallConfig|null
+ */
+ public function get($name)
+ {
+ foreach ($this->firewallConfigs as $config) {
+ if ($config->getName() === $name) {
+ return $config;
+ }
+ }
+ }
+
+ /**
+ * @return FirewallConfig|null
+ */
+ public function current()
+ {
+ if (!$this->requestStack) {
+ throw new \LogicException('Unable to get current firewall config without a RequestStack.');
+ }
+
+ return $this->fromRequest($this->requestStack->getCurrentRequest());
+ }
+
+ /**
+ * @param Request $request
+ *
+ * @return FirewallConfig|null
+ */
+ public function fromRequest(Request $request)
+ {
+ foreach ($this->firewallConfigs as $config) {
+ $requestMatcher = $this->getRequestMatcher($config);
+ if (null === $requestMatcher || $requestMatcher->matches($request)) {
+ return $config;
+ }
+ }
+ }
+
+ /**
+ * @return FirewallConfig[]
+ */
+ public function all()
+ {
+ return $this->firewallConfigs;
+ }
+
+ /**
+ * @return FirewallConfig[]
+ */
+ public function inContext($context)
+ {
+ return array_filter($this->firewallConfigs, function (FirewallConfig $config) use ($context) {
+ return $context === $config->getContext();
+ });
+ }
+
+ /**
+ * @param FirewallConfig $config
+ *
+ * @return RequestMatcher|null
+ */
+ private function getRequestMatcher(FirewallConfig $config)
+ {
+ if (empty($config->getRequestMatcher())) {
+ return;
+ }
+
+ $firewallName = $config->getName();
+
+ if (!isset($this->requestMatchers[$firewallName])) {
+ throw new \LogicException(sprintf('Request matcher not found for "%s" firewall.', $firewallName));
+ }
+
+ return $this->requestMatchers[$firewallName];
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php
index 9d00c121e5160..13d096d97e951 100644
--- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php
+++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php
@@ -23,22 +23,11 @@ class FirewallContext
{
private $listeners;
private $exceptionListener;
- private $config;
- public function __construct(array $listeners, ExceptionListener $exceptionListener = null, FirewallConfig $config = null)
+ public function __construct(array $listeners, ExceptionListener $exceptionListener = null)
{
- if (null === $config) {
- @trigger_error(sprintf('"%s()" expects an instance of "%s" as third argument since version 3.2 and will trigger an error in 4.0 if not provided.', __METHOD__, FirewallConfig::class), E_USER_DEPRECATED);
- }
-
$this->listeners = $listeners;
$this->exceptionListener = $exceptionListener;
- $this->config = $config;
- }
-
- public function getConfig()
- {
- return $this->config;
}
public function getContext()
diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php
index f833a63e65966..2944165532705 100644
--- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php
+++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php
@@ -49,20 +49,6 @@ public function getListeners(Request $request)
return $context->getContext();
}
- /**
- * @return FirewallConfig|null
- */
- public function getFirewallConfig(Request $request)
- {
- $context = $this->getFirewallContext($request);
-
- if (null === $context) {
- return;
- }
-
- return $context->getConfig();
- }
-
private function getFirewallContext(Request $request)
{
if ($this->contexts->contains($request)) {
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
index 2d912721ed4f4..ca953b63ab150 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
@@ -13,12 +13,11 @@
use Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
-use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
+use Symfony\Bundle\SecurityBundle\Security\FirewallConfigRegistry;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
-use Symfony\Component\Security\Http\FirewallMapInterface;
class SecurityDataCollectorTest extends \PHPUnit_Framework_TestCase
{
@@ -81,17 +80,17 @@ public function testGetFirewall()
$firewallConfig = new FirewallConfig('dummy', 'security.request_matcher.dummy', 'security.user_checker.dummy');
$request = $this->getRequest();
- $firewallMap = $this
- ->getMockBuilder(FirewallMap::class)
+ $registry = $this
+ ->getMockBuilder(FirewallConfigRegistry::class)
->disableOriginalConstructor()
->getMock();
- $firewallMap
+ $registry
->expects($this->once())
- ->method('getFirewallConfig')
+ ->method('fromRequest')
->with($request)
->willReturn($firewallConfig);
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap);
+ $collector = new SecurityDataCollector(null, null, null, null, $registry);
$collector->collect($request, $this->getResponse());
$collected = $collector->getFirewall();
@@ -119,23 +118,13 @@ public function testGetFirewallReturnsNull()
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
- // Inject an instance that is not context aware
- $firewallMap = $this
- ->getMockBuilder(FirewallMapInterface::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap);
- $collector->collect($request, $response);
- $this->assertNull($collector->getFirewall());
-
// Null config
- $firewallMap = $this
- ->getMockBuilder(FirewallMap::class)
+ $registry = $this
+ ->getMockBuilder(FirewallConfigRegistry::class)
->disableOriginalConstructor()
->getMock();
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap);
+ $collector = new SecurityDataCollector(null, null, null, null, $registry);
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
index 34e3ad56114ac..35cbbceff1065 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
@@ -65,14 +65,47 @@ public function testFirewalls()
$container = $this->getContainer('container1');
$arguments = $container->getDefinition('security.firewall.map')->getArguments();
$listeners = array();
- $configs = array();
foreach (array_keys($arguments[1]) as $contextId) {
$contextDef = $container->getDefinition($contextId);
$arguments = $contextDef->getArguments();
$listeners[] = array_map(function ($ref) { return (string) $ref; }, $arguments['index_0']);
+ }
+
+ $this->assertEquals(array(
+ array(),
+ array(
+ 'security.channel_listener',
+ 'security.logout_listener.secure',
+ 'security.authentication.listener.x509.secure',
+ 'security.authentication.listener.remote_user.secure',
+ 'security.authentication.listener.form.secure',
+ 'security.authentication.listener.basic.secure',
+ 'security.authentication.listener.digest.secure',
+ 'security.authentication.listener.rememberme.secure',
+ 'security.authentication.listener.anonymous.secure',
+ 'security.authentication.switchuser_listener.secure',
+ 'security.access_listener',
+ ),
+ array(
+ 'security.channel_listener',
+ 'security.context_listener.0',
+ 'security.authentication.listener.basic.host',
+ 'security.authentication.listener.anonymous.host',
+ 'security.access_listener',
+ ),
+ array(
+ 'security.channel_listener',
+ 'security.context_listener.1',
+ 'security.authentication.listener.basic.with_user_checker',
+ 'security.authentication.listener.anonymous.with_user_checker',
+ 'security.access_listener',
+ ),
+ ), $listeners);
- $configDef = $container->getDefinition($arguments['index_2']);
- $configs[] = array_values($configDef->getArguments());
+ $configs = array();
+ $configDefs = $container->getDefinition('security.firewall.config_registry')->getArgument(0);
+ foreach ($configDefs as $configRef) {
+ $configs[] = array_values($container->getDefinition($configRef)->getArguments());
}
$this->assertEquals(array(
@@ -131,37 +164,6 @@ public function testFirewalls()
),
),
), $configs);
-
- $this->assertEquals(array(
- array(),
- array(
- 'security.channel_listener',
- 'security.logout_listener.secure',
- 'security.authentication.listener.x509.secure',
- 'security.authentication.listener.remote_user.secure',
- 'security.authentication.listener.form.secure',
- 'security.authentication.listener.basic.secure',
- 'security.authentication.listener.digest.secure',
- 'security.authentication.listener.rememberme.secure',
- 'security.authentication.listener.anonymous.secure',
- 'security.authentication.switchuser_listener.secure',
- 'security.access_listener',
- ),
- array(
- 'security.channel_listener',
- 'security.context_listener.0',
- 'security.authentication.listener.basic.host',
- 'security.authentication.listener.anonymous.host',
- 'security.access_listener',
- ),
- array(
- 'security.channel_listener',
- 'security.context_listener.1',
- 'security.authentication.listener.basic.with_user_checker',
- 'security.authentication.listener.anonymous.with_user_checker',
- 'security.access_listener',
- ),
- ), $listeners);
}
public function testFirewallRequestMatchers()
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigRegistryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigRegistryTest.php
new file mode 100644
index 0000000000000..d6cce41c45aa5
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigRegistryTest.php
@@ -0,0 +1,92 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\SecurityBundle\Tests\Security;
+
+use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
+use Symfony\Bundle\SecurityBundle\Security\FirewallConfigRegistry;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestMatcher;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+class FirewallConfigRegistryTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGet()
+ {
+ $registry = new FirewallConfigRegistry(array(
+ $adminConfig = new FirewallConfig('admin', 'admin_request_matcher', 'user_checker'),
+ $appConfig = new FirewallConfig('app', '', 'user_checker'),
+ ));
+
+ $this->assertSame($adminConfig, $registry->get('admin'));
+ $this->assertSame($appConfig, $registry->get('app'));
+ }
+
+ public function testAll()
+ {
+ $registry = new FirewallConfigRegistry(array(
+ $adminConfig = new FirewallConfig('admin', 'admin_request_matcher', 'user_checker'),
+ $appConfig = new FirewallConfig('app', '', 'user_checker'),
+ ));
+
+ $this->assertSame(array($adminConfig, $appConfig), $registry->all());
+ }
+
+ public function testInContext()
+ {
+ $registry = new FirewallConfigRegistry(array(
+ $adminConfig = new FirewallConfig('admin', 'admin_request_matcher', 'user_checker', true, false, null, 'secured'),
+ $appConfig = new FirewallConfig('app', '', 'user_checker', true, false, null, 'secured'),
+ new FirewallConfig('stateless', '', 'user_checker', true, true, null, null),
+ ));
+
+ $this->assertSame(array($adminConfig, $appConfig), $registry->inContext('secured'));
+ }
+
+ public function testFromRequest()
+ {
+ $registry = new FirewallConfigRegistry(array(
+ $adminConfig = new FirewallConfig('admin', 'admin_request_matcher', 'user_checker', true, false, null, 'secured'),
+ $appConfig = new FirewallConfig('app', '', 'user_checker', true, false, null, 'secured'),
+ ), array(
+ 'admin' => new RequestMatcher('/admin'),
+ ));
+
+ $request = $this->getMockBuilder(Request::class)
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+ $request->method('getPathInfo')->willReturn('/admin');
+
+ $this->assertSame($adminConfig, $registry->fromRequest($request));
+ }
+
+ public function testCurrent()
+ {
+ $requestStack = new RequestStack();
+
+ $request = $this->getMockBuilder(Request::class)
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+ $request->method('getPathInfo')->willReturn('/admin');
+ $requestStack->push($request);
+
+ $registry = new FirewallConfigRegistry(array(
+ $adminConfig = new FirewallConfig('admin', 'admin_request_matcher', 'user_checker', true, false, null, 'secured'),
+ $appConfig = new FirewallConfig('app', '', 'user_checker', true, false, null, 'secured'),
+ ), array(
+ 'admin' => new RequestMatcher('/admin'),
+ ), $requestStack);
+
+ $this->assertSame($adminConfig, $registry->current());
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php
index 098e2c51f80dd..99589a25be4c1 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php
@@ -11,7 +11,6 @@
namespace Symfony\Bundle\SecurityBundle\Tests\Security;
-use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
@@ -20,8 +19,6 @@ class FirewallContextTest extends \PHPUnit_Framework_TestCase
{
public function testGetters()
{
- $config = new FirewallConfig('main', 'request_matcher', 'user_checker');
-
$exceptionListener = $this
->getMockBuilder(ExceptionListener::class)
->disableOriginalConstructor()
@@ -34,9 +31,8 @@ public function testGetters()
->getMock(),
);
- $context = new FirewallContext($listeners, $exceptionListener, $config);
+ $context = new FirewallContext($listeners, $exceptionListener);
$this->assertEquals(array($listeners, $exceptionListener), $context->getContext());
- $this->assertEquals($config, $context->getConfig());
}
}