Skip to content

Commit 3ea8997

Browse files
author
Igor Timoshenko
committed
[MonologBridge] Added SwitchUserTokenProcessor to log the impersonator user
1 parent e983035 commit 3ea8997

File tree

4 files changed

+154
-19
lines changed

4 files changed

+154
-19
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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\Bridge\Monolog\Processor;
13+
14+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
15+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
16+
17+
/**
18+
* The base class for security token processors.
19+
*
20+
* @author Dany Maillard <danymaillard93b@gmail.com>
21+
* @author Igor Timoshenko <igor.timoshenko@i.ua>
22+
*/
23+
abstract class AbstractTokenProcessor
24+
{
25+
/**
26+
* @var TokenStorageInterface
27+
*/
28+
protected $tokenStorage;
29+
30+
public function __construct(TokenStorageInterface $tokenStorage)
31+
{
32+
$this->tokenStorage = $tokenStorage;
33+
}
34+
35+
abstract protected function getKey(): string;
36+
37+
abstract protected function getToken(): ?TokenInterface;
38+
39+
public function __invoke(array $record): array
40+
{
41+
$record['extra'][$this->getKey()] = null;
42+
43+
if (null !== $token = $this->getToken()) {
44+
$record['extra'][$this->getKey()] = [
45+
'username' => $token->getUsername(),
46+
'authenticated' => $token->isAuthenticated(),
47+
'roles' => $token->getRoleNames(),
48+
];
49+
}
50+
51+
return $record;
52+
}
53+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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\Bridge\Monolog\Processor;
13+
14+
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
15+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
16+
17+
/**
18+
* Adds the original security token to the log entry.
19+
*
20+
* @author Igor Timoshenko <igor.timoshenko@i.ua>
21+
*/
22+
class SwitchUserTokenProcessor extends AbstractTokenProcessor
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
protected function getKey(): string
28+
{
29+
return 'original_token';
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
protected function getToken(): ?TokenInterface
36+
{
37+
$token = $this->tokenStorage->getToken();
38+
39+
if ($token instanceof SwitchUserToken) {
40+
return $token->getOriginalToken();
41+
}
42+
43+
return null;
44+
}
45+
}

src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,29 @@
1111

1212
namespace Symfony\Bridge\Monolog\Processor;
1313

14-
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
14+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1515

1616
/**
1717
* Adds the current security token to the log entry.
1818
*
1919
* @author Dany Maillard <danymaillard93b@gmail.com>
20+
* @author Igor Timoshenko <igor.timoshenko@i.ua>
2021
*/
21-
class TokenProcessor
22+
class TokenProcessor extends AbstractTokenProcessor
2223
{
23-
private $tokenStorage;
24-
25-
public function __construct(TokenStorageInterface $tokenStorage)
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
protected function getKey(): string
2628
{
27-
$this->tokenStorage = $tokenStorage;
29+
return 'token';
2830
}
2931

30-
public function __invoke(array $records)
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
protected function getToken(): ?TokenInterface
3136
{
32-
$records['extra']['token'] = null;
33-
if (null !== $token = $this->tokenStorage->getToken()) {
34-
$roles = $token->getRoleNames();
35-
36-
$records['extra']['token'] = [
37-
'username' => $token->getUsername(),
38-
'authenticated' => $token->isAuthenticated(),
39-
'roles' => $roles,
40-
];
41-
}
42-
43-
return $records;
37+
return $this->tokenStorage->getToken();
4438
}
4539
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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\Bridge\Monolog\Tests\Processor;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor;
16+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
17+
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
18+
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
19+
20+
/**
21+
* Tests the SwitchUserTokenProcessor.
22+
*
23+
* @author Igor Timoshenko <igor.timoshenko@i.ua>
24+
*/
25+
class SwitchUserTokenProcessorTest extends TestCase
26+
{
27+
public function testProcessor()
28+
{
29+
$originalToken = new UsernamePasswordToken('original_user', 'password', 'provider', ['ROLE_SUPER_ADMIN']);
30+
$switchUserToken = new SwitchUserToken('user', 'passsword', 'provider', ['ROLE_USER'], $originalToken);
31+
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
32+
$tokenStorage->method('getToken')->willReturn($switchUserToken);
33+
34+
$processor = new SwitchUserTokenProcessor($tokenStorage);
35+
$record = ['extra' => []];
36+
$record = $processor($record);
37+
38+
$this->assertArrayHasKey('original_token', $record['extra']);
39+
$this->assertEquals($originalToken->getUsername(), $record['extra']['original_token']['username']);
40+
$this->assertEquals($originalToken->isAuthenticated(), $record['extra']['original_token']['authenticated']);
41+
$this->assertEquals(['ROLE_SUPER_ADMIN'], $record['extra']['original_token']['roles']);
42+
}
43+
}

0 commit comments

Comments
 (0)