Skip to content

Commit 5bfd903

Browse files
Jeroenynicolas-grekas
authored andcommitted
[Security] Support loading UserBadge directly from accessToken
1 parent 58755b2 commit 5bfd903

7 files changed

+51
-44
lines changed

AccessToken/AccessTokenHandlerInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Http\AccessToken;
1313

1414
use Symfony\Component\Security\Core\Exception\AuthenticationException;
15+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
1516

1617
/**
1718
* The token handler retrieves the user identifier from the token.
@@ -24,5 +25,5 @@ interface AccessTokenHandlerInterface
2425
/**
2526
* @throws AuthenticationException
2627
*/
27-
public function getUserIdentifierFrom(#[\SensitiveParameter] string $accessToken): string;
28+
public function getUserBadgeFrom(#[\SensitiveParameter] string $accessToken): UserBadge;
2829
}

Authenticator/AccessTokenAuthenticator.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
2222
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
2323
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
24-
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
2524
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
2625
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
2726
use Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken;
@@ -38,9 +37,9 @@ class AccessTokenAuthenticator implements AuthenticatorInterface
3837
private ?TranslatorInterface $translator = null;
3938

4039
public function __construct(
41-
private readonly UserProviderInterface $userProvider,
4240
private readonly AccessTokenHandlerInterface $accessTokenHandler,
4341
private readonly AccessTokenExtractorInterface $accessTokenExtractor,
42+
private readonly ?UserProviderInterface $userProvider = null,
4443
private readonly ?AuthenticationSuccessHandlerInterface $successHandler = null,
4544
private readonly ?AuthenticationFailureHandlerInterface $failureHandler = null,
4645
private readonly ?string $realm = null,
@@ -58,11 +57,13 @@ public function authenticate(Request $request): Passport
5857
if (!$accessToken) {
5958
throw new BadCredentialsException('Invalid credentials.');
6059
}
61-
$userIdentifier = $this->accessTokenHandler->getUserIdentifierFrom($accessToken);
6260

63-
return new SelfValidatingPassport(
64-
new UserBadge($userIdentifier, $this->userProvider->loadUserByIdentifier(...))
65-
);
61+
$userBadge = $this->accessTokenHandler->getUserBadgeFrom($accessToken);
62+
if (null === $userBadge->getUserLoader() && $this->userProvider) {
63+
$userBadge->setUserLoader($this->userProvider->loadUserByIdentifier(...));
64+
}
65+
66+
return new SelfValidatingPassport($userBadge);
6667
}
6768

6869
public function createToken(Passport $passport, string $firewallName): TokenInterface

Tests/Authenticator/AccessToken/ChainedAccessTokenExtractorsTest.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\Security\Http\AccessToken\HeaderAccessTokenExtractor;
2323
use Symfony\Component\Security\Http\AccessToken\QueryAccessTokenExtractor;
2424
use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator;
25+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
2526
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
2627
use Symfony\Component\Security\Http\Tests\Authenticator\InMemoryAccessTokenHandler;
2728

@@ -40,7 +41,7 @@ protected function setUp(): void
4041
/**
4142
* @dataProvider provideSupportData
4243
*/
43-
public function testSupport($request): void
44+
public function testSupport($request)
4445
{
4546
$this->setUpAuthenticator();
4647

@@ -53,9 +54,9 @@ public function provideSupportData(): iterable
5354
yield [new Request([], [], [], [], [], ['HTTP_AUTHORIZATION' => 'Bearer INVALID_ACCESS_TOKEN'])];
5455
}
5556

56-
public function testAuthenticate(): void
57+
public function testAuthenticate()
5758
{
58-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
59+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
5960
$this->setUpAuthenticator();
6061

6162
$request = new Request([], [], [], [], [], ['HTTP_AUTHORIZATION' => 'Bearer VALID_ACCESS_TOKEN']);
@@ -66,7 +67,7 @@ public function testAuthenticate(): void
6667
/**
6768
* @dataProvider provideInvalidAuthenticateData
6869
*/
69-
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class): void
70+
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class)
7071
{
7172
$this->expectException($exceptionType);
7273
$this->expectExceptionMessage($errorMessage);
@@ -100,13 +101,13 @@ public function provideInvalidAuthenticateData(): iterable
100101
private function setUpAuthenticator(): void
101102
{
102103
$this->authenticator = new AccessTokenAuthenticator(
103-
$this->userProvider,
104104
$this->accessTokenHandler,
105105
new ChainAccessTokenExtractor([
106106
new FormEncodedBodyExtractor(),
107107
new QueryAccessTokenExtractor(),
108108
new HeaderAccessTokenExtractor(),
109-
])
109+
]),
110+
$this->userProvider
110111
);
111112
}
112113
}

Tests/Authenticator/AccessToken/FormEncodedBodyAccessTokenAuthenticatorTest.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
2020
use Symfony\Component\Security\Http\AccessToken\FormEncodedBodyExtractor;
2121
use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator;
22+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
2223
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
2324
use Symfony\Component\Security\Http\Tests\Authenticator\InMemoryAccessTokenHandler;
2425

