77use DateTimeImmutable ;
88use Exception ;
99use Laminas \Diactoros \Response ;
10- use Lcobucci \Clock \SystemClock ;
11- use Lcobucci \JWT \Encoding \JoseEncoder ;
12- use Lcobucci \JWT \Signer \Key \InMemory ;
1310use Lcobucci \JWT \Signer \Rsa \Sha256 ;
14- use Lcobucci \JWT \Token \Parser ;
15- use Lcobucci \JWT \Validation \Constraint \IdentifiedBy ;
16- use Lcobucci \JWT \Validation \Constraint \IssuedBy ;
17- use Lcobucci \JWT \Validation \Constraint \PermittedFor ;
18- use Lcobucci \JWT \Validation \Constraint \RelatedTo ;
19- use Lcobucci \JWT \Validation \Constraint \SignedWith ;
20- use Lcobucci \JWT \Validation \Constraint \StrictValidAt ;
21- use Lcobucci \JWT \Validation \Validator ;
2211use League \OAuth2 \Server \CryptKey ;
2312use PHPUnit \Framework \MockObject \MockObject ;
2413use PHPUnit \Framework \MockObject \Stub ;
3625use SimpleSAML \Module \oidc \Services \JsonWebTokenBuilderService ;
3726use SimpleSAML \Module \oidc \Services \LoggerService ;
3827use SimpleSAML \Module \oidc \Utils \ClaimTranslatorExtractor ;
28+ use SimpleSAML \OpenID \Algorithms \SignatureAlgorithmEnum ;
29+ use SimpleSAML \OpenID \Core ;
30+ use SimpleSAML \OpenID \Core \Factories \IdTokenFactory ;
31+ use SimpleSAML \OpenID \Core \IdToken ;
32+ use SimpleSAML \OpenID \ValueAbstracts \SignatureKeyPair ;
33+ use SimpleSAML \OpenID \ValueAbstracts \SignatureKeyPairBag ;
3934
4035/**
4136 * @covers \SimpleSAML\Module\oidc\Server\ResponseTypes\TokenResponse
@@ -61,6 +56,11 @@ class TokenResponseTest extends TestCase
6156 protected IdTokenBuilder $ idTokenBuilder ;
6257 protected Stub $ claimSetEntityFactoryStub ;
6358 protected MockObject $ loggerMock ;
59+ protected MockObject $ coreMock ;
60+ protected MockObject $ protocolSignatureKeyPairBagMock ;
61+ protected MockObject $ idTokenFactoryMock ;
62+ protected MockObject $ idTokenMock ;
63+ protected MockObject $ signatureKeyPairMock ;
6464
6565 /**
6666 * @throws \PHPUnit\Framework\MockObject\Exception
@@ -117,12 +117,31 @@ protected function setUp(): void
117117
118118 $ this ->claimSetEntityFactoryStub = $ this ->createStub (ClaimSetEntityFactory::class);
119119
120+ $ this ->idTokenFactoryMock = $ this ->createMock (IdTokenFactory::class);
121+
122+ $ this ->coreMock = $ this ->createMock (Core::class);
123+ $ this ->coreMock ->method ('idTokenFactory ' )->willReturn ($ this ->idTokenFactoryMock );
124+
120125 $ this ->idTokenBuilder = new IdTokenBuilder (
121126 new JsonWebTokenBuilderService ($ this ->moduleConfigMock ),
122127 new ClaimTranslatorExtractor (self ::USER_ID_ATTR , $ this ->claimSetEntityFactoryStub ),
128+ $ this ->coreMock ,
129+ $ this ->moduleConfigMock ,
123130 );
124131
125132 $ this ->loggerMock = $ this ->createMock (LoggerService::class);
133+
134+ $ this ->protocolSignatureKeyPairBagMock = $ this ->createMock (SignatureKeyPairBag::class);
135+ $ this ->signatureKeyPairMock = $ this ->createMock (SignatureKeyPair::class);
136+ $ this ->signatureKeyPairMock ->method ('getSignatureAlgorithm ' )
137+ ->willReturn (SignatureAlgorithmEnum::RS256 );
138+ $ this ->protocolSignatureKeyPairBagMock ->method ('getFirstOrFail ' )
139+ ->willReturn ($ this ->signatureKeyPairMock );
140+
141+ $ this ->moduleConfigMock ->method ('getProtocolSignatureKeyPairBag ' )
142+ ->willReturn ($ this ->protocolSignatureKeyPairBagMock );
143+
144+ $ this ->idTokenMock = $ this ->createMock (IdToken::class);
126145 }
127146
128147 protected function prepareMockedInstance (): TokenResponse
@@ -157,6 +176,11 @@ public function testItCanGenerateResponse(): void
157176 {
158177 $ this ->accessTokenEntityMock ->method ('getRequestedClaims ' )->willReturn ([]);
159178 $ this ->accessTokenEntityMock ->method ('getScopes ' )->willReturn ($ this ->scopes );
179+ $ this ->idTokenFactoryMock ->method ('fromData ' )
180+ ->willReturn ($ this ->idTokenMock );
181+ $ this ->idTokenMock ->expects ($ this ->once ())
182+ ->method ('getToken ' )
183+ ->willReturn ('token ' );
160184 $ idTokenResponse = $ this ->prepareMockedInstance ();
161185 $ idTokenResponse ->setAccessToken ($ this ->accessTokenEntityMock );
162186 $ response = $ idTokenResponse ->generateHttpResponse (new Response ());
@@ -191,6 +215,11 @@ public function testItCanGenerateResponseWithIndividualRequestedClaims(): void
191215 $ this ->accessTokenEntityMock ->method ('getScopes ' )->willReturn (
192216 [new ScopeEntity ('openid ' )],
193217 );
218+ $ this ->idTokenFactoryMock ->method ('fromData ' )
219+ ->willReturn ($ this ->idTokenMock );
220+ $ this ->idTokenMock ->expects ($ this ->once ())
221+ ->method ('getToken ' )
222+ ->willReturn ('token ' );
194223 $ idTokenResponse ->setAccessToken ($ this ->accessTokenEntityMock );
195224 $ response = $ idTokenResponse ->generateHttpResponse (new Response ());
196225
@@ -234,61 +263,6 @@ protected function shouldHaveValidIdToken(string $body, $expectedClaims = []): b
234263 );
235264 }
236265
237- // Check ID token
238- $ validator = new Validator ();
239- /** @var Plain $token */
240- $ token = (new Parser (new JoseEncoder ()))->parse ($ result ['id_token ' ]);
241-
242- $ validator ->assert (
243- $ token ,
244- new IdentifiedBy (self ::TOKEN_ID ),
245- new IssuedBy (self ::ISSUER ),
246- new PermittedFor (self ::CLIENT_ID ),
247- new RelatedTo (self ::SUBJECT ),
248- new StrictValidAt (SystemClock::fromUTC ()),
249- new SignedWith (
250- new Sha256 (),
251- InMemory::plainText (file_get_contents ($ this ->certFolder . '/oidc_module.crt ' )),
252- ),
253- );
254-
255- if ($ token ->headers ()->get ('kid ' ) !== self ::KEY_ID ) {
256- throw new Exception (
257- 'Wrong key id. Expected ' . self ::KEY_ID . ' was ' . $ token ->headers ()->get ('kid ' ),
258- );
259- }
260- $ expectedClaimsKeys = array_keys ($ expectedClaims );
261- $ expectedClaimsKeys = ['iss ' , 'iat ' , 'jti ' , 'aud ' , 'nbf ' , 'exp ' , 'sub ' , 'at_hash ' , ...$ expectedClaimsKeys ];
262- $ claims = array_keys ($ token ->claims ()->all ());
263- if ($ claims !== $ expectedClaimsKeys ) {
264- throw new Exception (
265- 'missing expected claim. Got ' . var_export ($ claims , true )
266- . ' need ' . var_export ($ expectedClaimsKeys , true ),
267- );
268- }
269- foreach ($ expectedClaims as $ claim => $ value ) {
270- $ valFromToken = $ token ->claims ()->get ($ claim );
271- if ($ value !== $ valFromToken ) {
272- throw new Exception (
273- 'Expected claim value ' . var_export ($ value , true )
274- . ' got ' . var_export ($ valFromToken , true ),
275- );
276- }
277- }
278-
279- $ dateWithNoMicroseconds = ['nbf ' , 'exp ' , 'iat ' ];
280- foreach ($ dateWithNoMicroseconds as $ key ) {
281- /**
282- * @var DateTimeImmutable $val
283- */
284- $ val = $ token ->claims ()->get ($ key );
285- //Get format representing microseconds
286- $ val = $ val ->format ('u ' );
287- if ($ val !== '000000 ' ) {
288- throw new Exception ("Value for ' $ key' has microseconds. micros ' $ val' " );
289- }
290- }
291-
292266 return true ;
293267 }
294268}
0 commit comments