8000 Merge branch '6.3' into 6.4 · symfony/symfony@6ee2b44 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6ee2b44

Browse files
Merge branch '6.3' into 6.4
* 6.3: [Security] Validate `aud` and `iss` claims on OidcTokenHandler
2 parents 9f250f3 + 744c378 commit 6ee2b44

File tree

7 files changed

+48
-28
lines changed

7 files changed

+48
-28
lines changed

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ class OidcTokenHandlerFactory implements TokenHandlerFactoryInterface
2828
public function create(ContainerBuilder $container, string $id, array|string $config): void
2929
{
3030
$tokenHandlerDefinition = $container->setDefinition($id, (new ChildDefinition('security.access_token_handler.oidc'))
31+
->replaceArgument(2, $config['audience'])
32+
->replaceArgument(3, $config['issuers'])
3133
->replaceArgument(4, $config['claim'])
32-
->replaceArgument(5, $config['audience'])
3334
);
3435

3536
if (!ContainerBuilder::willBeAvailable('web-token/jwt-core', Algorithm::class, ['symfony/security-bundle'])) {
@@ -39,11 +40,14 @@ public function create(ContainerBuilder $container, string $id, array|string $co
3940
->addError('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "web-token/jwt-core".');
4041
}
4142

43+
// @see Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory
44+
// for supported algorithms
4245
if (\in_array($config['algorithm'], ['ES256', 'ES384', 'ES512'], true)) {
4346
$tokenHandlerDefinition->replaceArgument(0, new Reference('security.access_token_handler.oidc.signature.'.$config['algorithm']));
4447
} else {
45-
$tokenHandlerDefiniti 8000 on->replaceArgument(0, (new ChildDefinition('security.access_token_handler.oidc.signature')))
46-
->replaceArgument(0, $config['algorithm']);
48+
$tokenHandlerDefinition->replaceArgument(0, (new ChildDefinition('security.access_token_handler.oidc.signature'))
49+
->replaceArgument(0, $config['algorithm'])
50+
);
4751
}
4852

4953
$tokenHandlerDefinition->replaceArgument(1, (new ChildDefinition('security.access_token_handler.oidc.jwk'))
@@ -68,7 +72,12 @@ public function addConfiguration(NodeBuilder $node): void
6872
->end()
6973
->scalarNode('audience')
7074
->info('Audience set in the token, for validation purpose.')
71-
->defaultNull()
75+
->isRequired()
76+
->end()
77+
->arrayNode('issuers')
78+
->info('Issuers allowed to generate the token, for validation purpose.')
79+
->isRequired()
80+
->prototype('scalar')->end()
7281
->end()
7382
->scalarNode('algorithm')
7483
->info('Algorithm used to sign the token.')

src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,22 @@
335335
</xsd:complexType>
336336

337337
<xsd:complexType name="oidc">
338+
<xsd:choice maxOccurs="unbounded">
339+
<xsd:element name="issuers" type="oidc_issuers" minOccurs="0" maxOccurs="1" />
340+
<xsd:element name="issuer" type="password_hasher" minOccurs="0" maxOccurs="unbounded" />
341+
</xsd:choice>
338342
<xsd:attribute name="claim" type="xsd:string" />
339-
<xsd:attribute name="audience" type="xsd:string" />
343+
<xsd:attribute name="audience" type="xsd:string" use="required" />
340344
<xsd:attribute name="algorithm" type="xsd:string" use="required" />
341345
<xsd:attribute name="key" type="xsd:string" use="required" />
342346
</xsd:complexType>
343347

348+
<xsd:complexType name="oidc_issuers">
349+
<xsd:sequence>
350+
<xsd:element name="issuer" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
351+
</xsd:sequence>
352+
</xsd:complexType>
353+
344354
<xsd:complexType name="login_throttling">
345355
<xsd:attribute name="limiter" type="xsd:string" />
346356
<xsd:attribute name="max-attempts" type="xsd:integer" />

src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@
6969
->args([
7070
abstract_arg('signature algorithm'),
7171
abstract_arg('signature key'),
72+
abstract_arg('audience'),
73+
abstract_arg('issuers'),
74+
'sub',
7275
service('logger')->nullOnInvalid(),
7376
service('clock'),
74-
'sub',
75-
null,
7677
])
7778

7879
->set('security.access_token_handler.oidc.jwk', JWK::class)

src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ public function testOidcSuccess()
343343
'iat' => $time,
344344
'nbf' => $time,
345345
'exp' => $time + 3600,
346-
'iss' => 'https://www.example.com/',
346+
'iss' => 'https://www.example.com',
347347
'aud' => 'Symfony OIDC',
348348
'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f',
349349
'username' => 'dunglas',

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ security:
2323
oidc:
2424
claim: 'username'
2525
audience: 'Symfony OIDC'
26+
issuers: [ 'https://www.example.com' ]
2627
algorithm: 'ES256'
2728
# tip: use https://mkjwk.org/ to generate a JWK
2829
key: '{"kty":"EC","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo"}'

src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ final class OidcTokenHandler implements AccessTokenHandlerInterface
4141
public function __construct(
4242
private Algorithm $signatureAlgorithm,
4343
private JWK $jwk,
44-
private ?LoggerInterface $logger = null,
45-
private ClockInterface $clock = new Clock(),
44+
private string $audience,
45+
private array $issuers,
4646
private string $claim = 'sub',
47-
private ?string $audience = null
47+
private ?LoggerInterface $logger = null,
48+
private ClockInterface $clock = new Clock()
4849
) {
4950
}
5051

@@ -80,10 +81,9 @@ public function getUserBadgeFrom(string $accessToken): UserBadge
8081
new Checker\IssuedAtChecker(0, false, $this->clock),
8182
new Checker\NotBeforeChecker(0, false, $this->clock),
8283
new Checker\ExpirationTimeChecker(0, false, $this->clock),
84+
new Checker\AudienceChecker($this->audience),
85+
new Checker\IssuerChecker($this->issuers),
8386
];
84-
if ($this->audience) {
85-
$checkers[] = new Checker\AudienceChecker($this->audience);
86-
}
8787
$claimCheckerManager = new ClaimCheckerManager($checkers);
8888
// if this check fails, an InvalidClaimException is thrown
8989
$claimCheckerManager->check($claims);

src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use Jose\Component\Signature\Serializer\CompactSerializer;
1919
use PHPUnit\Framework\TestCase;
2020
use Psr\Log\LoggerInterface;
21-
use Symfony\Component\Clock\Clock;
2221
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
2322
use Symfony\Component\Security\Core\User\OidcUser;
2423
use Symfony\Component\Security\Http\AccessToken\Oidc\OidcTokenHandler;
@@ -41,7 +40,7 @@ public function testGetsUserIdentifierFromSignedToken(string $claim, string $exp
4140
'iat' => $time,
4241
'nbf' => $time,
4342
'exp' => $time + 3600,
44-
'iss' => 'https://www.example.com/',
43+
'iss' => 'https://www.example.com',
4544
'aud' => self::AUDIENCE,
4645
'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f',
4746
'email' => 'foo@example.com',
@@ -55,10 +54,10 @@ public function testGetsUserIdentifierFromSignedToken(string $claim, string $exp
5554
$userBadge = (new OidcTokenHandler(
5655
new ES256(),
5756
$this->getJWK(),
58-
$loggerMock,
59-
new Clock(),
57+
self::AUDIENCE,
58+
['https://www.example.com'],
6059
$claim,
61-
self::AUDIENCE
60+
$loggerMock,
6261
))->getUserBadgeFrom($token);
6362
$actualUser = $userBadge->getUserLoader()();
6463

@@ -89,10 +88,10 @@ public function testThrowsAnErrorIfTokenIsInvalid(string $token)
8988
(new OidcTokenHandler(
9089
new ES256(),
9190
$this->getJWK(),
92-
$loggerMock,
93-
new Clock(),
91+
self::AUDIENCE,
92+
['https://www.example.com'],
9493
'sub',
95-
self::AUDIENCE
94+
$loggerMock,
9695
))->getUserBadgeFrom($token);
9796
}
9897

@@ -106,7 +105,7 @@ public static function getInvalidTokens(): iterable
106105
'iat' => time() - 3600,
107106
'nbf' => time() - 3600,
108107
'exp' => time() - 3590,
109-
'iss' => 'https://www.example.com/',
108+
'iss' => 'https://www.example.com',
110109
'aud' => self::AUDIENCE,
111110
'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f',
112111
'email' => 'foo@example.com',
@@ -118,7 +117,7 @@ public static function getInvalidTokens(): iterable
118117
'iat' => time(),
119118
'nbf' => time(),
120119
'exp' => time() + 3590,
121-
'iss' => 'https://www.example.com/',
120+
'iss' => 'https://www.example.com',
122121
'aud' => 'invalid',
123122
'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f',
124123
'email' => 'foo@example.com',
@@ -139,7 +138,7 @@ public function testThrowsAnErrorIfUserPropertyIsMissing()
139138
'iat' => $time,
140139
'nbf' => $time,
141140
'exp' => $time + 3600,
142-
'iss' => 'https://www.example.com/',
141+
'iss' => 'https://www.example.com',
143142
'aud' => self::AUDIENCE,
144143
'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f',
145144
];
@@ -148,10 +147,10 @@ public function testThrowsAnErrorIfUserPropertyIsMissing()
148147
(new OidcTokenHandler(
149148
new ES256(),
150149
self::getJWK(),
151-
$loggerMock,
152-
new Clock(),
150+
self::AUDIENCE,
151+
['https://www.example.com'],
153152
'email',
154-
self::AUDIENCE
153+
$loggerMock,
155154
))->getUserBadgeFrom($token);
156155
}
157156

0 commit comments

Comments
 (0)
0