[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');
|
$mapDef = $container->getDefinition('security.firewall.map');
|
||||||
$map = $authenticationProviders = array();
|
$map = $authenticationProviders = array();
|
||||||
foreach ($firewalls as $name => $firewall) {
|
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;
|
$contextId = 'security.firewall.map.context.'.$name;
|
||||||
$context = $container->setDefinition($contextId, new DefinitionDecorator('security.firewall.context'));
|
$context = $container->setDefinition($contextId, new DefinitionDecorator('security.firewall.context'));
|
||||||
$context
|
$context
|
||||||
->replaceArgument(0, $listeners)
|
->replaceArgument(0, $listeners)
|
||||||
->replaceArgument(1, $exceptionListener)
|
->replaceArgument(1, $exceptionListener)
|
||||||
|
->replaceArgument(2, $logoutListener)
|
||||||
;
|
;
|
||||||
$map[$contextId] = $matcher;
|
$map[$contextId] = $matcher;
|
||||||
}
|
}
|
||||||
@ -259,7 +260,7 @@ class SecurityExtension extends Extension
|
|||||||
|
|
||||||
// Security disabled?
|
// Security disabled?
|
||||||
if (false === $firewall['security']) {
|
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)
|
// Provider id (take the first registered provider if none defined)
|
||||||
@ -286,15 +287,15 @@ class SecurityExtension extends Extension
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Logout listener
|
// Logout listener
|
||||||
|
$logoutListenerId = null;
|
||||||
if (isset($firewall['logout'])) {
|
if (isset($firewall['logout'])) {
|
||||||
$listenerId = 'security.logout_listener.'.$id;
|
$logoutListenerId = 'security.logout_listener.'.$id;
|
||||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener'));
|
$logoutListener = $container->setDefinition($logoutListenerId, new DefinitionDecorator('security.logout_listener'));
|
||||||
$listener->replaceArgument(3, array(
|
$logoutListener->replaceArgument(3, array(
|
||||||
'csrf_parameter' => $firewall['logout']['csrf_parameter'],
|
'csrf_parameter' => $firewall['logout']['csrf_parameter'],
|
||||||
'intention' => $firewall['logout']['csrf_token_id'],
|
'intention' => $firewall['logout']['csrf_token_id'],
|
||||||
'logout_path' => $firewall['logout']['path'],
|
'logout_path' => $firewall['logout']['path'],
|
||||||
));
|
));
|
||||||
$listeners[] = new Reference($listenerId);
|
|
||||||
|
|
||||||
// add logout success handler
|
// add logout success handler
|
||||||
if (isset($firewall['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 = $container->setDefinition($logoutSuccessHandlerId, new DefinitionDecorator('security.logout.success_handler'));
|
||||||
$logoutSuccessHandler->replaceArgument(1, $firewall['logout']['target']);
|
$logoutSuccessHandler->replaceArgument(1, $firewall['logout']['target']);
|
||||||
}
|
}
|
||||||
$listener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
|
$logoutListener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
|
||||||
|
|
||||||
// add CSRF provider
|
// add CSRF provider
|
||||||
if (isset($firewall['logout']['csrf_token_generator'])) {
|
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
|
// add session logout handler
|
||||||
if (true === $firewall['logout']['invalidate_session'] && false === $firewall['stateless']) {
|
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
|
// add cookie logout handler
|
||||||
@ -322,12 +323,12 @@ class SecurityExtension extends Extension
|
|||||||
$cookieHandler = $container->setDefinition($cookieHandlerId, new DefinitionDecorator('security.logout.handler.cookie_clearing'));
|
$cookieHandler = $container->setDefinition($cookieHandlerId, new DefinitionDecorator('security.logout.handler.cookie_clearing'));
|
||||||
$cookieHandler->addArgument($firewall['logout']['delete_cookies']);
|
$cookieHandler->addArgument($firewall['logout']['delete_cookies']);
|
||||||
|
|
||||||
$listener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
$logoutListener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add custom handlers
|
// add custom handlers
|
||||||
foreach ($firewall['logout']['handlers'] as $handlerId) {
|
foreach ($firewall['logout']['handlers'] as $handlerId) {
|
||||||
$listener->addMethodCall('addHandler', array(new Reference($handlerId)));
|
$logoutListener->addMethodCall('addHandler', array(new Reference($handlerId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// register with LogoutUrlGenerator
|
// register with LogoutUrlGenerator
|
||||||
@ -362,7 +363,7 @@ class SecurityExtension extends Extension
|
|||||||
// Exception listener
|
// Exception listener
|
||||||
$exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $configuredEntryPoint ?: $defaultEntryPoint, $firewall['stateless']));
|
$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)
|
private function createContextListener($container, $contextKey)
|
||||||
|
@ -150,6 +150,7 @@
|
|||||||
<service id="security.firewall.context" class="%security.firewall.context.class%" abstract="true">
|
<service id="security.firewall.context" class="%security.firewall.context.class%" abstract="true">
|
||||||
<argument type="collection" />
|
<argument type="collection" />
|
||||||
<argument type="service" id="security.exception_listener" />
|
<argument type="service" id="security.exception_listener" />
|
||||||
|
<argument /> <!-- LogoutListener -->
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.logout_url_generator" class="Symfony\Component\Security\Http\Logout\LogoutUrlGenerator" public="false">
|
<service id="security.logout_url_generator" class="Symfony\Component\Security\Http\Logout\LogoutUrlGenerator" public="false">
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Bundle\SecurityBundle\Security;
|
namespace Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
|
||||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
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
|
* This is a wrapper around the actual firewall configuration which allows us
|
||||||
@ -23,15 +24,17 @@ class FirewallContext
|
|||||||
{
|
{
|
||||||
private $listeners;
|
private $listeners;
|
||||||
private $exceptionListener;
|
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->listeners = $listeners;
|
||||||
$this->exceptionListener = $exceptionListener;
|
$this->exceptionListener = $exceptionListener;
|
||||||
|
$this->logoutListener = $logoutListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContext()
|
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(),
|
||||||
array(
|
array(
|
||||||
'security.channel_listener',
|
'security.channel_listener',
|
||||||
'security.logout_listener.secure',
|
|
||||||
'security.authentication.listener.x509.secure',
|
'security.authentication.listener.x509.secure',
|
||||||
'security.authentication.listener.remote_user.secure',
|
'security.authentication.listener.remote_user.secure',
|
||||||
'security.authentication.listener.form.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": {
|
"require": {
|
||||||
"php": ">=5.3.9",
|
"php": ">=5.3.9",
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"symfony/security": "~2.7.38|~2.8.31",
|
"symfony/security": "~2.7.47|~2.8.40",
|
||||||
"symfony/security-acl": "~2.7",
|
"symfony/security-acl": "~2.7",
|
||||||
"symfony/http-kernel": "~2.7"
|
"symfony/http-kernel": "~2.7"
|
||||||
},
|
},
|
||||||
|
@ -47,20 +47,29 @@ class Firewall implements EventSubscriberInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// register listeners for this firewall
|
// 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) {
|
if (null !== $exceptionListener) {
|
||||||
$this->exceptionListeners[$event->getRequest()] = $exceptionListener;
|
$this->exceptionListeners[$event->getRequest()] = $exceptionListener;
|
||||||
$exceptionListener->register($this->dispatcher);
|
$exceptionListener->register($this->dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initiate the listener chain
|
// initiate the listener chain
|
||||||
foreach ($listeners as $listener) {
|
foreach ($authenticationListeners as $listener) {
|
||||||
$listener->handle($event);
|
$listener->handle($event);
|
||||||
|
|
||||||
if ($event->hasResponse()) {
|
if ($event->hasResponse()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $logoutListener) {
|
||||||
|
$logoutListener->handle($event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onKernelFinishRequest(FinishRequestEvent $event)
|
public function onKernelFinishRequest(FinishRequestEvent $event)
|
||||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Http;
|
|||||||
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||||
|
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FirewallMap allows configuration of different firewalls for specific parts
|
* FirewallMap allows configuration of different firewalls for specific parts
|
||||||
@ -25,9 +26,9 @@ class FirewallMap implements FirewallMapInterface
|
|||||||
{
|
{
|
||||||
private $map = array();
|
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) {
|
foreach ($this->map as $elements) {
|
||||||
if (null === $elements[0] || $elements[0]->matches($request)) {
|
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