@@ -254,10 +254,16 @@ public function testValidateIdTokenFailure(): void
254254 $ mockJWT = \Mockery::mock ('overload:Firebase\JWT\JWT ' , MockJWT::class);
255255 $ mockJWT ->shouldReceive ('decode ' )->andThrow (SignatureInvalidException::class, 'Signature verification failed ' );
256256
257- $ this ->expectException (ValidationException::class);
258- $ this ->expectExceptionMessage ('ID token validation failed ' );
259-
260- $ this ->provider ->validateIdToken ('token ' , self ::NONCE );
257+ try {
258+ $ this ->provider ->validateIdToken ('token ' , self ::NONCE );
259+ } catch (ValidationException $ thrown ) {
260+ $ this ->assertSame ('ID token validation failed: Signature verification failed ' , $ thrown ->getMessage ());
261+ $ this ->assertSame (0 , $ thrown ->getCode ());
262+ $ this ->assertInstanceOf (SignatureInvalidException::class, $ thrown ->getPrevious (), 'Original cause must be chained ' );
263+
264+ return ;
265+ }
266+ $ this ->fail ('Expected ValidationException ' );
261267 }
262268
263269 public function testValidateIdTokenAudience (): void
@@ -270,7 +276,7 @@ public function testValidateIdTokenAudience(): void
270276 $ mockJWT ->shouldReceive ('decode ' )->andReturn ($ mockClaims );
271277
272278 $ this ->expectException (ClaimsException::class);
273- $ this ->expectExceptionMessage ('ID token has incorrect audience ' );
279+ $ this ->expectExceptionMessage ('ID token has incorrect audience(s): incorrect aud ' );
274280
275281 $ this ->provider ->validateIdToken ('token ' , self ::NONCE );
276282 }
@@ -285,7 +291,7 @@ public function testValidateIdTokenIssuer(): void
285291 $ mockJWT ->shouldReceive ('decode ' )->andReturn ($ mockClaims );
286292
287293 $ this ->expectException (ClaimsException::class);
288- $ this ->expectExceptionMessage ('ID token has incorrect issuer ' );
294+ $ this ->expectExceptionMessage ('ID token has incorrect issuer: incorrect iss ' );
289295
290296 $ this ->provider ->validateIdToken ('token ' , self ::NONCE );
291297 }
@@ -300,7 +306,7 @@ public function testValidateIdTokenNonce(): void
300306 $ mockJWT ->shouldReceive ('decode ' )->andReturn ($ mockClaims );
301307
302308 $ this ->expectException (ClaimsException::class);
303- $ this ->expectExceptionMessage ('ID token has incorrect nonce ' );
309+ $ this ->expectExceptionMessage ('ID token has incorrect nonce: incorrect nonce ' );
304310
305311 $ this ->provider ->validateIdToken ('token ' , self ::NONCE );
306312 }
@@ -310,7 +316,7 @@ public function testConstructBadUrl(): void
310316 $ mockCacheItemPool = $ this ->createStub (CacheItemPoolInterface::class);
311317
312318 $ this ->expectException (BadUrlException::class);
313- $ this ->expectExceptionMessage ('OpenIDConnectMetadataUrl is invalid ' );
319+ $ this ->expectExceptionMessage ('OpenIDConnectMetadataUrl is invalid: not-a-valid-url ' );
314320
315321 new OpenIdConfigurationProvider ([
316322 'cacheItemPool ' => $ mockCacheItemPool ,
@@ -323,7 +329,7 @@ public function testConstructHttpUrlNotAllowed(): void
323329 $ mockCacheItemPool = $ this ->createStub (CacheItemPoolInterface::class);
324330
325331 $ this ->expectException (IllegalSchemeException::class);
326- $ this ->expectExceptionMessage ('OpenIDConnectMetadataUrl must use https ' );
332+ $ this ->expectExceptionMessage ('OpenIDConnectMetadataUrl must use https: http://some.url/openid-configuration ' );
327333
328334 new OpenIdConfigurationProvider ([
329335 'cacheItemPool ' => $ mockCacheItemPool ,
@@ -421,10 +427,15 @@ public function testCheckResponseWithErrorStatusCode(): void
421427
422428 $ method = new \ReflectionMethod (OpenIdConfigurationProvider::class, 'checkResponse ' );
423429
424- $ this ->expectException (IdentityProviderException::class);
425- $ this ->expectExceptionMessage ('400 ' );
430+ try {
431+ $ method ->invoke ($ this ->provider , $ response , []);
432+ } catch (IdentityProviderException $ thrown ) {
433+ $ this ->assertSame ('400 ' , $ thrown ->getMessage ());
434+ $ this ->assertSame (0 , $ thrown ->getCode ());
426435
427- $ method ->invoke ($ this ->provider , $ response , []);
436+ return ;
437+ }
438+ $ this ->fail ('Expected IdentityProviderException ' );
428439 }
429440
430441 public function testCreateResourceOwner (): void
@@ -464,7 +475,7 @@ public function testValidateIdTokenArrayAudienceInvalid(): void
464475 $ mockJWT ->shouldReceive ('decode ' )->andReturn ($ mockClaims );
465476
466477 $ this ->expectException (ClaimsException::class);
467- $ this ->expectExceptionMessage ('ID token has incorrect audience ' );
478+ $ this ->expectExceptionMessage ('ID token has incorrect audience(s): wrong_client_1, wrong_client_2 ' );
468479
469480 $ this ->provider ->validateIdToken ('token ' , self ::NONCE );
470481 }
@@ -547,10 +558,71 @@ public function testGetIdTokenFailure(): void
547558 'httpClient ' => $ mockHttpClient ,
548559 ]);
549560
550- $ this ->expectException (CodeException::class);
551- $ this ->expectExceptionMessage ('Get ID token failed ' );
561+ try {
562+ $ provider ->getIdToken ('test-code ' );
563+ } catch (CodeException $ thrown ) {
564+ $ this ->assertSame ('Get ID token failed: Connection failed ' , $ thrown ->getMessage ());
565+ $ this ->assertSame (0 , $ thrown ->getCode ());
566+ $ this ->assertInstanceOf (ClientExceptionInterface::class, $ thrown ->getPrevious (), 'Original cause must be chained ' );
552567
553- $ provider ->getIdToken ('test-code ' );
568+ return ;
569+ }
570+ $ this ->fail ('Expected CodeException ' );
571+ }
572+
573+ public function testGetIdTokenRejectsInvalidJsonResponse (): void
574+ {
575+ $ tokenEndpoint = 'https://azure_b2c_test.b2clogin.com/azure_b2c_test.onmicrosoft.com/oauth2/v2.0/token?p=test-policy ' ;
576+ $ openIDConnectMetadataUrl = 'https://some.url/openid-configuration ' ;
577+
578+ $ mockConfigResponse = $ this ->getMockHttpSuccessResponse ('/../MockData/mockOpenIDConfiguration.json ' );
579+
580+ $ malformedTokenResponseBody = 'not valid json{{{ ' ;
581+ $ mockTokenStream = $ this ->createStub (StreamInterface::class);
582+ $ mockTokenStream ->method ('getContents ' )->willReturn ($ malformedTokenResponseBody );
583+ $ mockTokenStream ->method ('__toString ' )->willReturn ($ malformedTokenResponseBody );
584+
585+ $ mockTokenResponse = $ this ->createStub (ResponseInterface::class);
586+ $ mockTokenResponse ->method ('getStatusCode ' )->willReturn (200 );
587+ $ mockTokenResponse ->method ('getBody ' )->willReturn ($ mockTokenStream );
588+
589+ $ mockHttpClient = $ this ->createStub (ClientInterface::class);
590+ $ mockHttpClient ->method ('request ' )->willReturnMap ([
591+ ['GET ' , $ openIDConnectMetadataUrl , [], $ mockConfigResponse ],
592+ ['POST ' , $ tokenEndpoint , ['form_params ' => [
593+ 'client_id ' => self ::CLIENT_ID ,
594+ 'client_secret ' => self ::CLIENT_SECRET ,
595+ 'redirect_uri ' => self ::REDIRECT_URI ,
596+ 'grant_type ' => 'authorization_code ' ,
597+ 'code ' => 'test-code ' ,
598+ ]], $ mockTokenResponse ],
599+ ]);
600+
601+ $ mockCacheItem = $ this ->createStub (CacheItemInterface::class);
602+ $ mockCacheItem ->method ('isHit ' )->willReturn (false );
603+
604+ $ mockCacheItemPool = $ this ->createStub (CacheItemPoolInterface::class);
605+ $ mockCacheItemPool ->method ('getItem ' )->willReturn ($ mockCacheItem );
606+
607+ $ provider = new OpenIdConfigurationProvider ([
608+ 'openIDConnectMetadataUrl ' => $ openIDConnectMetadataUrl ,
609+ 'cacheItemPool ' => $ mockCacheItemPool ,
610+ 'clientId ' => self ::CLIENT_ID ,
611+ 'clientSecret ' => self ::CLIENT_SECRET ,
612+ 'redirectUri ' => self ::REDIRECT_URI ,
613+ ], [
614+ 'httpClient ' => $ mockHttpClient ,
615+ ]);
616+
617+ try {
618+ $ provider ->getIdToken ('test-code ' );
619+ } catch (CodeException $ thrown ) {
620+ $ this ->assertSame (0 , $ thrown ->getCode ());
621+ $ this ->assertInstanceOf (\JsonException::class, $ thrown ->getPrevious (), 'Original cause must be chained ' );
622+
623+ return ;
624+ }
625+ $ this ->fail ('Expected CodeException ' );
554626 }
555627
556628 public function testGetIdTokenRejectsResponseWithoutStringIdToken (): void
@@ -698,7 +770,7 @@ public function testFetchJsonResourceNon200(): void
698770 ]);
699771
700772 $ this ->expectException (HttpException::class);
701- $ this ->expectExceptionMessage ('Cannot access json resource ' );
773+ $ this ->expectExceptionMessage ('Cannot access json resource: https://some.url/openid-configuration ' );
702774
703775 $ provider ->getBaseAuthorizationUrl ();
704776 }
@@ -728,10 +800,16 @@ public function testFetchJsonResourceClientException(): void
728800 'httpClient ' => $ mockHttpClient ,
729801 ]);
730802
731- $ this ->expectException (HttpException::class);
732- $ this ->expectExceptionMessage ('Connection refused ' );
803+ try {
804+ $ provider ->getBaseAuthorizationUrl ();
805+ } catch (HttpException $ thrown ) {
806+ $ this ->assertSame ('Connection refused ' , $ thrown ->getMessage ());
807+ $ this ->assertSame (0 , $ thrown ->getCode ());
808+ $ this ->assertSame ($ exception , $ thrown ->getPrevious (), 'Original cause must be chained ' );
733809
734- $ provider ->getBaseAuthorizationUrl ();
810+ return ;
811+ }
812+ $ this ->fail ('Expected HttpException ' );
735813 }
736814
737815 public function testFetchJsonResourceInvalidJson (): void
@@ -764,9 +842,15 @@ public function testFetchJsonResourceInvalidJson(): void
764842 'httpClient ' => $ mockHttpClient ,
765843 ]);
766844
767- $ this ->expectException (\ItkDev \OpenIdConnect \Exception \JsonException::class);
845+ try {
846+ $ provider ->getBaseAuthorizationUrl ();
847+ } catch (\ItkDev \OpenIdConnect \Exception \JsonException $ thrown ) {
848+ $ this ->assertSame (0 , $ thrown ->getCode ());
849+ $ this ->assertInstanceOf (\JsonException::class, $ thrown ->getPrevious (), 'Original cause must be chained ' );
768850
769- $ provider ->getBaseAuthorizationUrl ();
851+ return ;
852+ }
853+ $ this ->fail ('Expected JsonException ' );
770854 }
771855
772856 public function testGetJwtVerificationKeysRejectsJwksMissingKeysArray (): void
@@ -978,10 +1062,16 @@ public function testGetConfigurationCacheInvalidArgument(): void
9781062 'httpClient ' => $ mockHttpClient ,
9791063 ]);
9801064
981- $ this ->expectException (CacheException::class);
982- $ this ->expectExceptionMessage ('Invalid cache key ' );
1065+ try {
1066+ $ provider ->getBaseAuthorizationUrl ();
1067+ } catch (CacheException $ thrown ) {
1068+ $ this ->assertSame ('Invalid cache key ' , $ thrown ->getMessage ());
1069+ $ this ->assertSame (0 , $ thrown ->getCode ());
1070+ $ this ->assertSame ($ exception , $ thrown ->getPrevious (), 'Original cause must be chained ' );
9831071
984- $ provider ->getBaseAuthorizationUrl ();
1072+ return ;
1073+ }
1074+ $ this ->fail ('Expected CacheException ' );
9851075 }
9861076
9871077 public function testGetJwtVerificationKeysCacheInvalidArgument (): void
@@ -1017,10 +1107,16 @@ public function testGetJwtVerificationKeysCacheInvalidArgument(): void
10171107 'httpClient ' => $ mockHttpClient ,
10181108 ]);
10191109
1020- $ this ->expectException (CacheException::class);
1021- $ this ->expectExceptionMessage ('Invalid jwks cache key ' );
1110+ try {
1111+ $ provider ->validateIdToken ('token ' , self ::NONCE );
1112+ } catch (CacheException $ thrown ) {
1113+ $ this ->assertSame ('Invalid jwks cache key ' , $ thrown ->getMessage ());
1114+ $ this ->assertSame (0 , $ thrown ->getCode ());
1115+ $ this ->assertSame ($ exception , $ thrown ->getPrevious (), 'Original cause must be chained ' );
10221116
1023- $ provider ->validateIdToken ('token ' , self ::NONCE );
1117+ return ;
1118+ }
1119+ $ this ->fail ('Expected CacheException ' );
10241120 }
10251121
10261122 public function testBase64urlDecodeFailure (): void
@@ -1065,7 +1161,7 @@ public function testBase64urlDecodeFailure(): void
10651161 $ mockJWT = \Mockery::mock ('overload:Firebase\JWT\JWT ' , MockJWT::class);
10661162
10671163 $ this ->expectException (\ItkDev \OpenIdConnect \Exception \DecodeException::class);
1068- $ this ->expectExceptionMessage ('Error url decoding input ' );
1164+ $ this ->expectExceptionMessage ('Error url decoding input !!! ' );
10691165
10701166 $ provider ->validateIdToken ('token ' , self ::NONCE );
10711167 }
0 commit comments