Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9055e78

Browse files
committed
[Security] Add logout configuration for Clear-Site-Data header
1 parent ea7cc20 commit 9055e78

File tree

7 files changed

+155
-2
lines changed

7 files changed

+155
-2
lines changed

src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
251251
->scalarNode('path')->defaultValue('/logout')->end()
252252
->scalarNode('target')->defaultValue('/')->end()
253253
->booleanNode('invalidate_session')->defaultTrue()->end()
254+
->scalarNode('clear_site_data')->defaultValue('off')->end()
254255
->end()
255256
->fixXmlConfig('delete_cookie')
256257
->children()

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
451451
'logout_path' => $firewall['logout']['path'],
452452
]);
453453

454-
$logoutSuccessListenerId = 'security.logout.listener.default.'.$id;
455-
$container->setDefinition($logoutSuccessListenerId, new ChildDefinition('security.logout.listener.default'))
454+
$container->setDefinition('security.logout.listener.default.'.$id, new ChildDefinition('security.logout.listener.default'))
456455
->replaceArgument(1, $firewall['logout']['target'])
457456
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
458457

@@ -474,6 +473,13 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
474473
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
475474
}
476475

476+
// add clear site data listener
477+
if ('off' !== $firewall['logout']['clear_site_data']) {
478+
$container->setDefinition('security.logout.listener.clear_site_data.'.$id, new ChildDefinition('security.logout.listener.clear_site_data'))
479+
->addArgument($firewall['logout']['clear_site_data'])
480+
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
481+
}
482+
477483
// register with LogoutUrlGenerator
478484
$container
479485
->getDefinition('security.logout_url_generator')

src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Security\Http\Authentication\CustomAuthenticationSuccessHandler;
1818
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
1919
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler;
20+
use Symfony\Component\Security\Http\EventListener\ClearSiteDataLogoutListener;
2021
use Symfony\Component\Security\Http\EventListener\CookieClearingLogoutListener;
2122
use Symfony\Component\Security\Http\EventListener\DefaultLogoutListener;
2223
use Symfony\Component\Security\Http\EventListener\SessionLogoutListener;
@@ -64,6 +65,9 @@
6465
->set('security.logout.listener.session', SessionLogoutListener::class)
6566
->abstract()
6667

68+
->set('security.logout.listener.clear_site_data', ClearSiteDataLogoutListener::class)
69+
->abstract()
70+
6771
->set('security.logout.listener.cookie_clearing', CookieClearingLogoutListener::class)
6872
->abstract()
6973

src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ public function testFirewalls()
181181
'invalidate_session' => true,
182182
'delete_cookies' => [],
183183
'enable_csrf' => null,
184+
'clear_site_data' => 'off',
184185
],
185186
],
186187
[

src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,48 @@ public function testConfigureCustomFirewallListener()
848848
$this->assertContains('custom_firewall_listener_id', $firewallListeners);
849849
}
850850

851+
public function testClearSiteDataLogoutListenerEnabled()
852+
{
853+
$container = $this->getRawContainer();
854+
855+
$firewallId = 'logout_firewall';
856+
$container->loadFromExtension('security', [
857+
'firewalls' => [
858+
$firewallId => [
859+
'logout' => [
860+
'clear_site_data' => '"*"',
861+
],
862+
],
863+
],
864+
]);
865+
866+
$container->compile();
867+
868+
$this->assertTrue($container->has('security.logout.listener.clear_site_data.'.$firewallId));
869+
$listenerArgument = $container->getDefinition('security.logout.listener.clear_site_data.'.$firewallId)->getArgument(0);
870+
$this->assertEquals('"*"', $listenerArgument);
871+
}
872+
873+
public function testClearSiteDataLogoutListenerDisabled()
874+
{
875+
$container = $this->getRawContainer();
876+
877+
$firewallId = 'logout_firewall';
878+
$container->loadFromExtension('security', [
879+
'firewalls' => [
880+
$firewallId => [
881+
'logout' => [
882+
'clear_site_data' => 'off',
883+
],
884+
],
885+
],
886+
]);
887+
888+
$container->compile();
889+
890+
$this->assertFalse($container->has('security.logout.listener.clear_site_data.'.$firewallId));
891+
}
892+
851893
/**
852894
* @group legacy
853895
*/
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Http\EventListener;
13+
14+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15+
use Symfony\Component\Security\Http\Event\LogoutEvent;
16+
17+
/**
18+
* Handler for Clear-Site-Data header during logout.
19+
*
20+
* @author Max Beckers <[email protected]>
21+
*
22+
* @final
23+
*/
24+
class ClearSiteDataLogoutListener implements EventSubscriberInterface
25+
{
26+
private const HEADER_NAME = 'Clear-Site-Data';
27+
28+
private string $cookieValue;
29+
30+
/**
31+
* @param string $cookieValue The value for the Clear-Site-Data header. Can be '*' or a subset of 'cache', 'cookies', 'storage', 'executionContexts'.
32+
*/
33+
public function __construct(string $cookieValue)
34+
{
35+
$this->cookieValue = $cookieValue;
36+
}
37+
38+
public function onLogout(LogoutEvent $event): void
39+
{
40+
if (!$event->getResponse()?->headers->has(static::HEADER_NAME)) {
41+
$event->getResponse()->headers->set(static::HEADER_NAME, $this->cookieValue);
42+
}
43+
}
44+
45+
public static function getSubscribedEvents(): array
46+
{
47+
return [
48+
LogoutEvent::class => 'onLogout',
49+
];
50+
}
51+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Http\Tests\EventListener;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\Security\Http\Event\LogoutEvent;
18+
use Symfony\Component\Security\Http\EventListener\ClearSiteDataLogoutListener;
19+
20+
class ClearSiteDataLogoutListenerTest extends TestCase
21+
{
22+
/**
23+
* @dataProvider provideClearSiteDataConfig
24+
*/
25+
public function testLogout(string $clearSiteDataConfig)
26+
{
27+
$response = new Response();
28+
$event = new LogoutEvent(new Request(), null);
29+
$event->setResponse($response);
30+
31+
$listener = new ClearSiteDataLogoutListener($clearSiteDataConfig);
32+
33+
$headerCountBefore = $response->headers->count();
34+
35+
$listener->onLogout($event);
36+
37+
$this->assertEquals(++$headerCountBefore, $response->headers->count());
38+
39+
$this->assertNotNull($response->headers->get('Clear-Site-Data'));
40+
$this->assertEquals($clearSiteDataConfig, $response->headers->get('Clear-Site-Data'));
41+
}
42+
43+
public function provideClearSiteDataConfig()
44+
{
45+
yield ['"*"'];
46+
yield ['"cache", "cookies", "storage", "executionContexts"'];
47+
}
48+
}

0 commit comments

Comments
 (0)