@@ -34,7 +35,7 @@ protected function setUp(): void
3435
$this->accessTokenHandler = new InMemoryAccessTokenHandler();
3536
}
3637

37-
public function testSupport(): void
38+
public function testSupport()
3839
{
3940
$this->setUpAuthenticator();
4041
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
@@ -44,7 +45,7 @@ public function testSupport(): void
4445
$this->assertNull($this->authenticator->supports($request));
4546
}
4647

47-
public function testSupportsWithCustomParameter(): void
48+
public function testSupportsWithCustomParameter()
4849
{
4950
$this->setUpAuthenticator('protection-token');
5051
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
@@ -54,9 +55,9 @@ public function testSupportsWithCustomParameter(): void
5455
$this->assertNull($this->authenticator->supports($request));
5556
}
5657

57-
public function testAuthenticate(): void
58+
public function testAuthenticate()
5859
{
59-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
60+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
6061
$this->setUpAuthenticator();
6162
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded'], 'access_token=VALID_ACCESS_TOKEN');
6263
$request->request->set('access_token', 'VALID_ACCESS_TOKEN');
@@ -66,9 +67,9 @@ public function testAuthenticate(): void
6667
$this->assertInstanceOf(SelfValidatingPassport::class, $passport);
6768
}
6869

69-
public function testAuthenticateWithCustomParameter(): void
70+
public function testAuthenticateWithCustomParameter()
7071
{
71-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
72+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
7273
$this->setUpAuthenticator('protection-token');
7374
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
7475
$request->request->set('protection-token', 'VALID_ACCESS_TOKEN');
@@ -81,7 +82,7 @@ public function testAuthenticateWithCustomParameter(): void
8182
/**
8283
* @dataProvider provideInvalidAuthenticateData
8384
*/
84-
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class): void
85+
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class)
8586
{
8687
$this->expectException($exceptionType);
8788
$this->expectExceptionMessage($errorMessage);
@@ -119,9 +120,9 @@ public function provideInvalidAuthenticateData(): iterable
119120
private function setUpAuthenticator(string $parameter = 'access_token'): void
120121
{
121122
$this->authenticator = new AccessTokenAuthenticator(
122-
$this->userProvider,
123123
$this->accessTokenHandler,
124-
new FormEncodedBodyExtractor($parameter)
124+
new FormEncodedBodyExtractor($parameter),
125+
$this->userProvider
125126
);
126127
}
127128
}

Tests/Authenticator/AccessToken/HeaderAccessTokenAuthenticatorTest.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
2020
use Symfony\Component\Security\Http\AccessToken\HeaderAccessTokenExtractor;
2121
use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator;
22+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
2223
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
2324
use Symfony\Component\Security\Http\Tests\Authenticator\InMemoryAccessTokenHandler;
2425

@@ -37,7 +38,7 @@ protected function setUp(): void
3738
/**
3839
* @dataProvider provideSupportData
3940
*/
40-
public function testSupport($request): void
41+
public function testSupport($request)
4142
{
4243
$this->setUpAuthenticator();
4344

@@ -53,7 +54,7 @@ public function provideSupportData(): iterable
5354
/**
5455
* @dataProvider provideSupportsWithCustomTokenTypeData
5556
*/
56-
public function testSupportsWithCustomTokenType($request, $result): void
57+
public function testSupportsWithCustomTokenType($request, $result)
5758
{
5859
$this->setUpAuthenticator('Authorization', 'JWT');
5960

@@ -71,7 +72,7 @@ public function provideSupportsWithCustomTokenTypeData(): iterable
7172
/**
7273
* @dataProvider provideSupportsWithCustomHeaderParameter
7374
*/
74-
public function testSupportsWithCustomHeaderParameter($request, $result): void
75+
public function testSupportsWithCustomHeaderParameter($request, $result)
7576
{
7677
$this->setUpAuthenticator('X-FOO');
7778

@@ -86,19 +87,19 @@ public function provideSupportsWithCustomHeaderParameter(): iterable
8687
yield [new Request([], [], [], [], [], ['HTTP_AUTHORIZATION' => 'Bearer INVALID_ACCESS_TOKEN']), false];
8788
}
8889

89-
public function testAuthenticate(): void
90+
public function testAuthenticate()
9091
{
91-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
92+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
9293
$this->setUpAuthenticator();
9394

9495
$request = new Request([], [], [], [], [], ['HTTP_AUTHORIZATION' => 'Bearer VALID_ACCESS_TOKEN']);
9596
$passport = $this->authenticator->authenticate($request);
9697
$this->assertInstanceOf(SelfValidatingPassport::class, $passport);
9798
}
9899

99-
public function testAuthenticateWithCustomTokenType(): void
100+
public function testAuthenticateWithCustomTokenType()
100101
{
101-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
102+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
102103
$this->setUpAuthenticator('Authorization', 'JWT');
103104

104105
$request = new Request([], [], [], [], [], ['HTTP_AUTHORIZATION' => 'JWT VALID_ACCESS_TOKEN']);
@@ -109,7 +110,7 @@ public function testAuthenticateWithCustomTokenType(): void
109110
/**
110111
* @dataProvider provideInvalidAuthenticateData
111112
*/
112-
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class): void
113+
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class)
113114
{
114115
$this->expectException($exceptionType);
115116
$this->expectExceptionMessage($errorMessage);
@@ -143,9 +144,9 @@ public function provideInvalidAuthenticateData(): iterable
143144
private function setUpAuthenticator(string $headerParameter = 'Authorization', string $tokenType = 'Bearer'): void
144145
{
145146
$this->authenticator = new AccessTokenAuthenticator(
146-
$this->userProvider,
147147
$this->accessTokenHandler,
148-
new HeaderAccessTokenExtractor($headerParameter, $tokenType)
148+
new HeaderAccessTokenExtractor($headerParameter, $tokenType),
149+
$this->userProvider
149150
);
150151
}
151152
}

Tests/Authenticator/AccessToken/QueryAccessTokenAuthenticatorTest.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
2020
use Symfony\Component\Security\Http\AccessToken\QueryAccessTokenExtractor;
2121
use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator;
22+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
2223
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
2324
use Symfony\Component\Security\Http\Tests\Authenticator\InMemoryAccessTokenHandler;
2425

@@ -34,7 +35,7 @@ protected function setUp(): void
3435
$this->accessTokenHandler = new InMemoryAccessTokenHandler();
3536
}
3637

