Skip to content

Commit 1b91ae2

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: [Bridge][Monolog] Add intruction about 'ResetLoggersWorkerSubscriber deprecation' in main UPGRADE-5.4.md [Security] Move TraceableAuthenticator to security-http [Form] Check the type of the constraints option Fixed default behavior
2 parents 4dc39ad + 303edcd commit 1b91ae2

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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\Authenticator\Debug;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
17+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
18+
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
19+
use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface;
20+
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
21+
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
22+
use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException;
23+
use Symfony\Component\VarDumper\Caster\ClassStub;
24+
25+
/**
26+
* Collects info about an authenticator for debugging purposes.
27+
*
28+
* @author Robin Chalas <robin.chalas@gmail.com>
29+
*/
30+
final class TraceableAuthenticator implements AuthenticatorInterface, InteractiveAuthenticatorInterface, AuthenticationEntryPointInterface
31+
{
32+
private $authenticator;
33+
private $passport;
34+
private $duration;
35+
private $stub;
36+
37+
public function __construct(AuthenticatorInterface $authenticator)
38+
{
39+
$this->authenticator = $authenticator;
40+
}
41+
42+
public function getInfo(): array
43+
{
44+
return [
45+
'supports' => true,
46+
'passport' => $this->passport,
47+
'duration' => $this->duration,
48+
'stub' => $this->stub ?? $this->stub = class_exists(ClassStub::class) ? new ClassStub(\get_class($this->authenticator)) : \get_class($this->authenticator),
49+
];
50+
}
51+
52+
public function supports(Request $request): ?bool
53+
{
54+
return $this->authenticator->supports($request);
55+
}
56+
57+
public function authenticate(Request $request): Passport
58+
{
59+
$startTime = microtime(true);
60+
$this->passport = $this->authenticator->authenticate($request);
61+
$this->duration = microtime(true) - $startTime;
62+
63+
return $this->passport;
64+
}
65+
66+
public function createToken(Passport $passport, string $firewallName): TokenInterface
67+
{
68+
return method_exists($this->authenticator, 'createToken') ? $this->authenticator->createToken($passport, $firewallName) : $this->authenticator->createAuthenticatedToken($passport, $firewallName);
69+
}
70+
71+
public function createAuthenticatedToken(Passport $passport, string $firewallName): TokenInterface
72+
{
73+
return $this->authenticator->createAuthenticatedToken($passport, $firewallName);
74+
}
75+
76+
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
77+
{
78+
return $this->authenticator->onAuthenticationSuccess($request, $token, $firewallName);
79+
}
80+
81+
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
82+
{
83+
return $this->authenticator->onAuthenticationFailure($request, $exception);
84+
}
85+
86+
public function start(Request $request, AuthenticationException $authException = null): Response
87+
{
88+
if (!$this->authenticator instanceof AuthenticationEntryPointInterface) {
89+
throw new NotAnEntryPointException();
90+
}
91+
92+
return $this->authenticator->start($request, $authException);
93+
}
94+
95+
public function isInteractive(): bool
96+
{
97+
return $this->authenticator instanceof InteractiveAuthenticatorInterface && $this->authenticator->isInteractive();
98+
}
99+
100+
public function __call($method, $args)
101+
{
102+
return $this->authenticator->{$method}(...$args);
103+
}
104+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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\Authenticator\Debug;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpKernel\Event\RequestEvent;
16+
use Symfony\Component\Security\Http\Firewall\AbstractListener;
17+
use Symfony\Component\Security\Http\Firewall\AuthenticatorManagerListener;
18+
use Symfony\Component\VarDumper\Caster\ClassStub;
19+
20+
/**
21+
* Decorates the AuthenticatorManagerListener to collect information about security authenticators.
22+
*
23+
* @author Robin Chalas <robin.chalas@gmail.com>
24+
*/
25+
final class TraceableAuthenticatorManagerListener extends AbstractListener
26+
{
27+
private $authenticationManagerListener;
28+
private $authenticatorsInfo = [];
29+
private $hasVardumper;
30+
31+
public function __construct(AuthenticatorManagerListener $authenticationManagerListener)
32+
{
33+
$this->authenticationManagerListener = $authenticationManagerListener;
34+
$this->hasVardumper = class_exists(ClassStub::class);
35+
}
36+
37+
public function supports(Request $request): ?bool
38+
{
39+
return $this->authenticationManagerListener->supports($request);
40+
}
41+
42+
public function authenticate(RequestEvent $event): void
43+
{
44+
$request = $event->getRequest();
45+
46+
if (!$authenticators = $request->attributes->get('_security_authenticators')) {
47+
return;
48+
}
49+
50+
foreach ($request->attributes->get('_security_skipped_authenticators') as $skippedAuthenticator) {
51+
$this->authenticatorsInfo[] = [
52+
'supports' => false,
53+
'stub' => $this->hasVardumper ? new ClassStub(\get_class($skippedAuthenticator)) : \get_class($skippedAuthenticator),
54+
'passport' => null,
55+
'duration' => 0,
56+
];
57+
}
58+
59+
foreach ($authenticators as $key => $authenticator) {
60+
$authenticators[$key] = new TraceableAuthenticator($authenticator);
61+
}
62+
63+
$request->attributes->set('_security_authenticators', $authenticators);
64+
65+
$this->authenticationManagerListener->authenticate($event);
66+
67+
foreach ($authenticators as $authenticator) {
68+
$this->authenticatorsInfo[] = $authenticator->getInfo();
69+
}
70+
}
71+
72+
public function getAuthenticatorManagerListener(): AuthenticatorManagerListener
73+
{
74+
return $this->authenticationManagerListener;
75+
}
76+
77+
public function getAuthenticatorsInfo(): array
78+
{
79+
return $this->authenticatorsInfo;
80+
}
81+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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\Tests\Authenticator\Debug;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
17+
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator;
18+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
19+
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
20+
21+
class TraceableAuthenticatorTest extends TestCase
22+
{
23+
public function testGetInfo()
24+
{
25+
$request = new Request();
26+
$passport = new SelfValidatingPassport(new UserBadge('robin', function () {}));
27+
28+
$authenticator = $this->createMock(AuthenticatorInterface::class);
29+
$authenticator
30+
->expects($this->once())
31+
->method('authenticate')
32+
->with($request)
33+
->willReturn($passport);
34+
35+
$traceable = new TraceableAuthenticator($authenticator);
36+
$this->assertSame($passport, $traceable->authenticate($request));
37+
$this->assertSame($passport, $traceable->getInfo()['passport']);
38+
}
39+
}

0 commit comments

Comments
 (0)