Skip to content

Commit 67e21d4

Browse files
committed
[SecurityBundle] Add shortcut option to enable logout CSRF protection
1 parent fa1ec72 commit 67e21d4

File tree

6 files changed

+68
-3
lines changed

6 files changed

+68
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ CHANGELOG
99
* Add `Security::getFirewallConfig()` to help to get the firewall configuration associated to the Request
1010
* Add `Security::login()` to login programmatically
1111
* Add `Security::logout()` to logout programmatically
12+
* Add `security.firewalls.logout.enable_csrf` to enable CSRF protection using the default CSRF token generator
1213

1314
6.1
1415
---

DependencyInjection/MainConfiguration.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,23 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
210210
->arrayNode('logout')
211211
->treatTrueLike([])
212212
->canBeUnset()
213+
->beforeNormalization()
214+
->ifTrue(fn ($v): bool => \is_array($v) && (isset($v['csrf_token_generator']) xor isset($v['enable_csrf'])))
215+
->then(function (array $v): array {
216+
if (isset($v['csrf_token_generator'])) {
217+
$v['enable_csrf'] = true;
218+
} elseif ($v['enable_csrf']) {
219+
$v['csrf_token_generator'] = 'security.csrf.token_generator';
220+
}
221+
222+
return $v;
223+
})
224+
->end()
213225
->children()
214-
->scalarNode('csrf_parameter')->defaultValue('_csrf_token')->end()
215-
->scalarNode('csrf_token_generator')->cannotBeEmpty()->end()
226+
->booleanNode('enable_csrf')->defaultNull()->end()
216227
->scalarNode('csrf_token_id')->defaultValue('logout')->end()
228+
->scalarNode('csrf_parameter')->defaultValue('_csrf_token')->end()
229+
->scalarNode('csrf_token_generator')->end()
217230
->scalarNode('path')->defaultValue('/logout')->end()
218231
->scalarNode('target')->defaultValue('/')->end()
219232
->booleanNode('invalidate_session')->defaultTrue()->end()

DependencyInjection/SecurityExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
426426
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
427427

428428
// add CSRF provider
429-
if (isset($firewall['logout']['csrf_token_generator'])) {
429+
if ($firewall['logout']['enable_csrf']) {
430430
$logoutListener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
431431
}
432432

Resources/config/schema/security-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
<xsd:attribute name="csrf-parameter" type="xsd:string" />
178178
<xsd:attribute name="csrf-token-generator" type="xsd:string" />
179179
<xsd:attribute name="csrf-token-id" type="xsd:string" />
180+
<xsd:attribute name="enable-csrf" type="xsd:boolean" />
180181
<xsd:attribute name="path" type="xsd:string" />
181182
<xsd:attribute name="target" type="xsd:string" />
182183
<xsd:attribute name="invalidate-session" type="xsd:boolean" />

Tests/DependencyInjection/CompleteConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ public function testFirewalls()
173173
'target' => '/',
174174
'invalidate_session' => true,
175175
'delete_cookies' => [],
176+
'enable_csrf' => null,
176177
],
177178
],
178179
[

Tests/DependencyInjection/MainConfigurationTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,55 @@ public function testCsrfAliases()
8888
$this->assertEquals('a_token_id', $processedConfig['firewalls']['stub']['logout']['csrf_token_id']);
8989
}
9090

91+
public function testLogoutCsrf()
92+
{
93+
$config = [
94+
'firewalls' => [
95+
'custom_token_generator' => [
96+
'logout' => [
97+
'csrf_token_generator' => 'a_token_generator',
98+
'csrf_token_id' => 'a_token_id',
99+
],
100+
],
101+
'default_token_generator' => [
102+
'logout' => [
103+
'enable_csrf' => true,
104+
'csrf_token_id' => 'a_token_id',
105+
],
106+
],
107+
'disabled_csrf' => [
108+
'logout' => [
109+
'enable_csrf' => false,
110+
],
111+
],
112+
'empty' => [
113+
'logout' => true,
114+
],
115+
],
116+
];
117+
$config = array_merge(static::$minimalConfig, $config);
118+
119+
$processor = new Processor();
120+
$configuration = new MainConfiguration([], []);
121+
$processedConfig = $processor->processConfiguration($configuration, [$config]);
122+
123+
$assertions = [
124+
'custom_token_generator' => [true, 'a_token_generator'],
125+
'default_token_generator' => [true, 'security.csrf.token_generator'],
126+
'disabled_csrf' => [false, null],
127+
'empty' => [false, null],
128+
];
129+
foreach ($assertions as $firewallName => [$enabled, $tokenGenerator]) {
130+
$this->assertEquals($enabled, $processedConfig['firewalls'][$firewallName]['logout']['enable_csrf']);
131+
if ($tokenGenerator) {
132+
$this->assertEquals($tokenGenerator, $processedConfig['firewalls'][$firewallName]['logout']['csrf_token_generator']);
133+
$this->assertEquals('a_token_id', $processedConfig['firewalls'][$firewallName]['logout']['csrf_token_id']);
134+
} else {
135+
$this->assertArrayNotHasKey('csrf_token_generator', $processedConfig['firewalls'][$firewallName]['logout']);
136+
}
137+
}
138+
}
139+
91140
public function testDefaultUserCheckers()
92141
{
93142
$processor = new Processor();

0 commit comments

Comments
 (0)