[Security] Fix logout
This commit is contained in:
parent
b7feafcf58
commit
9e88eb5aa9
@ -222,13 +222,14 @@ class SecurityExtension extends Extension
|
||||
$mapDef = $container->getDefinition('security.firewall.map');
|
||||
$map = $authenticationProviders = array();
|
||||
foreach ($firewalls as $name => $firewall) {
|
||||
list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds);
|
||||
list($matcher, $listeners, $exceptionListener, $logoutListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds);
|
||||
|
||||
$contextId = 'security.firewall.map.context.'.$name;
|
||||
$context = $container->setDefinition($contextId, new DefinitionDecorator('security.firewall.context'));
|
||||
$context
|
||||
->replaceArgument(0, $listeners)
|
||||
->replaceArgument(1, $exceptionListener)
|
||||
->replaceArgument(2, $logoutListener)
|
||||
;
|
||||
$map[$contextId] = $matcher;
|
||||
}
|
||||
@ -259,7 +260,7 @@ class SecurityExtension extends Extension
|
||||
|
||||
// Security disabled?
|
||||
if (false === $firewall['security']) {
|
||||
return array($matcher, array(), null);
|
||||
return array($matcher, array(), null, null);
|
||||
}
|
||||
|
||||
// Provider id (take the first registered provider if none defined)
|
||||
@ -286,15 +287,15 @@ class SecurityExtension extends Extension
|
||||
}
|
||||
|
||||
// Logout listener
|
||||
$logoutListenerId = null;
|
||||
if (isset($firewall['logout'])) {
|
||||
$listenerId = 'security.logout_listener.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener'));
|
||||
$listener->replaceArgument(3, array(
|
||||
$logoutListenerId = 'security.logout_listener.'.$id;
|
||||
$logoutListener = $container->setDefinition($logoutListenerId, new DefinitionDecorator('security.logout_listener'));
|
||||
$logoutListener->replaceArgument(3, array(
|
||||
'csrf_parameter' => $firewall['logout']['csrf_parameter'],
|
||||
'intention' => $firewall['logout']['csrf_token_id'],
|
||||
'logout_path' => $firewall['logout']['path'],
|
||||
));
|
||||
$listeners[] = new Reference($listenerId);
|
||||
|
||||
// add logout success handler
|
||||
if (isset($firewall['logout']['success_handler'])) {
|
||||
@ -304,16 +305,16 @@ class SecurityExtension extends Extension
|
||||
$logoutSuccessHandler = $container->setDefinition($logoutSuccessHandlerId, new DefinitionDecorator('security.logout.success_handler'));
|
||||
$logoutSuccessHandler->replaceArgument(1, $firewall['logout']['target']);
|
||||
}
|
||||
$listener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
|
||||
$logoutListener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
|
||||
|
||||
// add CSRF provider
|
||||
if (isset($firewall['logout']['csrf_token_generator'])) {
|
||||
$listener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
|
||||
$logoutListener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
|
||||
}
|
||||
|
||||
// add session logout handler
|
||||
if (true === $firewall['logout']['invalidate_session'] && false === $firewall['stateless']) {
|
||||
$listener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
|
||||
$logoutListener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
|
||||
}
|
||||
|
||||
// add cookie logout handler
|
||||
@ -322,12 +323,12 @@ class SecurityExtension extends Extension
|
||||
$cookieHandler = $container->setDefinition($cookieHandlerId, new DefinitionDecorator('security.logout.handler.cookie_clearing'));
|
||||
$cookieHandler->addArgument($firewall['logout']['delete_cookies']);
|
||||
|
||||
$listener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
||||
$logoutListener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
||||
}
|
||||
|
||||
// add custom handlers
|
||||
foreach ($firewall['logout']['handlers'] as $handlerId) {
|
||||
$listener->addMethodCall('addHandler', array(new Reference($handlerId)));
|
||||
$logoutListener->addMethodCall('addHandler', array(new Reference($handlerId)));
|
||||
}
|
||||
|
||||
// register with LogoutUrlGenerator
|
||||
@ -362,7 +363,7 @@ class SecurityExtension extends Extension
|
||||
// Exception listener
|
||||
$exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $configuredEntryPoint ?: $defaultEntryPoint, $firewall['stateless']));
|
||||
|
||||
return array($matcher, $listeners, $exceptionListener);
|
||||
return array($matcher, $listeners, $exceptionListener, null !== $logoutListenerId ? new Reference($logoutListenerId) : null);
|
||||
}
|
||||
|
||||
private function createContextListener($container, $contextKey)
|
||||
|
@ -150,6 +150,7 @@
|
||||
<service id="security.firewall.context" class="%security.firewall.context.class%" abstract="true">
|
||||
<argument type="collection" />
|
||||
<argument type="service" id="security.exception_listener" />
|
||||
<argument /> <!-- LogoutListener -->
|
||||
</service>
|
||||
|
||||
<service id="security.logout_url_generator" class="Symfony\Component\Security\Http\Logout\LogoutUrlGenerator" public="false">
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
/**
|
||||
* This is a wrapper around the actual firewall configuration which allows us
|
||||
@ -23,15 +24,17 @@ class FirewallContext
|
||||
{
|
||||
private $listeners;
|
||||
private $exceptionListener;
|
||||
private $logoutListener;
|
||||
|
||||
public function __construct(array $listeners, ExceptionListener $exceptionListener = null)
|
||||
public function __construct(array $listeners, ExceptionListener $exceptionListener = null, LogoutListener $logoutListener = null)
|
||||
{
|
||||
$this->listeners = $listeners;
|
||||
$this->exceptionListener = $exceptionListener;
|
||||
$this->logoutListener = $logoutListener;
|
||||
}
|
||||
|
||||
public function getContext()
|
||||
{
|
||||
return array($this->listeners, $this->exceptionListener);
|
||||
return array($this->listeners, $this->exceptionListener, $this->logoutListener);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,6 @@ class FirewallMap implements FirewallMapInterface
|
||||
}
|
||||
}
|
||||
|
||||
return array(array(), null);
|
||||
return array(array(), null, null);
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,6 @@ abstract class CompleteConfigurationTest extends TestCase
|
||||
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',
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
|
||||
|
||||
class LogoutTest extends WebTestCase
|
||||
{
|
||||
public function testSessionLessRememberMeLogout()
|
||||
{
|
||||
$client = $this->createClient(array('test_case' => 'RememberMeLogout', 'root_config' => 'config.yml'));
|
||||
|
||||
$client->request('POST', '/login', array(
|
||||
'_username' => 'johannes',
|
||||
'_password' => 'test',
|
||||
));
|
||||
|
||||
$cookieJar = $client->getCookieJar();
|
||||
$cookieJar->expire(session_name());
|
||||
|
||||
$this->assertNotNull($cookieJar->get('REMEMBERME'));
|
||||
|
||||
$client->request('GET', '/logout');
|
||||
|
||||
$this->assertNull($cookieJar->get('REMEMBERME'));
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
|
||||
return array(
|
||||
new FrameworkBundle(),
|
||||
new SecurityBundle(),
|
||||
);
|
@ -0,0 +1,25 @@
|
||||
imports:
|
||||
- { resource: ./../config/framework.yml }
|
||||
|
||||
security:
|
||||
encoders:
|
||||
Symfony\Component\Security\Core\User\User: plaintext
|
||||
|
||||
providers:
|
||||
in_memory:
|
||||
memory:
|
||||
users:
|
||||
johannes: { password: test, roles: [ROLE_USER] }
|
||||
|
||||
firewalls:
|
||||
default:
|
||||
form_login:
|
||||
check_path: login
|
||||
remember_me: true
|
||||
require_previous_session: false
|
||||
remember_me:
|
||||
always_remember_me: true
|
||||
key: key
|
||||
logout: ~
|
||||
anonymous: ~
|
||||
stateless: true
|
@ -0,0 +1,5 @@
|
||||
login:
|
||||
path: /login
|
||||
|
||||
logout:
|
||||
path: /logout
|
@ -18,7 +18,7 @@
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"ext-xml": "*",
|
||||
"symfony/security": "~2.7.38|~2.8.31",
|
||||
"symfony/security": "~2.7.47|~2.8.40",
|
||||
"symfony/security-acl": "~2.7",
|
||||
"symfony/http-kernel": "~2.7"
|
||||
},
|
||||
|
@ -47,20 +47,29 @@ class Firewall implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
// register listeners for this firewall
|
||||
list($listeners, $exceptionListener) = $this->map->getListeners($event->getRequest());
|
||||
$listeners = $this->map->getListeners($event->getRequest());
|
||||
|
||||
$authenticationListeners = $listeners[0];
|
||||
$exceptionListener = $listeners[1];
|
||||
$logoutListener = isset($listeners[2]) ? $listeners[2] : null;
|
||||
|
||||
if (null !== $exceptionListener) {
|
||||
$this->exceptionListeners[$event->getRequest()] = $exceptionListener;
|
||||
$exceptionListener->register($this->dispatcher);
|
||||
}
|
||||
|
||||
// initiate the listener chain
|
||||
foreach ($listeners as $listener) {
|
||||
foreach ($authenticationListeners as $listener) {
|
||||
$listener->handle($event);
|
||||
|
||||
if ($event->hasResponse()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $logoutListener) {
|
||||
$logoutListener->handle($event);
|
||||
}
|
||||
}
|
||||
|
||||
public function onKernelFinishRequest(FinishRequestEvent $event)
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Http;
|
||||
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
/**
|
||||
* FirewallMap allows configuration of different firewalls for specific parts
|
||||
@ -25,9 +26,9 @@ class FirewallMap implements FirewallMapInterface
|
||||
{
|
||||
private $map = array();
|
||||
|
||||
public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null)
|
||||
public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null, LogoutListener $logoutListener = null)
|
||||
{
|
||||
$this->map[] = array($requestMatcher, $listeners, $exceptionListener);
|
||||
$this->map[] = array($requestMatcher, $listeners, $exceptionListener, $logoutListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,10 +38,10 @@ class FirewallMap implements FirewallMapInterface
|
||||
{
|
||||
foreach ($this->map as $elements) {
|
||||
if (null === $elements[0] || $elements[0]->matches($request)) {
|
||||
return array($elements[1], $elements[2]);
|
||||
return array($elements[1], $elements[2], $elements[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return array(array(), null);
|
||||
return array(array(), null, null);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user