diff --git a/composer.json b/composer.json index 09fed59..397a6f1 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "require": { "php": ">=8.1", - "jumbojett/openid-connect-php": "^1.0.0", + "jumbojett/openid-connect-php": "^1.0.2", "guzzlehttp/guzzle": "^7.5", "web-token/jwt-library": "^3.4" }, diff --git a/phpstan.neon b/phpstan.neon index 8baaf5e..5ba2d4f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,7 +2,5 @@ parameters: paths: - src level: 8 - excludePaths: - - src/BaseOpenIDConnectClient.php includes: - phar://phpstan.phar/conf/bleedingEdge.neon diff --git a/src/OpenIDConnectClient.php b/src/OpenIDConnectClient.php index 856117a..286526b 100644 --- a/src/OpenIDConnectClient.php +++ b/src/OpenIDConnectClient.php @@ -20,15 +20,11 @@ class OpenIDConnectClient extends \Jumbojett\OpenIDConnectClient { protected ?JweDecryptInterface $jweDecrypter; protected ?OpenIDConfiguration $openIDConfiguration; - /** - * @var int|null Response code from the server - */ - protected ?int $responseCode; /** * @var string|null Content type from the server */ - private ?string $responseContentType; + private ?string $internalResponseContentType = null; public function __construct( ?string $providerUrl = null, @@ -199,7 +195,7 @@ protected function fetchURL(string $url, string $post_body = null, array $header } $this->responseCode = $request->status(); - $this->responseContentType = $request->header('Content-Type'); + $this->internalResponseContentType = $request->header('Content-Type'); if ($request->failed()) { throw new OpenIDConnectClientException( @@ -227,7 +223,7 @@ public function getResponseCode(): int */ public function getResponseContentType(): ?string { - return $this->responseContentType; + return $this->internalResponseContentType; } public function setTlsVerify(bool|string $tlsVerify): void diff --git a/src/Services/ExceptionHandler.php b/src/Services/ExceptionHandler.php index de5a378..147f747 100644 --- a/src/Services/ExceptionHandler.php +++ b/src/Services/ExceptionHandler.php @@ -103,11 +103,8 @@ protected function default400Response(OpenIDConnectClientException $exception): protected function getRequest(): ?Request { + /** @psalm-var Request $request */ $request = request(); - if (!($request instanceof Request)) { - return null; - } - return $request; } } diff --git a/tests/Feature/Http/Controllers/LoginControllerResponseTest.php b/tests/Feature/Http/Controllers/LoginControllerResponseTest.php index 790a004..c8627ae 100644 --- a/tests/Feature/Http/Controllers/LoginControllerResponseTest.php +++ b/tests/Feature/Http/Controllers/LoginControllerResponseTest.php @@ -9,8 +9,10 @@ use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Session; use Illuminate\Testing\TestResponse; +use Jumbojett\OpenIDConnectClientException; use MinVWS\OpenIDConnectLaravel\OpenIDConfiguration\OpenIDConfiguration; use MinVWS\OpenIDConnectLaravel\OpenIDConfiguration\OpenIDConfigurationLoader; +use MinVWS\OpenIDConnectLaravel\Services\ExceptionHandlerInterface; use MinVWS\OpenIDConnectLaravel\Tests\TestCase; use Mockery; @@ -76,7 +78,7 @@ public function testNonceAndStateAreSetInCache(): void $response ->assertStatus(302) - ->assertRedirectContains("https://provider.rdobeheer.nl/authorize") + ->assertRedirectContains("https://provider.example.com/authorize") ->assertRedirectContains('response_type=code') ->assertRedirectContains('redirect_uri=http%3A%2F%2Flocalhost%2Foidc%2Flogin') ->assertRedirectContains('client_id=test-client-id') @@ -106,7 +108,7 @@ public function testCodeChallengeIsSetWhenSupported( $response ->assertStatus(302) - ->assertRedirectContains("https://provider.rdobeheer.nl/authorize"); + ->assertRedirectContains("https://provider.example.com/authorize"); if ($codeChallengeShouldBeSet) { $response @@ -129,36 +131,235 @@ public function codeChallengeMethodProvider(): array ]; } - public function testTokenSignedWithClientSecret(): void + public function testStateDoesNotMatch(): void + { + Http::fake([ + // Token requested by OpenIDConnectClient::authenticate() function. + // Currently needed because the package requests the token endpoint before checking the state. + // TODO: Remove if https://github.com/jumbojett/OpenID-Connect-PHP/pull/447 is merged. + 'https://provider.example.com/token' => Http::response([ + 'access_token' => 'access-token-from-token-endpoint', + 'id_token' => 'some-valid-token-not-needed-for-this-state-check', + 'token_type' => 'Bearer', + 'expires_in' => 3600, + ]), + ]); + + // Set OIDC config + $this->mockOpenIDConfigurationLoader(); + Config::set('oidc.issuer', 'https://provider.example.com'); + Config::set('oidc.client_id', 'test-client-id'); + Config::set('oidc.client_secret', 'the-secret-client-secret'); + + // Mock LoginResponseHandlerInterface to check handleExceptionWhileAuthenticate is called. + $mockExceptionHandler = Mockery::mock(ExceptionHandlerInterface::class); + $mockExceptionHandler + ->shouldReceive('handleExceptionWhileAuthenticate') + ->withArgs(function (OpenIDConnectClientException $e) { + return $e->getMessage() === 'Unable to determine state'; + }) + ->once(); + $this->app->instance(ExceptionHandlerInterface::class, $mockExceptionHandler); + + // Set the current state, which is usually generated and saved in the session before login, + // and sent to the issuer during the login redirect. + Session::put('openid_connect_state', 'some-state'); + + // We simulate here that the state does not match with the state in the session. + $this->getRoute('oidc.login', ['code' => 'some-code', 'state' => 'a-different-state']); + } + + public function testIdTokenSignedWithClientSecret(): void { $idToken = generateJwt([ - "iss" => "https://provider.rdobeheer.nl", + "iss" => "https://provider.example.com", "aud" => 'test-client-id', + "sub" => 'test-subject', ], 'the-secret-client-secret'); Http::fake([ // Token requested by OpenIDConnectClient::authenticate() function. - 'https://provider.rdobeheer.nl/token' => Http::response([ + 'https://provider.example.com/token' => Http::response([ 'access_token' => 'access-token-from-token-endpoint', 'id_token' => $idToken, 'token_type' => 'Bearer', 'expires_in' => 3600, ]), // User info requested by OpenIDConnectClient::requestUserInfo() function. - 'https://provider.rdobeheer.nl/userinfo?schema=openid' => Http::response([ - 'email' => 'teste@rdobeheer.nl', + 'https://provider.example.com/userinfo?schema=openid' => Http::response([ + 'email' => 'tester@example.com', + ]), + ]); + + // Set OIDC config + $this->mockOpenIDConfigurationLoader(); + + Config::set('oidc.issuer', 'https://provider.example.com'); + Config::set('oidc.client_id', 'test-client-id'); + Config::set('oidc.client_secret', 'the-secret-client-secret'); + + // Set the current state, which is usually generated and saved in the session before login, + // and sent to the issuer during the login redirect. + Session::put('openid_connect_state', 'some-state'); + + // We simulate here that the user now comes back after successful login at issuer. + $response = $this->getRoute('oidc.login', ['code' => 'some-code', 'state' => 'some-state']); + $response->assertStatus(200); + $response->assertJson([ + 'userInfo' => [ + 'email' => 'tester@example.com', + ] + ]); + + $this->assertEmpty(session('openid_connect_state')); + $this->assertEmpty(session('openid_connect_nonce')); + + Http::assertSentCount(2); + Http::assertSentInOrder([ + 'https://provider.example.com/token', + 'https://provider.example.com/userinfo?schema=openid', + ]); + Http::assertSent(function (Request $request) { + if ($request->url() === 'https://provider.example.com/token') { + $this->assertSame( + expected: 'POST', + actual: $request->method(), + ); + $this->assertSame( + expected: 'grant_type=authorization_code' + . '&code=some-code' + . '&redirect_uri=http%3A%2F%2Flocalhost%2Foidc%2Flogin' + . '&client_id=test-client-id' + . '&client_secret=the-secret-client-secret', + actual: $request->body(), + ); + return true; + } + + if ($request->url() === 'https://provider.example.com/userinfo?schema=openid') { + $this->assertSame( + expected: 'GET', + actual: $request->method(), + ); + $this->assertSame( + expected: [ + 'Bearer access-token-from-token-endpoint' + ], + actual: $request->header('Authorization'), + ); + } + + return true; + }); + } + + public function testIdTokenSignedWithIncorrectClientSecret(): void + { + $idToken = generateJwt([ + "iss" => "https://provider.example.com", + "aud" => 'test-client-id', + "sub" => 'test-subject', + ], 'not-the-secret-client-secret'); + + Http::fake([ + // Token requested by OpenIDConnectClient::authenticate() function. + 'https://provider.example.com/token' => Http::response([ + 'access_token' => 'access-token-from-token-endpoint', + 'id_token' => $idToken, + 'token_type' => 'Bearer', + 'expires_in' => 3600, + ]), + ]); + + // Set OIDC config + $this->mockOpenIDConfigurationLoader(); + Config::set('oidc.issuer', 'https://provider.example.com'); + Config::set('oidc.client_id', 'test-client-id'); + Config::set('oidc.client_secret', 'the-secret-client-secret'); + + // Mock LoginResponseHandlerInterface to check handleExceptionWhileAuthenticate is called. + $mockExceptionHandler = Mockery::mock(ExceptionHandlerInterface::class); + $mockExceptionHandler + ->shouldReceive('handleExceptionWhileAuthenticate') + ->withArgs(function (OpenIDConnectClientException $e) { + return $e->getMessage() === 'Unable to verify signature'; + }) + ->once(); + $this->app->instance(ExceptionHandlerInterface::class, $mockExceptionHandler); + + // Set the current state, which is usually generated and saved in the session before login, + // and sent to the issuer during the login redirect. + Session::put('openid_connect_state', 'some-state'); + + // We simulate here that the user now comes back after successful login at issuer. + $this->getRoute('oidc.login', ['code' => 'some-code', 'state' => 'some-state']); + + Http::assertSentCount(1); + Http::assertSentInOrder([ + 'https://provider.example.com/token', + ]); + Http::assertSent(function (Request $request) { + if ($request->url() === 'https://provider.example.com/token') { + $this->assertSame( + expected: 'POST', + actual: $request->method(), + ); + $this->assertSame( + expected: 'grant_type=authorization_code' + . '&code=some-code' + . '&redirect_uri=http%3A%2F%2Flocalhost%2Foidc%2Flogin' + . '&client_id=test-client-id' + . '&client_secret=the-secret-client-secret', + actual: $request->body(), + ); + return true; + } + return true; + }); + } + + public function testIdTokenAndUserinfoSignedWithClientSecret(): void + { + $idToken = generateJwt([ + "iss" => "https://provider.example.com", + "aud" => 'test-client-id', + "sub" => 'test-subject', + ], 'the-secret-client-secret'); + + $signedUserInfo = generateJwt([ + "iss" => "https://provider.example.com", + "aud" => 'test-client-id', + "sub" => 'test-subject', + "email" => 'tester@example.com', + ], 'the-secret-client-secret'); + + Http::fake([ + // Token requested by OpenIDConnectClient::authenticate() function. + 'https://provider.example.com/token' => Http::response([ + 'access_token' => 'access-token-from-token-endpoint', + 'id_token' => $idToken, + 'token_type' => 'Bearer', + 'expires_in' => 3600, ]), + // User info requested by OpenIDConnectClient::requestUserInfo() function. + 'https://provider.example.com/userinfo?schema=openid' => Http::response( + body: $signedUserInfo, + status: 200, + headers: [ + 'Content-Type' => 'application/jwt', + ] + ), ]); // Set OIDC config $this->mockOpenIDConfigurationLoader(); - Config::set('oidc.issuer', 'https://provider.rdobeheer.nl'); + Config::set('oidc.issuer', 'https://provider.example.com'); Config::set('oidc.client_id', 'test-client-id'); Config::set('oidc.client_secret', 'the-secret-client-secret'); - // Set current state, normally this is generated before logging in and send - // to the issuer, when the user is redirected for login. + // Set the current state, which is usually generated and saved in the session before login, + // and sent to the issuer during the login redirect. Session::put('openid_connect_state', 'some-state'); // We simulate here that the user now comes back after successful login at issuer. @@ -166,7 +367,7 @@ public function testTokenSignedWithClientSecret(): void $response->assertStatus(200); $response->assertJson([ 'userInfo' => [ - 'email' => 'teste@rdobeheer.nl', + 'email' => 'tester@example.com', ] ]); @@ -175,11 +376,110 @@ public function testTokenSignedWithClientSecret(): void Http::assertSentCount(2); Http::assertSentInOrder([ - 'https://provider.rdobeheer.nl/token', - 'https://provider.rdobeheer.nl/userinfo?schema=openid', + 'https://provider.example.com/token', + 'https://provider.example.com/userinfo?schema=openid', + ]); + Http::assertSent(function (Request $request) { + if ($request->url() === 'https://provider.example.com/token') { + $this->assertSame( + expected: 'POST', + actual: $request->method(), + ); + $this->assertSame( + expected: 'grant_type=authorization_code' + . '&code=some-code' + . '&redirect_uri=http%3A%2F%2Flocalhost%2Foidc%2Flogin' + . '&client_id=test-client-id' + . '&client_secret=the-secret-client-secret', + actual: $request->body(), + ); + return true; + } + + if ($request->url() === 'https://provider.example.com/userinfo?schema=openid') { + $this->assertSame( + expected: 'GET', + actual: $request->method(), + ); + $this->assertSame( + expected: [ + 'Bearer access-token-from-token-endpoint' + ], + actual: $request->header('Authorization'), + ); + } + + return true; + }); + } + + public function testSubClaimIdTokenDoesNotEqualsSubClaimUserinfo(): void + { + $idToken = generateJwt([ + "iss" => "https://provider.example.com", + "aud" => 'test-client-id', + "sub" => 'test-subject', + ], 'the-secret-client-secret'); + + $signedUserInfo = generateJwt([ + "iss" => "https://provider.example.com", + "aud" => 'test-client-id', + "sub" => 'different-subject', + "email" => 'tester@example.com', + ], 'the-secret-client-secret'); + + Http::fake([ + // Token requested by OpenIDConnectClient::authenticate() function. + 'https://provider.example.com/token' => Http::response([ + 'access_token' => 'access-token-from-token-endpoint', + 'id_token' => $idToken, + 'token_type' => 'Bearer', + 'expires_in' => 3600, + ]), + // User info requested by OpenIDConnectClient::requestUserInfo() function. + 'https://provider.example.com/userinfo?schema=openid' => Http::response( + body: $signedUserInfo, + status: 200, + headers: [ + 'Content-Type' => 'application/jwt', + ] + ), + ]); + + // Set OIDC config + $this->mockOpenIDConfigurationLoader(); + + Config::set('oidc.issuer', 'https://provider.example.com'); + Config::set('oidc.client_id', 'test-client-id'); + Config::set('oidc.client_secret', 'the-secret-client-secret'); + + // Mock LoginResponseHandlerInterface to check handleExceptionWhileRequestUserInfo is called. + $mockExceptionHandler = Mockery::mock(ExceptionHandlerInterface::class); + $mockExceptionHandler + ->shouldReceive('handleExceptionWhileRequestUserInfo') + ->withArgs(function (OpenIDConnectClientException $e) { + return $e->getMessage() === 'Invalid JWT signature'; + }) + ->once(); + $this->app->instance(ExceptionHandlerInterface::class, $mockExceptionHandler); + + // Set the current state, which is usually generated and saved in the session before login, + // and sent to the issuer during the login redirect. + Session::put('openid_connect_state', 'some-state'); + + // We simulate here that the user now comes back after successful login at issuer. + $this->getRoute('oidc.login', ['code' => 'some-code', 'state' => 'some-state']); + + $this->assertEmpty(session('openid_connect_state')); + $this->assertEmpty(session('openid_connect_nonce')); + + Http::assertSentCount(2); + Http::assertSentInOrder([ + 'https://provider.example.com/token', + 'https://provider.example.com/userinfo?schema=openid', ]); Http::assertSent(function (Request $request) { - if ($request->url() === 'https://provider.rdobeheer.nl/token') { + if ($request->url() === 'https://provider.example.com/token') { $this->assertSame( expected: 'POST', actual: $request->method(), @@ -195,7 +495,7 @@ public function testTokenSignedWithClientSecret(): void return true; } - if ($request->url() === 'https://provider.rdobeheer.nl/userinfo?schema=openid') { + if ($request->url() === 'https://provider.example.com/userinfo?schema=openid') { $this->assertSame( expected: 'GET', actual: $request->method(), @@ -216,7 +516,7 @@ public function testTokenSignedWithPrivateKey(): void { Http::fake([ // Token requested by OpenIDConnectClient::authenticate() function. - 'https://provider.rdobeheer.nl/token' => Http::response([ + 'https://provider.example.com/token' => Http::response([ 'access_token' => 'access-token-from-token-endpoint', 'id_token' => 'does-not-matter-not-testing-id-token', 'token_type' => 'Bearer', @@ -227,15 +527,15 @@ public function testTokenSignedWithPrivateKey(): void // Set OIDC provider configuration $this->mockOpenIDConfigurationLoader(tokenEndpointAuthMethodsSupported: ['private_key_jwt']); - Config::set('oidc.issuer', 'https://provider.rdobeheer.nl'); + Config::set('oidc.issuer', 'https://provider.example.com'); Config::set('oidc.client_id', 'test-client-id'); // Set client private key [$key, $keyResource] = generateOpenSSLKey(); Config::set('oidc.client_authentication.signing_private_key_path', stream_get_meta_data($keyResource)['uri']); - // Set current state, normally this is generated before logging in and send - // to the issuer, when the user is redirected for login. + // Set the current state, which is usually generated and saved in the session before login, + // and sent to the issuer during the login redirect. Session::put('openid_connect_state', 'some-state'); // We simulate here that the user now comes back after successful login at issuer. @@ -247,14 +547,14 @@ public function testTokenSignedWithPrivateKey(): void Http::assertSentCount(1); Http::assertSentInOrder([ - 'https://provider.rdobeheer.nl/token', + 'https://provider.example.com/token', ]); Http::assertSent(function (Request $request) { - if (!in_array($request->url(), ['https://provider.rdobeheer.nl/token'], true)) { + if (!in_array($request->url(), ['https://provider.example.com/token'], true)) { return false; } - if ($request->url() === 'https://provider.rdobeheer.nl/token') { + if ($request->url() === 'https://provider.example.com/token') { $this->assertSame( expected: 'POST', actual: $request->method(), @@ -310,16 +610,16 @@ protected function exampleOpenIDConfiguration( frontchannelLogoutSessionSupported: false, backchannelLogoutSupported: false, backchannelLogoutSessionSupported: false, - issuer: "https://provider.rdobeheer.nl", - authorizationEndpoint: "https://provider.rdobeheer.nl/authorize", - jwksUri: "https://provider.rdobeheer.nl/jwks", - tokenEndpoint: "https://provider.rdobeheer.nl/token", + issuer: "https://provider.example.com", + authorizationEndpoint: "https://provider.example.com/authorize", + jwksUri: "https://provider.example.com/jwks", + tokenEndpoint: "https://provider.example.com/token", scopesSupported: ["openid"], responseTypesSupported: ["code"], responseModesSupported: ["query"], subjectTypesSupported: ["pairwise"], idTokenSigningAlgValuesSupported: ["RS256"], - userinfoEndpoint: "https://provider.rdobeheer.nl/userinfo", + userinfoEndpoint: "https://provider.example.com/userinfo", codeChallengeMethodsSupported: $codeChallengeMethodsSupported, ); } diff --git a/tests/Feature/Http/Controllers/LoginControllerTest.php b/tests/Feature/Http/Controllers/LoginControllerTest.php index 133f054..c9d85bd 100644 --- a/tests/Feature/Http/Controllers/LoginControllerTest.php +++ b/tests/Feature/Http/Controllers/LoginControllerTest.php @@ -32,7 +32,7 @@ public function testLoginRouteRedirectsToAuthorizeUrlOfProvider(): void $response = $this->get(route('oidc.login')); $response ->assertStatus(302) - ->assertRedirectContains("https://provider.rdobeheer.nl/authorize") + ->assertRedirectContains("https://provider.example.com/authorize") ->assertRedirectContains('response_type=code') ->assertRedirectContains('redirect_uri=http%3A%2F%2Flocalhost%2Foidc%2Flogin') ->assertRedirectContains('client_id=test-client-id') @@ -55,7 +55,7 @@ public function testLoginRouteRedirectsToAuthorizeUrlOfProviderWithScopes( $response = $this->get(route('oidc.login', ['login_hint' => 'test-login-hint'])); $response ->assertStatus(302) - ->assertRedirectContains("https://provider.rdobeheer.nl/authorize") + ->assertRedirectContains("https://provider.example.com/authorize") ->assertRedirectContains('test-client-id') ->assertRedirectContains('login_hint=test-login-hint') ->assertRedirectContains($scopeInUrl); @@ -79,7 +79,7 @@ public function testLoginRouteRedirectsToAuthorizeUrlOfProviderWithLoginHint(): $response = $this->get(route('oidc.login', ['login_hint' => 'test-login-hint'])); $response ->assertStatus(302) - ->assertRedirectContains("https://provider.rdobeheer.nl/authorize") + ->assertRedirectContains("https://provider.example.com/authorize") ->assertRedirectContains('test-client-id') ->assertRedirectContains('login_hint=test-login-hint'); } @@ -139,16 +139,16 @@ protected function exampleOpenIDConfiguration(): OpenIDConfiguration frontchannelLogoutSessionSupported: false, backchannelLogoutSupported: false, backchannelLogoutSessionSupported: false, - issuer: "https://provider.rdobeheer.nl", - authorizationEndpoint: "https://provider.rdobeheer.nl/authorize", - jwksUri: "https://provider.rdobeheer.nl/jwks", - tokenEndpoint: "https://provider.rdobeheer.nl/token", + issuer: "https://provider.example.com", + authorizationEndpoint: "https://provider.example.com/authorize", + jwksUri: "https://provider.example.com/jwks", + tokenEndpoint: "https://provider.example.com/token", scopesSupported: ["openid"], responseTypesSupported: ["code"], responseModesSupported: ["query"], subjectTypesSupported: ["pairwise"], idTokenSigningAlgValuesSupported: ["RS256"], - userinfoEndpoint: "https://provider.rdobeheer.nl/userinfo", + userinfoEndpoint: "https://provider.example.com/userinfo", codeChallengeMethodsSupported: ["S256"], ); } diff --git a/tests/Feature/OpenIDConfiguration/OpenIDConfigurationLoaderTest.php b/tests/Feature/OpenIDConfiguration/OpenIDConfigurationLoaderTest.php index 8e58d75..251d3dc 100644 --- a/tests/Feature/OpenIDConfiguration/OpenIDConfigurationLoaderTest.php +++ b/tests/Feature/OpenIDConfiguration/OpenIDConfigurationLoaderTest.php @@ -27,17 +27,17 @@ public function testConfigurationIsLoaded(): void $this->fakeSuccessfulResponse(); $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); $this->assertSame("3.0", $configuration->version); - $this->assertSame("https://provider.rdobeheer.nl", $configuration->issuer); - $this->assertSame("https://provider.rdobeheer.nl/authorize", $configuration->authorizationEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/jwks", $configuration->jwksUri); - $this->assertSame("https://provider.rdobeheer.nl/token", $configuration->tokenEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/userinfo", $configuration->userinfoEndpoint); + $this->assertSame("https://provider.example.com", $configuration->issuer); + $this->assertSame("https://provider.example.com/authorize", $configuration->authorizationEndpoint); + $this->assertSame("https://provider.example.com/jwks", $configuration->jwksUri); + $this->assertSame("https://provider.example.com/token", $configuration->tokenEndpoint); + $this->assertSame("https://provider.example.com/userinfo", $configuration->userinfoEndpoint); } public function testConfigurationIsLoadedMultipleTimesWhenNotCached(): void @@ -45,7 +45,7 @@ public function testConfigurationIsLoadedMultipleTimesWhenNotCached(): void $this->fakeSuccessfulResponse(); $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); // Load 2 times @@ -55,11 +55,11 @@ public function testConfigurationIsLoadedMultipleTimesWhenNotCached(): void Http::assertSentCount(2); $this->assertSame("3.0", $configuration->version); - $this->assertSame("https://provider.rdobeheer.nl", $configuration->issuer); - $this->assertSame("https://provider.rdobeheer.nl/authorize", $configuration->authorizationEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/jwks", $configuration->jwksUri); - $this->assertSame("https://provider.rdobeheer.nl/token", $configuration->tokenEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/userinfo", $configuration->userinfoEndpoint); + $this->assertSame("https://provider.example.com", $configuration->issuer); + $this->assertSame("https://provider.example.com/authorize", $configuration->authorizationEndpoint); + $this->assertSame("https://provider.example.com/jwks", $configuration->jwksUri); + $this->assertSame("https://provider.example.com/token", $configuration->tokenEndpoint); + $this->assertSame("https://provider.example.com/userinfo", $configuration->userinfoEndpoint); } public function testConfigurationIsCached(): void @@ -67,7 +67,7 @@ public function testConfigurationIsCached(): void $this->fakeSuccessfulResponse(); $loader = new OpenIDConfigurationLoader( - issuer: 'https://provider.rdobeheer.nl', + issuer: 'https://provider.example.com', cacheStore: Cache::store('array'), cacheTtl: 86400, ); @@ -82,11 +82,11 @@ public function testConfigurationIsCached(): void Http::assertSentCount(1); $this->assertSame("3.0", $configuration->version); - $this->assertSame("https://provider.rdobeheer.nl", $configuration->issuer); - $this->assertSame("https://provider.rdobeheer.nl/authorize", $configuration->authorizationEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/jwks", $configuration->jwksUri); - $this->assertSame("https://provider.rdobeheer.nl/token", $configuration->tokenEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/userinfo", $configuration->userinfoEndpoint); + $this->assertSame("https://provider.example.com", $configuration->issuer); + $this->assertSame("https://provider.example.com/authorize", $configuration->authorizationEndpoint); + $this->assertSame("https://provider.example.com/jwks", $configuration->jwksUri); + $this->assertSame("https://provider.example.com/token", $configuration->tokenEndpoint); + $this->assertSame("https://provider.example.com/userinfo", $configuration->userinfoEndpoint); } public function testLoaderThrowsExceptionWhenProviderReturns400ResponseCode(): void @@ -97,7 +97,7 @@ public function testLoaderThrowsExceptionWhenProviderReturns400ResponseCode(): v $this->expectExceptionMessage("Could not load OpenID configuration from issuer"); $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); @@ -110,14 +110,14 @@ public function testLoaderThrowsExceptionWhenProviderReturns400ResponseCodeAsser try { $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); } catch (OpenIDConfigurationLoaderException $exception) { $this->assertSame("Could not load OpenID configuration from issuer", $exception->getMessage()); $context = $exception->context(); - $this->assertSame("https://provider.rdobeheer.nl", $context['issuer']); + $this->assertSame("https://provider.example.com", $context['issuer']); $this->assertSame("/.well-known/openid-configuration", $context['url']); $this->assertSame(400, $context['response_status_code']); } @@ -129,14 +129,14 @@ public function testLoaderThrowsExceptionWhenProviderReturns500ResponseCodeAsser try { $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); } catch (OpenIDConfigurationLoaderException $exception) { $this->assertSame("Could not load OpenID configuration from issuer", $exception->getMessage()); $context = $exception->context(); - $this->assertSame("https://provider.rdobeheer.nl", $context['issuer']); + $this->assertSame("https://provider.example.com", $context['issuer']); $this->assertSame("/.well-known/openid-configuration", $context['url']); $this->assertSame(500, $context['response_status_code']); } @@ -148,14 +148,14 @@ public function testLoaderThrowsExceptionWhenProviderReturns200ButNullResponse() try { $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); } catch (OpenIDConfigurationLoaderException $exception) { $this->assertSame("Response body of OpenID configuration is not JSON", $exception->getMessage()); $context = $exception->context(); - $this->assertSame("https://provider.rdobeheer.nl", $context['issuer']); + $this->assertSame("https://provider.example.com", $context['issuer']); $this->assertSame("/.well-known/openid-configuration", $context['url']); $this->assertSame(200, $context['response_status_code']); $this->assertSame('', $context['response_body']); @@ -168,14 +168,14 @@ public function testLoaderThrowsExceptionWhenProviderReturns200ButStringResponse try { $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); } catch (OpenIDConfigurationLoaderException $exception) { $this->assertSame("Response body of OpenID configuration is not JSON", $exception->getMessage()); $context = $exception->context(); - $this->assertSame("https://provider.rdobeheer.nl", $context['issuer']); + $this->assertSame("https://provider.example.com", $context['issuer']); $this->assertSame("/.well-known/openid-configuration", $context['url']); $this->assertSame(200, $context['response_status_code']); $this->assertSame('some invalid response', $context['response_body']); @@ -189,7 +189,7 @@ public function testLoaderReturnsEmptyConfigurationOnEmptyJsonResponse(): void $loader = new OpenIDConfigurationLoader( - 'https://provider.rdobeheer.nl', + 'https://provider.example.com', ); $configuration = $loader->getConfiguration(); @@ -205,7 +205,7 @@ public function testConfigurationIsLoadedMultipleTimesWhenCacheStoreIsNull(): vo $this->fakeSuccessfulResponse(); $loader = new OpenIDConfigurationLoader( - issuer: 'https://provider.rdobeheer.nl', + issuer: 'https://provider.example.com', cacheStore: Cache::store('null'), ); @@ -216,17 +216,17 @@ public function testConfigurationIsLoadedMultipleTimesWhenCacheStoreIsNull(): vo Http::assertSentCount(2); $this->assertSame("3.0", $configuration->version); - $this->assertSame("https://provider.rdobeheer.nl", $configuration->issuer); - $this->assertSame("https://provider.rdobeheer.nl/authorize", $configuration->authorizationEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/jwks", $configuration->jwksUri); - $this->assertSame("https://provider.rdobeheer.nl/token", $configuration->tokenEndpoint); - $this->assertSame("https://provider.rdobeheer.nl/userinfo", $configuration->userinfoEndpoint); + $this->assertSame("https://provider.example.com", $configuration->issuer); + $this->assertSame("https://provider.example.com/authorize", $configuration->authorizationEndpoint); + $this->assertSame("https://provider.example.com/jwks", $configuration->jwksUri); + $this->assertSame("https://provider.example.com/token", $configuration->tokenEndpoint); + $this->assertSame("https://provider.example.com/userinfo", $configuration->userinfoEndpoint); } protected function fakeSuccessfulResponse(): void { Http::fake([ - 'https://provider.rdobeheer.nl/.well-known/openid-configuration' => Http::response([ + 'https://provider.example.com/.well-known/openid-configuration' => Http::response([ "version" => "3.0", "token_endpoint_auth_methods_supported" => [ "none" @@ -242,10 +242,10 @@ protected function fakeSuccessfulResponse(): void "frontchannel_logout_session_supported" => false, "backchannel_logout_supported" => false, "backchannel_logout_session_supported" => false, - "issuer" => "https://provider.rdobeheer.nl", - "authorization_endpoint" => "https://provider.rdobeheer.nl/authorize", - "jwks_uri" => "https://provider.rdobeheer.nl/jwks", - "token_endpoint" => "https://provider.rdobeheer.nl/token", + "issuer" => "https://provider.example.com", + "authorization_endpoint" => "https://provider.example.com/authorize", + "jwks_uri" => "https://provider.example.com/jwks", + "token_endpoint" => "https://provider.example.com/token", "scopes_supported" => [ "openid" ], @@ -258,7 +258,7 @@ protected function fakeSuccessfulResponse(): void "subject_types_supported" => [ "pairwise" ], - "userinfo_endpoint" => "https://provider.rdobeheer.nl/userinfo", + "userinfo_endpoint" => "https://provider.example.com/userinfo", "id_token_signing_alg_values_supported" => [ "RS256" ], @@ -272,7 +272,7 @@ protected function fakeSuccessfulResponse(): void protected function fakeInvalidResponse(int $statusCode, array|null|string $body): void { Http::fake([ - 'https://provider.rdobeheer.nl/*' => Http::response($body, $statusCode), + 'https://provider.example.com/*' => Http::response($body, $statusCode), ]); } }