8000 [Security] Dispatch an event when "logout user on change" steps in · symfony/symfony@5765f69 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5765f69

Browse files
author
Amrouche Hamza
committed
[Security] Dispatch an event when "logout user on change" steps in
1 parent 278a7ec commit 5765f69

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Event;
13+
14+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
15+
use Symfony\Component\Security\Core\User\UserInterface;
16+
use Symfony\Contracts\EventDispatcher\Event;
17+
18+
/**
19+
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
20+
*/
21+
class LogoutOnChangeEvent extends Event
22+
{
23+
private $token;
24+
private $user;
25+
26+
public function __construct(TokenInterface $token, UserInterface $user)
27+
{
28+
$this->token = $token;
29+
$this->user = $user;
30+
}
31+
32+
/**
33+
* @return TokenInterface The token used to refresh the user
34+
*/
35+
public function getToken(): TokenInterface
36+
{
37+
return $this->token;
38+
}
39+
40+
/**
41+
* @return UserInterface The user refreshed by the provider
42+
*/
43+
public function getUser(): UserInterface
44+
{
45+
return $this->user;
46+
}
47+
}

src/Symfony/Component/Security/Http/Firewall/ContextListener.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
use Symfony\Component\Security\Core\Role\SwitchUserRole;
2929
use Symfony\Component\Security\Core\User\UserInterface;
3030
use Symfony\Component\Security\Core\User\UserProviderInterface;
31+
use Symfony\Component\Security\Http\Event\LogoutOnChangeEvent;
32+
use Symfony\Component\Security\Http\SecurityEvents;
3133

3234
/**
3335
* ContextListener manages the SecurityContext persistence through a session.
@@ -186,6 +188,10 @@ protected function refreshUser(TokenInterface $token)
186188
$this->logger->debug('Cannot refresh token because user has changed.', ['username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider)]);
187189
}
188190

191+
if (null !== $this->dispatcher) {
192+
$this->dispatcher->dispatch(new LogoutOnChangeEvent($token, $refreshedUser), SecurityEvents::LOGOUT_ON_CHANGE);
193+
}
194+
189195
continue;
190196
}
191197

src/Symfony/Component/Security/Http/SecurityEvents.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,12 @@ final class SecurityEvents
3131
* @Event("Symfony\Component\Security\Http\Event\SwitchUserEvent")
3232
*/
3333
const SWITCH_USER = 'security.switch_user';
34+
35+
/**
36+
* The LOGOUT_ON_CHANGE event occurs when a token has been deauthenticated
37+
* because of a user change.
38+
*
39+
* @Event("Symfony\Component\Security\Http\Event\LogoutOnChangeEvent")
40+
*/
41+
const LOGOUT_ON_CHANGE = 'security.logout_on_change';
3442
}

src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use Symfony\Component\Security\Core\User\UserInterface;
3333
use Symfony\Component\Security\Core\User\UserProviderInterface;
3434
use Symfony\Component\Security\Http\Firewall\ContextListener;
35+
use Symfony\Component\Security\Http\SecurityEvents;
3536

3637
class ContextListenerTest extends TestCase
3738
{
@@ -313,6 +314,30 @@ public function testAcceptsProvidersAsTraversable()
313314
$this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser());
314315
}
315316

317+
public function testLogoutOnChangeEventAsBeenSent()
318+
{
319+
$tokenStorage = new TokenStorage();
320+
$refreshedUser = new User('foobar', 'baz');
321+
322+
$user = new User('foo', 'bar');
323+
$session = new Session(new MockArraySessionStorage());
324+
$session->set('_security_context_key', serialize(new UsernamePasswordToken($user, '', 'context_key', ['ROLE_USER'])));
325+
326+
$request = new Request();
327+
$request->setSession($session);
328+
$request->cookies->set('MOCKSESSID', true);
329+
330+
$eventDispatcher = new EventDispatcher();
331+
$eventDispatcher->addListener(SecurityEvents::LOGOUT_ON_CHANGE, function ($event) use ($refreshedUser) {
332+
$this->assertEquals($event->getWrappedEvent()->getUser(), $refreshedUser);
333+
});
334+
335+
$listener = new ContextListener($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], 'context_key', null, $eventDispatcher);
336+
$listener(new RequestEvent($this->getMockBuilder(HttpKernelInterface::class)->getMock(), $request, HttpKernelInterface::MASTER_REQUEST));
337+
338+
$this->assertNull($tokenStorage->getToken());
339+
}
340+
316341
protected function runSessionOnKernelResponse($newToken, $original = null)
317342
{
318343
$session = new Session(new MockArraySessionStorage());

0 commit comments

Comments
 (0)
0