37-
public function testSupport(): void
38+
public function testSupport()
3839
{
3940
$this->setUpAuthenticator();
4041
$request = new Request();
@@ -43,7 +44,7 @@ public function testSupport(): void
4344
$this->assertNull($this->authenticator->supports($request));
4445
}
4546

46-
public function testSupportsWithCustomParameter(): void
47+
public function testSupportsWithCustomParameter()
4748
{
4849
$this->setUpAuthenticator('protection-token');
4950
$request = new Request();
@@ -52,9 +53,9 @@ public function testSupportsWithCustomParameter(): void
5253
$this->assertNull($this->authenticator->supports($request));
5354
}
5455

55-
public function testAuthenticate(): void
56+
public function testAuthenticate()
5657
{
57-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
58+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
5859
$this->setUpAuthenticator();
5960
$request = new Request();
6061
$request->query->set('access_token', 'VALID_ACCESS_TOKEN');
@@ -63,9 +64,9 @@ public function testAuthenticate(): void
6364
$this->assertInstanceOf(SelfValidatingPassport::class, $passport);
6465
}
6566

66-
public function testAuthenticateWithCustomParameter(): void
67+
public function testAuthenticateWithCustomParameter()
6768
{
68-
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', 'foo');
69+
$this->accessTokenHandler->add('VALID_ACCESS_TOKEN', new UserBadge('foo'));
6970
$this->setUpAuthenticator('protection-token');
7071
$request = new Request();
7172
$request->query->set('protection-token', 'VALID_ACCESS_TOKEN');
@@ -77,7 +78,7 @@ public function testAuthenticateWithCustomParameter(): void
7778
/**
7879
* @dataProvider provideInvalidAuthenticateData
7980
*/
80-
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class): void
81+
public function testAuthenticateInvalid($request, $errorMessage, $exceptionType = BadRequestHttpException::class)
8182
{
8283
$this->expectException($exceptionType);
8384
$this->expectExceptionMessage($errorMessage);
@@ -111,9 +112,9 @@ public function provideInvalidAuthenticateData(): iterable
111112
private function setUpAuthenticator(string $parameter = 'access_token'): void
112113
{
113114
$this->authenticator = new AccessTokenAuthenticator(
114-
$this->userProvider,
115115
$this->accessTokenHandler,
116-
new QueryAccessTokenExtractor($parameter)
116+
new QueryAccessTokenExtractor($parameter),
117+
$this->userProvider
117118
);
118119
}
119120
}

Tests/Authenticator/InMemoryAccessTokenHandler.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@
1313

1414
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
1515
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
16+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
1617

1718
class InMemoryAccessTokenHandler implements AccessTokenHandlerInterface
1819
{
1920
/**
20-
* @var array<string, string>
21+
* @var array<string, UserBadge>
2122
*/
2223
private $accessTokens = [];
2324

24-
public function getUserIdentifierFrom(string $accessToken): string
25+
public function getUserBadgeFrom(string $accessToken): UserBadge
2526
{
2627
if (!\array_key_exists($accessToken, $this->accessTokens)) {
2728
throw new BadCredentialsException('Invalid access token or invalid user.');
@@ -37,7 +38,7 @@ public function remove(string $accessToken): self
3738
return $this;
3839
}
3940

40-
public function add(string $accessToken, string $user): self
41+
public function add(string $accessToken, UserBadge $user): self
4142
{
4243
$this->accessTokens[$accessToken] = $user;
4344

0 commit comments

Comments
 (0)