Skip to content

Commit 0cb4275

Browse files
#93 Protect the logout against CSRF
The prepended logout configuration enables enable_csrf (token id `logout`, parameter `_csrf_token`): the logout link of the EasyAdmin menu (LogoutUrlGenerator) carries the token, /process/logout without a valid token is refused (403). UPGRADE.md v4.0 completed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent c684d01 commit 0cb4275

6 files changed

Lines changed: 46 additions & 3 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Latest
1212
* [#91](https://github.com/cleverage/ui-process-bundle/issues/91) `LoginController`: pass `error` and `last_username` (`AuthenticationUtils`) to the login template, so that a failed login displays the error message and keeps the email. Test updated.
1313

1414
## BC break
15-
* [#93](https://github.com/cleverage/ui-process-bundle/issues/93) Protect the login form against CSRF: `enable_csrf` on the prepended `form_login` configuration, `csrf_token_intention` passed to the login template, `symfony/security-csrf` declared. Add tests.
15+
* [#93](https://github.com/cleverage/ui-process-bundle/issues/93) Protect the login form and the logout against CSRF: `enable_csrf` on the prepended `form_login` and `logout` configurations, `csrf_token_intention` passed to the login template, `symfony/security-csrf` declared. Add tests.
1616
* Please follow [UPGRADE.md v4.0](UPGRADE.md#v40)
1717

1818
v3.0.2

‎UPGRADE.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,28 @@ security:
2626
enable_csrf: false
2727
```
2828
29+
### CSRF protection of the logout
30+
31+
The `logout` configuration prepended by the bundle now enables `enable_csrf` (token id `logout`, parameter
32+
`_csrf_token`): `/process/logout` without a valid token is refused (403). The logout link of the UI menu carries the
33+
token. If you link to the logout from your own templates, use `logout_path()` (or `logout_url()`) instead of
34+
`path('process_logout')`:
35+
36+
```twig
37+
<a href="{{ logout_path() }}">Logout</a>
38+
```
39+
40+
To keep the previous behaviour, disable it on your `main` firewall:
41+
42+
```yaml
43+
# config/packages/security.yaml
44+
security:
45+
firewalls:
46+
main:
47+
logout:
48+
enable_csrf: false
49+
```
50+
2951
## v3.0
3052

3153
### Import routes

‎docs/reference/03-users_and_security.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ security:
2525
path: process_logout
2626
target: process_login
2727
clear_site_data: '*'
28+
enable_csrf: true
2829
```
2930
3031
So your application firewall must be named `main`. The only required application configuration is a password
@@ -43,6 +44,10 @@ The login form is protected by a CSRF token (token id `authenticate`, parameter
4344
protection must be enabled (`framework.csrf_protection`, enabled by default when the session is). If you override the
4445
login template, keep the `_csrf_token` field (the `csrf_token_intention` variable passed by `LoginController`).
4546

47+
The logout is also protected by a CSRF token (token id `logout`, parameter `_csrf_token`): the logout link of the UI
48+
menu carries it. To link to the logout from your own templates, use `logout_path()` (or `logout_url()`), which adds the
49+
token, rather than `path('process_logout')`.
50+
4651
Roles
4752
-----
4853

‎src/DependencyInjection/CleverAgeUiProcessExtension.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ public function prepend(ContainerBuilder $container): void
130130
'path' => 'process_logout',
131131
'target' => 'process_login',
132132
'clear_site_data' => '*',
133+
'enable_csrf' => true,
133134
],
134135
],
135136
],

‎tests/DependencyInjection/CleverAgeUiProcessExtensionTest.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public function testPrepend(): void
180180
'provider' => 'process_user_provider',
181181
'custom_authenticator' => ['cleverage_ui_process.security.http_process_execution_authenticator'],
182182
'form_login' => ['login_path' => 'process_login', 'check_path' => 'process_login', 'enable_csrf' => true],
183-
'logout' => ['path' => 'process_logout', 'target' => 'process_login', 'clear_site_data' => '*'],
183+
'logout' => ['path' => 'process_logout', 'target' => 'process_login', 'clear_site_data' => '*', 'enable_csrf' => true],
184184
],
185185
],
186186
$security[0]['firewalls']

‎tests/Functional/SecurityTest.php‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,25 @@ public function testLogout(): void
154154
{
155155
$this->login();
156156

157-
$this->client->request('GET', '/process/logout');
157+
// Logout link of the user menu, with the CSRF token
158+
$crawler = $this->client->request('GET', '/process/process-execution');
159+
$link = $crawler->filter('a[href^="/process/logout?_csrf_token="]');
160+
self::assertGreaterThan(0, $link->count());
161+
$this->client->click($link->first()->link());
158162
self::assertResponseRedirects('http://localhost/process/login');
159163

160164
$this->client->request('GET', '/process');
161165
self::assertResponseRedirects('http://localhost/process/login');
162166
}
167+
168+
public function testLogoutWithoutCsrfToken(): void
169+
{
170+
$this->login();
171+
172+
$this->client->request('GET', '/process/logout');
173+
self::assertResponseStatusCodeSame(403);
174+
175+
$this->client->request('GET', '/process/process-execution');
176+
self::assertResponseIsSuccessful();
177+
}
163178
}

0 commit comments

Comments
 (0)