From d4a6f6c817aa973f3e5367c34898540d556cf010 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sat, 2 Dec 2017 17:46:48 +0100 Subject: [PATCH 1/7] [SecurityBundle] fix setLogoutOnUserChange calls for context listeners --- .../DependencyInjection/SecurityExtension.php | 14 +++++++++----- .../DependencyInjection/SecurityExtensionTest.php | 10 +++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 835794f15fdd5..064c663fb7b52 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -276,15 +276,19 @@ private function createFirewalls($config, ContainerBuilder $container) $customUserChecker = true; } + $configId = 'security.firewall.map.config.'.$name; + + list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); + if (!isset($firewall['logout_on_user_change']) || !$firewall['logout_on_user_change']) { @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $name), E_USER_DEPRECATED); } - $contextListenerDefinition->addMethodCall('setLogoutOnUserChange', array($firewall['logout_on_user_change'])); - - $configId = 'security.firewall.map.config.'.$name; - - list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); + foreach ($listeners as $listener) { + if (0 === strpos($listenerId = (string) $listener, 'security.context_listener.')) { + $container->getDefinition($listenerId)->addMethodCall('setLogoutOnUserChange', array($firewall['logout_on_user_change'])); + } + } $contextId = 'security.firewall.map.context.'.$name; $context = $container->setDefinition($contextId, new ChildDefinition('security.firewall.context')); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 0b339188e7590..a5fb1c477fd70 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -127,7 +127,7 @@ public function testDisableRoleHierarchyVoter() * @group legacy * @expectedDeprecation Not setting "logout_on_user_change" to true on firewall "some_firewall" is deprecated as of 3.4, it will always be true in 4.0. */ - public function testDeprecationForUserLogout() + public function testConfiguresLogoutOnUserChangeForContextListenersCorrectly() { $container = $this->getRawContainer(); @@ -142,10 +142,18 @@ public function testDeprecationForUserLogout() 'http_basic' => null, 'logout_on_user_change' => false, ), + 'some_other_firewall' => array( + 'pattern' => '/.*', + 'http_basic' => null, + 'logout_on_user_change' => true, + ), ), )); $container->compile(); + + $this->assertEquals(array(array('setLogoutOnUserChange', array(false))), $container->getDefinition('security.context_listener.0')->getMethodCalls()); + $this->assertEquals(array(array('setLogoutOnUserChange', array(true))), $container->getDefinition('security.context_listener.1')->getMethodCalls()); } /** From 98abd1e58d5aada23ab0c875f56aab242e8a9484 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 3 Dec 2017 10:22:00 +0100 Subject: [PATCH 2/7] review feedback --- .../DependencyInjection/SecurityExtension.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 064c663fb7b52..1708b0aa1686e 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -276,17 +276,18 @@ private function createFirewalls($config, ContainerBuilder $container) $customUserChecker = true; } - $configId = 'security.firewall.map.config.'.$name; - - list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); - if (!isset($firewall['logout_on_user_change']) || !$firewall['logout_on_user_change']) { @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $name), E_USER_DEPRECATED); } + $configId = 'security.firewall.map.config.'.$name; + + list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); + foreach ($listeners as $listener) { if (0 === strpos($listenerId = (string) $listener, 'security.context_listener.')) { $container->getDefinition($listenerId)->addMethodCall('setLogoutOnUserChange', array($firewall['logout_on_user_change'])); + break; } } From fb42305bd07910379676b7f4feb3ea874c282a48 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 3 Dec 2017 11:09:12 +0100 Subject: [PATCH 3/7] review feedback #2 --- .../DependencyInjection/SecurityExtension.php | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 1708b0aa1686e..3560e6f31bcfd 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -276,21 +276,10 @@ private function createFirewalls($config, ContainerBuilder $container) $customUserChecker = true; } - if (!isset($firewall['logout_on_user_change']) || !$firewall['logout_on_user_change']) { - @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $name), E_USER_DEPRECATED); - } - $configId = 'security.firewall.map.config.'.$name; list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); - foreach ($listeners as $listener) { - if (0 === strpos($listenerId = (string) $listener, 'security.context_listener.')) { - $container->getDefinition($listenerId)->addMethodCall('setLogoutOnUserChange', array($firewall['logout_on_user_change'])); - break; - } - } - $contextId = 'security.firewall.map.context.'.$name; $context = $container->setDefinition($contextId, new ChildDefinition('security.firewall.context')); $context @@ -375,7 +364,11 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $contextKey = $firewall['context']; } - $listeners[] = new Reference($this->createContextListener($container, $contextKey)); + if (!isset($firewall['logout_on_user_change']) || !$firewall['logout_on_user_change']) { + @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $id), E_USER_DEPRECATED); + } + + $listeners[] = new Reference($this->createContextListener($container, $contextKey, $firewall['logout_on_user_change'])); } $config->replaceArgument(6, $contextKey); @@ -486,7 +479,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a return array($matcher, $listeners, $exceptionListener); } - private function createContextListener($container, $contextKey) + private function createContextListener($container, $contextKey, $logoutUserOnChange) { if (isset($this->contextListeners[$contextKey])) { return $this->contextListeners[$contextKey]; @@ -495,6 +488,7 @@ private function createContextListener($container, $contextKey) $listenerId = 'security.context_listener.'.count($this->contextListeners); $listener = $container->setDefinition($listenerId, new ChildDefinition('security.context_listener')); $listener->replaceArgument(2, $contextKey); + $listener->addMethodCall('setLogoutOnUserChange', array($logoutUserOnChange)); return $this->contextListeners[$contextKey] = $listenerId; } From d9d74770ae2288dcb550a966f9e5b27b369ef129 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 3 Dec 2017 18:51:26 +0100 Subject: [PATCH 4/7] throw if sharing context with different logout_on_user_change values --- .../DependencyInjection/SecurityExtension.php | 8 ++++- .../SecurityExtensionTest.php | 34 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 3560e6f31bcfd..cd7bc51dfdb77 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -43,6 +43,7 @@ class SecurityExtension extends Extension private $factories = array(); private $userProviderFactories = array(); private $expressionLanguage; + private $firewallsByContextKey = array(); public function __construct() { @@ -368,6 +369,11 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $id), E_USER_DEPRECATED); } + if (isset($this->firewallsByContextKey[$contextKey]) && $firewall['logout_on_user_change'] !== $this->firewallsByContextKey[$contextKey][1]['logout_on_user_change']) { + throw new InvalidConfigurationException(sprintf('Firewalls "%s" and "%s" need to have the same value for option "logout_on_user_change" as they are sharing the context "%s"', $this->firewallsByContextKey[$contextKey][0], $id, $contextKey)); + } + + $this->firewallsByContextKey[$contextKey] = array($id, $firewall); $listeners[] = new Reference($this->createContextListener($container, $contextKey, $firewall['logout_on_user_change'])); } @@ -479,7 +485,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a return array($matcher, $listeners, $exceptionListener); } - private function createContextListener($container, $contextKey, $logoutUserOnChange) + private function createContextListener(ContainerBuilder $container, $contextKey, $logoutUserOnChange) { if (isset($this->contextListeners[$contextKey])) { return $this->contextListeners[$contextKey]; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index a5fb1c477fd70..6c19d008eb008 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -15,6 +15,7 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension; use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\DummyProvider; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\ContainerBuilder; class SecurityExtensionTest extends TestCase @@ -135,7 +136,6 @@ public function testConfiguresLogoutOnUserChangeForContextListenersCorrectly() 'providers' => array( 'default' => array('id' => 'foo'), ), - 'firewalls' => array( 'some_firewall' => array( 'pattern' => '/.*', @@ -156,6 +156,38 @@ public function testConfiguresLogoutOnUserChangeForContextListenersCorrectly() $this->assertEquals(array(array('setLogoutOnUserChange', array(true))), $container->getDefinition('security.context_listener.1')->getMethodCalls()); } + /** + * @group legacy + * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException + * @expectedExceptionMessage Firewalls "some_firewall" and "some_other_firewall" need to have the same value for option "logout_on_user_change" as they are sharing the context "my_context" + */ + public function testThrowsIfLogoutOnUserChangeDifferentForSharedContext() + { + $container = $this->getRawContainer(); + + $container->loadFromExtension('security', array( + 'providers' => array( + 'default' => array('id' => 'foo'), + ), + 'firewalls' => array( + 'some_firewall' => array( + 'pattern' => '/.*', + 'http_basic' => null, + 'context' => 'my_context', + 'logout_on_user_change' => false, + ), + 'some_other_firewall' => array( + 'pattern' => '/.*', + 'http_basic' => null, + 'context' => 'my_context', + 'logout_on_user_change' => true, + ), + ), + )); + + $container->compile(); + } + /** * @group legacy * @expectedDeprecation Firewall "some_firewall" is configured as "stateless" but the "switch_user.stateless" key is set to false. Both should have the same value, the firewall's "stateless" value will be used as default value for the "switch_user.stateless" key in 4.0. From 3ece4c638971724547809e3ec922f86c8d84aa9d Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 3 Dec 2017 18:52:20 +0100 Subject: [PATCH 5/7] throw if sharing context with different logout_on_user_change values --- .../SecurityBundle/DependencyInjection/SecurityExtension.php | 2 +- .../Tests/DependencyInjection/SecurityExtensionTest.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index cd7bc51dfdb77..fd2f6a7c48e0d 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -369,7 +369,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $id), E_USER_DEPRECATED); } - if (isset($this->firewallsByContextKey[$contextKey]) && $firewall['logout_on_user_change'] !== $this->firewallsByContextKey[$contextKey][1]['logout_on_user_change']) { + if (isset($this->firewallsByContextKey[$contextKey]) && $this->firewallsByContextKey[$contextKey][1]['logout_on_user_change'] !== $firewall['logout_on_user_change']) { throw new InvalidConfigurationException(sprintf('Firewalls "%s" and "%s" need to have the same value for option "logout_on_user_change" as they are sharing the context "%s"', $this->firewallsByContextKey[$contextKey][0], $id, $contextKey)); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 6c19d008eb008..289c5af20f20d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -15,7 +15,6 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension; use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\DummyProvider; -use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\ContainerBuilder; class SecurityExtensionTest extends TestCase From 46572983049c8f8e8d2ef1479650fa56138f35f5 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 3 Dec 2017 18:53:40 +0100 Subject: [PATCH 6/7] revert unrelated change --- .../SecurityBundle/DependencyInjection/SecurityExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index fd2f6a7c48e0d..4e0866097b2ed 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -485,7 +485,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a return array($matcher, $listeners, $exceptionListener); } - private function createContextListener(ContainerBuilder $container, $contextKey, $logoutUserOnChange) + private function createContextListener($container, $contextKey, $logoutUserOnChange) { if (isset($this->contextListeners[$contextKey])) { return $this->contextListeners[$contextKey]; From 8174c954ac3b0d282d929fc619a7f9016dedaaf1 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Mon, 4 Dec 2017 19:02:42 +0100 Subject: [PATCH 7/7] refactor + cleanup --- .../DependencyInjection/MainConfiguration.php | 11 ----------- .../DependencyInjection/SecurityExtension.php | 12 ++++++------ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index fb66cf78e706e..ad076f05e71e1 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -340,17 +340,6 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto return $firewall; }) ->end() - ->validate() - ->ifTrue(function ($v) { - return (isset($v['stateless']) && true === $v['stateless']) || (isset($v['security']) && false === $v['security']); - }) - ->then(function ($v) { - // this option doesn't change behavior when true when stateless, so prevent deprecations - $v['logout_on_user_change'] = true; - - return $v; - }) - ->end() ; } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 4e0866097b2ed..1bc06b1f47900 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -43,7 +43,7 @@ class SecurityExtension extends Extension private $factories = array(); private $userProviderFactories = array(); private $expressionLanguage; - private $firewallsByContextKey = array(); + private $logoutOnUserChangeByContextKey = array(); public function __construct() { @@ -365,16 +365,16 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $contextKey = $firewall['context']; } - if (!isset($firewall['logout_on_user_change']) || !$firewall['logout_on_user_change']) { + if (!$logoutOnUserChange = $firewall['logout_on_user_change']) { @trigger_error(sprintf('Not setting "logout_on_user_change" to true on firewall "%s" is deprecated as of 3.4, it will always be true in 4.0.', $id), E_USER_DEPRECATED); } - if (isset($this->firewallsByContextKey[$contextKey]) && $this->firewallsByContextKey[$contextKey][1]['logout_on_user_change'] !== $firewall['logout_on_user_change']) { - throw new InvalidConfigurationException(sprintf('Firewalls "%s" and "%s" need to have the same value for option "logout_on_user_change" as they are sharing the context "%s"', $this->firewallsByContextKey[$contextKey][0], $id, $contextKey)); + if (isset($this->logoutOnUserChangeByContextKey[$contextKey]) && $this->logoutOnUserChangeByContextKey[$contextKey][1] !== $logoutOnUserChange) { + throw new InvalidConfigurationException(sprintf('Firewalls "%s" and "%s" need to have the same value for option "logout_on_user_change" as they are sharing the context "%s"', $this->logoutOnUserChangeByContextKey[$contextKey][0], $id, $contextKey)); } - $this->firewallsByContextKey[$contextKey] = array($id, $firewall); - $listeners[] = new Reference($this->createContextListener($container, $contextKey, $firewall['logout_on_user_change'])); + $this->logoutOnUserChangeByContextKey[$contextKey] = array($id, $logoutOnUserChange); + $listeners[] = new Reference($this->createContextListener($container, $contextKey, $logoutOnUserChange)); } $config->replaceArgument(6, $contextKey);