|
14 | 14 | use MinVWS\OpenIDConnectLaravel\Tests\TestCase;
|
15 | 15 | use Mockery;
|
16 | 16 |
|
17 |
| -use function MinVWS\OpenIDConnectLaravel\Tests\generateJwt; |
| 17 | +use function MinVWS\OpenIDConnectLaravel\Tests\{ |
| 18 | + generateJwt, |
| 19 | + generateOpenSSLKey, |
| 20 | +}; |
18 | 21 |
|
19 | 22 | class LoginControllerResponseTest extends TestCase
|
20 | 23 | {
|
@@ -90,7 +93,9 @@ public function testCodeChallengeIsSetWhenSupported(
|
90 | 93 | array $codeChallengesSupportedAtProvider,
|
91 | 94 | bool $codeChallengeShouldBeSet,
|
92 | 95 | ): void {
|
93 |
| - $this->mockOpenIDConfigurationLoader($codeChallengesSupportedAtProvider); |
| 96 | + $this->mockOpenIDConfigurationLoader( |
| 97 | + codeChallengeMethodsSupported: $codeChallengesSupportedAtProvider, |
| 98 | + ); |
94 | 99 | Config::set('oidc.code_challenge_method', $requestedCodeChallengeMethod);
|
95 | 100 |
|
96 | 101 | // Check if code verified is not set in cache.
|
@@ -207,21 +212,95 @@ public function testTokenSignedWithClientSecret(): void
|
207 | 212 | });
|
208 | 213 | }
|
209 | 214 |
|
210 |
| - protected function mockOpenIDConfigurationLoader(array $codeChallengeMethodsSupported = []): void |
| 215 | + public function testTokenSignedWithPrivateKey(): void |
211 | 216 | {
|
| 217 | + Http::fake([ |
| 218 | + // Token requested by OpenIDConnectClient::authenticate() function. |
| 219 | + 'https://provider.rdobeheer.nl/token' => Http::response([ |
| 220 | + 'access_token' => 'access-token-from-token-endpoint', |
| 221 | + 'id_token' => 'does-not-matter-not-testing-id-token', |
| 222 | + 'token_type' => 'Bearer', |
| 223 | + 'expires_in' => 3600, |
| 224 | + ]), |
| 225 | + ]); |
| 226 | + |
| 227 | + // Set OIDC provider configuration |
| 228 | + $this->mockOpenIDConfigurationLoader(tokenEndpointAuthMethodsSupported: ['private_key_jwt']); |
| 229 | + |
| 230 | + Config::set('oidc.issuer', 'https://provider.rdobeheer.nl'); |
| 231 | + Config::set('oidc.client_id', 'test-client-id'); |
| 232 | + |
| 233 | + // Set client private key |
| 234 | + [$key, $keyResource] = generateOpenSSLKey(); |
| 235 | + Config::set('oidc.client_authentication.signing_private_key_path', stream_get_meta_data($keyResource)['uri']); |
| 236 | + |
| 237 | + // Set current state, normally this is generated before logging in and send |
| 238 | + // to the issuer, when the user is redirected for login. |
| 239 | + Session::put('openid_connect_state', 'some-state'); |
| 240 | + |
| 241 | + // We simulate here that the user now comes back after successful login at issuer. |
| 242 | + $this->getRoute('oidc.login', ['code' => 'some-code', 'state' => 'some-state']); |
| 243 | + |
| 244 | + // Check if state and nonce are removed from session. |
| 245 | + $this->assertEmpty(session('openid_connect_state')); |
| 246 | + $this->assertEmpty(session('openid_connect_nonce')); |
| 247 | + |
| 248 | + Http::assertSentCount(1); |
| 249 | + Http::assertSentInOrder([ |
| 250 | + 'https://provider.rdobeheer.nl/token', |
| 251 | + ]); |
| 252 | + Http::assertSent(function (Request $request) { |
| 253 | + if (!in_array($request->url(), ['https://provider.rdobeheer.nl/token'], true)) { |
| 254 | + return false; |
| 255 | + } |
| 256 | + |
| 257 | + if ($request->url() === 'https://provider.rdobeheer.nl/token') { |
| 258 | + $this->assertSame( |
| 259 | + expected: 'POST', |
| 260 | + actual: $request->method(), |
| 261 | + ); |
| 262 | + |
| 263 | + // We only check if the client_assertion is set in the request body. |
| 264 | + // The JWT of the PrivateKeyJWTBuilder is tested in a separate test. |
| 265 | + $this->assertStringStartsWith( |
| 266 | + prefix: 'grant_type=authorization_code' |
| 267 | + . '&code=some-code' |
| 268 | + . '&redirect_uri=http%3A%2F%2Flocalhost%2Foidc%2Flogin' |
| 269 | + . '&client_id=test-client-id' |
| 270 | + . '&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer' |
| 271 | + . '&client_assertion=eyJhbGciOiJSUzI1NiJ9.', |
| 272 | + string: $request->body(), |
| 273 | + ); |
| 274 | + |
| 275 | + return true; |
| 276 | + } |
| 277 | + |
| 278 | + return true; |
| 279 | + }); |
| 280 | + } |
| 281 | + |
| 282 | + protected function mockOpenIDConfigurationLoader( |
| 283 | + array $tokenEndpointAuthMethodsSupported = ["none"], |
| 284 | + array $codeChallengeMethodsSupported = [], |
| 285 | + ): void { |
212 | 286 | $mock = Mockery::mock(OpenIDConfigurationLoader::class);
|
213 | 287 | $mock
|
214 | 288 | ->shouldReceive('getConfiguration')
|
215 |
| - ->andReturn($this->exampleOpenIDConfiguration($codeChallengeMethodsSupported)); |
| 289 | + ->andReturn($this->exampleOpenIDConfiguration( |
| 290 | + tokenEndpointAuthMethodsSupported: $tokenEndpointAuthMethodsSupported, |
| 291 | + codeChallengeMethodsSupported: $codeChallengeMethodsSupported, |
| 292 | + )); |
216 | 293 |
|
217 | 294 | $this->app->instance(OpenIDConfigurationLoader::class, $mock);
|
218 | 295 | }
|
219 | 296 |
|
220 |
| - protected function exampleOpenIDConfiguration(array $codeChallengeMethodsSupported = []): OpenIDConfiguration |
221 |
| - { |
| 297 | + protected function exampleOpenIDConfiguration( |
| 298 | + array $tokenEndpointAuthMethodsSupported = ["none"], |
| 299 | + array $codeChallengeMethodsSupported = [], |
| 300 | + ): OpenIDConfiguration { |
222 | 301 | return new OpenIDConfiguration(
|
223 | 302 | version: "3.0",
|
224 |
| - tokenEndpointAuthMethodsSupported: ["none"], |
| 303 | + tokenEndpointAuthMethodsSupported: $tokenEndpointAuthMethodsSupported, |
225 | 304 | claimsParameterSupported: true,
|
226 | 305 | requestParameterSupported: false,
|
227 | 306 | requestUriParameterSupported: true,
|
|
0 commit comments