Failed Conditions
Pull Request — master (#158)
by
unknown
05:45
created

theClientWithTrustedIssuerAssertionIsAuthenticated()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 19
c 1
b 1
f 0
dl 0
loc 26
rs 9.6333
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2019 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace OAuth2Framework\Component\ClientAuthentication\Tests;
15
16
use Jose\Component\Checker\ClaimCheckerManager;
17
use Jose\Component\Checker\HeaderCheckerManager;
18
use Jose\Component\Core\AlgorithmManager;
19
use Jose\Component\Core\JWK;
20
use Jose\Component\Core\JWKSet;
21
use Jose\Component\Core\Util\JsonConverter;
22
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
23
use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256;
24
use Jose\Component\Encryption\Compression\CompressionMethodManager;
25
use Jose\Component\Encryption\Compression\Deflate;
26
use Jose\Component\Encryption\JWEBuilder;
27
use Jose\Component\Encryption\JWEDecrypter;
28
use Jose\Component\Encryption\JWELoader;
29
use Jose\Component\Encryption\JWETokenSupport;
30
use Jose\Component\Encryption\Serializer\JWESerializerManager;
31
use Jose\Component\Signature\Algorithm\HS256;
32
use Jose\Component\Signature\Algorithm\RS256;
33
use Jose\Component\Signature\JWS;
34
use Jose\Component\Signature\JWSBuilder;
35
use Jose\Component\Signature\JWSTokenSupport;
36
use Jose\Component\Signature\JWSVerifier;
37
use Jose\Component\Signature\Serializer\CompactSerializer;
38
use OAuth2Framework\Component\ClientAuthentication\AuthenticationMethodManager;
39
use OAuth2Framework\Component\ClientAuthentication\ClientAssertionJwt;
40
use OAuth2Framework\Component\Core\Client\Client;
41
use OAuth2Framework\Component\Core\Client\ClientId;
42
use OAuth2Framework\Component\Core\DataBag\DataBag;
43
use OAuth2Framework\Component\Core\Message\OAuth2Error;
44
use OAuth2Framework\Component\Core\TrustedIssuer\TrustedIssuer;
45
use OAuth2Framework\Component\Core\TrustedIssuer\TrustedIssuerRepository;
46
use PHPUnit\Framework\TestCase;
47
use Prophecy\Prophecy\ObjectProphecy;
48
use Psr\Http\Message\ServerRequestInterface;
49
use Psr\Http\Message\StreamInterface;
50
use function Safe\json_decode;
51
52
/**
53
 * @group TokenEndpoint
54
 * @group ClientAuthentication
55
 *
56
 * @internal
57
 */
58
final class ClientAssertionJwtAuthenticationMethodTest extends TestCase
59
{
60
    /**
61
     * @var null|ClientAssertionJwt
62
     */
63
    private $method;
64
65
    /**
66
     * @test
67
     */
68
    public function genericCalls()
69
    {
70
        $method = $this->getMethod();
71
72
        static::assertEquals([], $method->getSchemesParameters());
73
        static::assertEquals(['client_secret_jwt', 'private_key_jwt'], $method->getSupportedMethods());
74
        static::assertEquals(['HS256', 'RS256'], $method->getSupportedSignatureAlgorithms());
75
        static::assertEquals([], $method->getSupportedKeyEncryptionAlgorithms());
76
        static::assertEquals([], $method->getSupportedContentEncryptionAlgorithms());
77
    }
78
79
    /**
80
     * @test
81
     */
82
    public function genericCallsWithEncryptionSupport()
83
    {
84
        $method = $this->getMethodWithEncryptionSupport(false);
85
86
        static::assertEquals([], $method->getSchemesParameters());
87
        static::assertEquals(['client_secret_jwt', 'private_key_jwt'], $method->getSupportedMethods());
88
        static::assertEquals(['HS256', 'RS256'], $method->getSupportedSignatureAlgorithms());
89
        static::assertEquals(['RSA-OAEP-256'], $method->getSupportedKeyEncryptionAlgorithms());
90
        static::assertEquals(['A256CBC-HS512'], $method->getSupportedContentEncryptionAlgorithms());
91
    }
92
93
    /**
94
     * @test
95
     */
96
    public function theClientIdCannotBeFoundInTheRequest()
97
    {
98
        $method = $this->getMethod();
99
        $request = $this->buildRequest([]);
100
        $request->getParsedBody()->willReturn([]);
101
        $request->getHeader('Authorization')->willReturn([]);
102
103
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
104
        static::assertNull($clientId);
105
        static::assertNull($credentials);
106
    }
107
108
    /**
109
     * @test
110
     */
111
    public function theClientAssertionTypeIsNotSupported()
112
    {
113
        $method = $this->getMethod();
114
        $request = $this->buildRequest([
115
            'client_assertion_type' => 'foo',
116
        ]);
117
118
        $request->getHeader('Authorization')->willReturn([]);
119
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
120
        static::assertNull($clientId);
121
        static::assertNull($credentials);
122
    }
123
124
    /**
125
     * @test
126
     */
127
    public function theClientAssertionIsMissing()
128
    {
129
        $method = $this->getMethod();
130
        $request = $this->buildRequest([
131
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
132
        ]);
133
134
        $request->getHeader('Authorization')->willReturn([]);
135
136
        try {
137
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
138
            static::fail('An OAuth2 exception should be thrown.');
139
        } catch (OAuth2Error $e) {
140
            static::assertEquals('invalid_request', $e->getMessage());
141
            static::assertEquals('Parameter "client_assertion" is missing.', $e->getErrorDescription());
142
        }
143
    }
144
145
    /**
146
     * @test
147
     */
148
    public function theClientAssertionIsInvalid()
149
    {
150
        $method = $this->getMethod();
151
        $request = $this->buildRequest([
152
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
153
            'client_assertion' => 'foo',
154
        ]);
155
156
        $request->getHeader('Authorization')->willReturn([]);
157
158
        try {
159
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
160
            static::fail('An OAuth2 exception should be thrown.');
161
        } catch (OAuth2Error $e) {
162
            static::assertEquals('invalid_request', $e->getMessage());
163
            static::assertEquals('Unable to load, decrypt or verify the client assertion.', $e->getErrorDescription());
164
        }
165
    }
166
167
    /**
168
     * @test
169
     */
170
    public function theClientAssertionSignedByTheClientIsInvalidBecauseOfMissingClaims()
171
    {
172
        $assertion = $this->serializeJWS(
173
            $this->createInvalidClientAssertionSignedByTheClient()
174
        );
175
        $method = $this->getMethod();
176
        $request = $this->buildRequest([
177
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
178
            'client_assertion' => $assertion,
179
        ]);
180
181
        $request->getHeader('Authorization')->willReturn([]);
182
183
        try {
184
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
185
            static::fail('An OAuth2 exception should be thrown.');
186
        } catch (OAuth2Error $e) {
187
            static::assertEquals('invalid_request', $e->getMessage());
188
            static::assertEquals('The following claim(s) is/are mandatory: "iss, sub, aud, exp".', $e->getErrorDescription());
189
        }
190
    }
191
192
    /**
193
     * @test
194
     */
195
    public function theClientAssertionSignedByTheClientIsRejectedBecauseEncryptionIsMandatory()
196
    {
197
        $assertion = $this->serializeJWS(
198
            $this->createInvalidClientAssertionSignedByTheClient()
199
        );
200
        $method = $this->getMethodWithEncryptionSupport(true);
201
        $request = $this->buildRequest([
202
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
203
            'client_assertion' => $assertion,
204
        ]);
205
206
        $request->getHeader('Authorization')->willReturn([]);
207
208
        try {
209
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
210
            static::fail('An OAuth2 exception should be thrown.');
211
        } catch (OAuth2Error $e) {
212
            static::assertEquals('invalid_request', $e->getMessage());
213
            static::assertEquals('The encryption of the assertion is mandatory but the decryption of the assertion failed.', $e->getErrorDescription());
214
        }
215
    }
216
217
    /**
218
     * @test
219
     */
220
    public function theEncryptedClientAssertionSignedAndEncryptedByTheClientIsInvalidBecauseOfMissingClaims()
221
    {
222
        $assertion = $this->encryptAssertion(
223
            $this->serializeJWS(
224
                $this->createInvalidClientAssertionSignedByTheClient()
225
            )
226
        );
227
        $method = $this->getMethodWithEncryptionSupport(false);
228
        $request = $this->buildRequest([
229
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
230
            'client_assertion' => $assertion,
231
        ]);
232
233
        $request->getHeader('Authorization')->willReturn([]);
234
235
        try {
236
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
237
            static::fail('An OAuth2 exception should be thrown.');
238
        } catch (OAuth2Error $e) {
239
            static::assertEquals('invalid_request', $e->getMessage());
240
            static::assertEquals('The following claim(s) is/are mandatory: "iss, sub, aud, exp".', $e->getErrorDescription());
241
        }
242
    }
243
244
    /**
245
     * @test
246
     */
247
    public function theClientAssertionIsValidAndTheClientIdIsRetrieved()
248
    {
249
        $assertion = $this->serializeJWS(
250
            $this->createValidClientAssertionSignedByTheClient()
251
        );
252
        $method = $this->getMethod();
253
        $request = $this->buildRequest([
254
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
255
            'client_assertion' => $assertion,
256
        ]);
257
258
        $request->getHeader('Authorization')->willReturn([]);
259
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
260
        static::assertEquals('ClientId', $clientId->getValue());
261
    }
262
263
    /**
264
     * @test
265
     */
266
    public function theEncryptedClientAssertionIsValidAndTheClientIdIsRetrieved()
267
    {
268
        $assertion = $this->encryptAssertion(
269
            $this->serializeJWS(
270
                $this->createValidClientAssertionSignedByTheClient()
271
            )
272
        );
273
        $method = $this->getMethodWithEncryptionSupport(false);
274
        $request = $this->buildRequest([
275
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
276
            'client_assertion' => $assertion,
277
        ]);
278
        $request->getHeader('Authorization')->willReturn([]);
279
280
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
281
        static::assertEquals('ClientId', $clientId->getValue());
282
    }
283
284
    /**
285
     * @test
286
     */
287
    public function theClientUsesAnotherAuthenticationMethod()
288
    {
289
        $jws = $this->createInvalidClientAssertionSignedByTheClient();
290
        $assertion = $this->encryptAssertion(
291
            $this->serializeJWS(
292
                $jws
293
            )
294
        );
295
        $method = $this->getMethodWithEncryptionSupport(false);
296
        $manager = new AuthenticationMethodManager();
297
        $manager->add($method);
298
299
        $client = $this->prophesize(Client::class);
300
        $client->isPublic()->willReturn(false);
301
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
302
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
303
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_post');
304
305
        $request = $this->buildRequest([
306
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
307
            'client_assertion' => $assertion,
308
        ]);
309
310
        static::assertFalse($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
311
    }
312
313
    /**
314
     * @test
315
     */
316
    public function theClientWithPrivateKeyIsAuthenticated()
317
    {
318
        $jws = $this->createValidClientAssertionSignedByTheClient();
319
        $assertion = $this->encryptAssertion(
320
            $this->serializeJWS(
321
                $jws
322
            )
323
        );
324
        $method = $this->getMethodWithEncryptionSupport(false);
325
        $manager = new AuthenticationMethodManager();
326
        $manager->add($method);
327
328
        $client = $this->prophesize(Client::class);
329
        $client->isPublic()->willReturn(false);
330
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
331
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
332
        $client->get('token_endpoint_auth_method')->willReturn('private_key_jwt');
333
        $client->getTokenEndpointAuthenticationMethod()->willReturn('private_key_jwt');
334
        $client->has('jwks')->willReturn(true);
335
        $client->get('jwks')->willReturn(json_decode('{"keys":[{"kty":"oct","k":"U0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVU"}]}', true));
336
        $client->areClientCredentialsExpired()->willReturn(false);
337
338
        $request = $this->buildRequest([
339
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
340
            'client_assertion' => $assertion,
341
        ]);
342
343
        static::assertTrue($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
344
    }
345
346
    /**
347
     * @test
348
     */
349
    public function theClientWithClientSecretIsAuthenticated()
350
    {
351
        $jws = $this->createValidClientAssertionSignedByTheClient();
352
        $assertion = $this->encryptAssertion(
353
            $this->serializeJWS(
354
                $jws
355
            )
356
        );
357
        $method = $this->getMethodWithEncryptionSupport(false);
358
        $manager = new AuthenticationMethodManager();
359
        $manager->add($method);
360
361
        $client = $this->prophesize(Client::class);
362
        $client->isPublic()->willReturn(false);
363
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
364
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
365
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_jwt');
366
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt');
367
        $client->has('jwks')->willReturn(false);
368
        $client->has('client_secret')->willReturn(true);
369
        $client->get('client_secret')->willReturn('SECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRETSECRET');
370
        $client->areClientCredentialsExpired()->willReturn(false);
371
372
        $request = $this->buildRequest([
373
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
374
            'client_assertion' => $assertion,
375
        ]);
376
377
        static::assertTrue($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
378
    }
379
380
    /**
381
     * @test
382
     */
383
    public function theClientWithTrustedIssuerAssertionIsAuthenticated()
384
    {
385
        $jws = $this->createValidClientAssertionSignedByATrustedIssuer();
386
        $assertion = $this->serializeJWS(
387
            $jws
388
        );
389
        $method = $this->getMethodWithTrustedIssuerSupport();
390
        $manager = new AuthenticationMethodManager();
391
        $manager->add($method);
392
393
        $client = $this->prophesize(Client::class);
394
        $client->isPublic()->willReturn(false);
395
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
396
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
397
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_jwt');
398
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt');
399
        $client->has('jwks')->willReturn(false);
400
        $client->has('client_secret')->willReturn(false);
401
        $client->areClientCredentialsExpired()->willReturn(false);
402
403
        $request = $this->buildRequest([
404
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
405
            'client_assertion' => $assertion,
406
        ]);
407
408
        static::assertTrue($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
409
    }
410
411
    /**
412
     * @test
413
     */
414
    public function theClientConfigurationCanBeCheckedWithClientSecretJwt()
415
    {
416
        $method = $this->getMethod();
417
        $commandParameters = new DataBag([
418
            'token_endpoint_auth_method' => 'client_secret_jwt',
419
        ]);
420
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
421
422
        static::assertTrue($validatedParameters->has('client_secret'));
423
        static::assertTrue($validatedParameters->has('client_secret_expires_at'));
424
    }
425
426
    /**
427
     * @test
428
     */
429
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreSet()
430
    {
431
        $this->expectException(\InvalidArgumentException::class);
432
        $this->expectExceptionMessage('Either the parameter "jwks" or "jwks_uri" must be set.');
433
        $method = $this->getMethod();
434
        $commandParameters = new DataBag([
435
            'token_endpoint_auth_method' => 'private_key_jwt',
436
            'jwks' => 'foo',
437
            'jwks_uri' => 'bar',
438
        ]);
439
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
440
441
        static::assertTrue($validatedParameters->has('token_endpoint_auth_method'));
442
        static::assertEquals('private_key_jwt', $validatedParameters->get('token_endpoint_auth_method'));
443
    }
444
445
    /**
446
     * @test
447
     */
448
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreNotSetBecauseTrustedIssuerSupportIsDisabled()
449
    {
450
        $this->expectException(\InvalidArgumentException::class);
451
        $this->expectExceptionMessage('Either the parameter "jwks" or "jwks_uri" must be set.');
452
        $method = $this->getMethod();
453
        $commandParameters = new DataBag([
454
            'token_endpoint_auth_method' => 'private_key_jwt',
455
        ]);
456
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
457
458
        static::assertTrue($validatedParameters->has('token_endpoint_auth_method'));
459
        static::assertEquals('private_key_jwt', $validatedParameters->get('token_endpoint_auth_method'));
460
    }
461
462
    /**
463
     * @test
464
     */
465
    public function theClientConfigurationCanBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreNotSetBecauseTrustedIssuerSupportIsEnabled()
466
    {
467
        $method = $this->getMethodWithTrustedIssuerSupport();
468
        $commandParameters = new DataBag([
469
            'token_endpoint_auth_method' => 'private_key_jwt',
470
        ]);
471
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
472
473
        static::assertFalse($validatedParameters->has('jwks'));
474
        static::assertFalse($validatedParameters->has('jwks_uri'));
475
    }
476
477
    /**
478
     * @test
479
     */
480
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfJwksIsNotAValidKeySet()
481
    {
482
        $method = $this->getMethod();
483
        $commandParameters = new DataBag([
484
            'token_endpoint_auth_method' => 'private_key_jwt',
485
            'jwks' => 'foo',
486
        ]);
487
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
488
        static::assertTrue($validatedParameters->has('jwks'));
489
    }
490
491
    /**
492
     * @test
493
     */
494
    public function theClientConfigurationCanBeCheckedWithPrivateKeyJwtIfJwksIsValid()
495
    {
496
        $method = $this->getMethod();
497
        $commandParameters = new DataBag([
498
            'token_endpoint_auth_method' => 'private_key_jwt',
499
            'jwks' => json_decode('{"keys":[{"kty":"oct","k":"U0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVU"}]}', true),
500
        ]);
501
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
502
503
        static::assertTrue($validatedParameters->has('jwks'));
504
        static::assertEquals(json_decode('{"keys":[{"kty":"oct","k":"U0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVU"}]}', true), $validatedParameters->get('jwks'));
505
    }
506
507
    /**
508
     * @test
509
     */
510
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfJwksUriFactoryIsNotAvailable()
511
    {
512
        $method = $this->getMethod();
513
        $commandParameters = new DataBag([
514
            'token_endpoint_auth_method' => 'private_key_jwt',
515
            'jwks_uri' => 'foo',
516
        ]);
517
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
518
519
        static::assertTrue($validatedParameters->has('jwks_uri'));
520
    }
521
522
    private function getMethod(): ClientAssertionJwt
523
    {
524
        if (null === $this->method) {
525
            $this->method = new ClientAssertionJwt(
526
                new JWSVerifier(new AlgorithmManager([new HS256(), new RS256()])),
527
                new HeaderCheckerManager([], [new JWSTokenSupport()]),
528
                new ClaimCheckerManager([]),
529
                3600
530
            );
531
        }
532
533
        return $this->method;
534
    }
535
536
    private function getMethodWithEncryptionSupport(bool $isRequired): ClientAssertionJwt
537
    {
538
        $method = clone $this->getMethod();
539
540
        $method->enableEncryptedAssertions(
541
            new JWELoader(
542
                new JWESerializerManager([new \Jose\Component\Encryption\Serializer\CompactSerializer()]),
543
                new JWEDecrypter(
544
                    new AlgorithmManager([new RSAOAEP256()]),
545
                    new AlgorithmManager([new A256CBCHS512()]),
546
                    new CompressionMethodManager([new Deflate()])
547
                ),
548
                new HeaderCheckerManager([], [new JWETokenSupport()])
549
            ),
550
            new JWKSet([new JWK([
551
                'kty' => 'RSA',
552
                'kid' => '[email protected]',
553
                'use' => 'enc',
554
                'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE',
555
                'e' => 'AQAB',
556
                'alg' => 'RSA-OAEP-256',
557
                'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE',
558
                'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ',
559
                'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q',
560
                'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ',
561
                'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ',
562
                'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA',
563
            ])]),
564
            $isRequired
565
        );
566
567
        return $method;
568
    }
569
570
    private function getMethodWithTrustedIssuerSupport(): ClientAssertionJwt
571
    {
572
        $method = clone $this->getMethod();
573
574
        $trustedIssuer = $this->prophesize(TrustedIssuer::class);
575
        $trustedIssuer->name()->willReturn('TRUSTED_ISSUER');
576
        $trustedIssuer->getAllowedAssertionTypes()->willReturn(['urn:ietf:params:oauth:client-assertion-type:jwt-bearer']);
577
        $trustedIssuer->getAllowedSignatureAlgorithms()->willReturn(['RS256']);
578
        $trustedIssuer->getJWKSet()->willReturn(new JWKSet([new JWK([
579
            'kty' => 'RSA',
580
            'n' => '33WRDEG5rN7daMgI2N5H8cPwTeQPOnz34uG2fe0yKyHjJDGE2XoESRpu5LelSPdYM_r4AWMFWoDWPd-7xaq7uFEkM8c6zaQIgj4uEiq-pBMvH-e805SFbYOKYqfQe4eeXAk4OrQwcUkSrlGskf6YUaw_3IwbPgzEDTgTZFVtQlE',
581
            'e' => 'AQAB',
582
            'alg' => 'RS256',
583
            'use' => 'sig',
584
        ])]));
585
586
        $trustedIssuerRepository = $this->prophesize(TrustedIssuerRepository::class);
587
        $trustedIssuerRepository->find('TRUSTED_ISSUER')->willReturn($trustedIssuer->reveal());
588
589
        $method->enableTrustedIssuerSupport($trustedIssuerRepository->reveal());
590
591
        return $method;
592
    }
593
594
    private function serializeJWS(JWS $jws): string
595
    {
596
        $serializer = new CompactSerializer();
597
598
        return $serializer->serialize($jws, 0);
599
    }
600
601
    private function createValidClientAssertionSignedByTheClient(): JWS
602
    {
603
        $jwsBuilder = new JWSBuilder(
604
            new AlgorithmManager([
605
                new HS256(),
606
            ])
607
        );
608
609
        return $jwsBuilder
610
            ->create()
611
            ->withPayload(JsonConverter::encode([
612
                'iss' => 'ClientId',
613
                'sub' => 'ClientId',
614
                'aud' => 'My Server',
615
                'exp' => time() + 3600,
616
            ]))
617
            ->addSignature(
618
                JWK::createFromJson('{"kty":"oct","k":"U0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVU"}'),
619
                ['alg' => 'HS256']
620
            )
621
            ->build()
622
        ;
623
    }
624
625
    private function createValidClientAssertionSignedByATrustedIssuer(): JWS
626
    {
627
        $jwsBuilder = new JWSBuilder(
628
            new AlgorithmManager([
629
                new RS256(),
630
            ])
631
        );
632
633
        return $jwsBuilder
634
            ->create()
635
            ->withPayload(JsonConverter::encode([
636
                'iss' => 'TRUSTED_ISSUER',
637
                'sub' => 'ClientId',
638
                'aud' => 'My Server',
639
                'exp' => time() + 3600,
640
            ]))
641
            ->addSignature(
642
                new JWK([
643
                    'kty' => 'RSA',
644
                    'n' => '33WRDEG5rN7daMgI2N5H8cPwTeQPOnz34uG2fe0yKyHjJDGE2XoESRpu5LelSPdYM_r4AWMFWoDWPd-7xaq7uFEkM8c6zaQIgj4uEiq-pBMvH-e805SFbYOKYqfQe4eeXAk4OrQwcUkSrlGskf6YUaw_3IwbPgzEDTgTZFVtQlE',
645
                    'e' => 'AQAB',
646
                    'p' => '9Vovb8pySyOZUoTrNMD6JmTsDa12u9y4_HImQuKD0rerVo2y5y7D_r00i1MhGHkBrI3W2PsubIiZgKp1f0oQfQ',
647
                    'd' => 'jrDrO3Fo2GvD5Jn_lER0mnxtIb_kvYt5WyaYutbRN1u_SKhaVeklfWzkrSZb5DkV2LOE1JXfoEgvBnms1O9OSJXwqDrFF7NDebw95g6JzI-SbkIHw0Cb-_E9K92FjvW3Bi8j9PKIa8c_dpwIAIirc_q8uhSTf4WoIOHSFbSaQPE',
648
                    'q' => '6Sgna9gQw4dXN0jBSjOZSjl4S2_H3wHatclrvlYfbJVU6GlIlqWGaUkdFvCuEr9iXJAY4zpEQ4P370EZtsyVZQ',
649
                    'dp' => '5m79fpE1Jz0YE1ijT7ivOMAws-fnTCnR08eiB8-W36GBWplbHaXejrJFV1WMD-AWomnVD5VZ1LW29hEiqZp2QQ',
650
                    'dq' => 'JV2pC7CB50QeZx7C02h3jZyuObC9YHEEoxOXr9ZPjPBVvjV5S6NVajQsdEu4Kgr_8YOqaWgiHovcxTwyqcgZvQ',
651
                    'qi' => 'VZykPj-ugKQxuWTSE-hA-nJqkl7FzjfzHte4QYUSHLHFq6oLlHhgUoJ_4oFLaBmCvgZLAFRDDD6pnd5Fgzt9ow',
652
                ]),
653
                ['alg' => 'RS256']
654
            )
655
            ->build()
656
        ;
657
    }
658
659
    private function createInvalidClientAssertionSignedByTheClient(): JWS
660
    {
661
        $jwsBuilder = new JWSBuilder(
662
            new AlgorithmManager([
663
                new HS256(),
664
            ])
665
        );
666
667
        return $jwsBuilder
668
            ->create()
669
            ->withPayload(JsonConverter::encode([]))
670
            ->addSignature(
671
                JWK::createFromJson('{"kty":"oct","k":"U0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVUU0VDUkVU"}'),
672
                ['alg' => 'HS256']
673
            )
674
            ->build()
675
        ;
676
    }
677
678
    private function createInvalidClientAssertionSignedByATrustedIssuer(): JWS
0 ignored issues
show
Unused Code introduced by
The method createInvalidClientAsser...ignedByATrustedIssuer() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
679
    {
680
        $jwsBuilder = new JWSBuilder(
681
            new AlgorithmManager([
682
                new RS256(),
683
            ])
684
        );
685
686
        return $jwsBuilder
687
            ->create()
688
            ->withPayload(JsonConverter::encode([
689
            ]))
690
            ->addSignature(
691
                new JWK([
692
                    'kty' => 'RSA',
693
                    'n' => '33WRDEG5rN7daMgI2N5H8cPwTeQPOnz34uG2fe0yKyHjJDGE2XoESRpu5LelSPdYM_r4AWMFWoDWPd-7xaq7uFEkM8c6zaQIgj4uEiq-pBMvH-e805SFbYOKYqfQe4eeXAk4OrQwcUkSrlGskf6YUaw_3IwbPgzEDTgTZFVtQlE',
694
                    'e' => 'AQAB',
695
                    'p' => '9Vovb8pySyOZUoTrNMD6JmTsDa12u9y4_HImQuKD0rerVo2y5y7D_r00i1MhGHkBrI3W2PsubIiZgKp1f0oQfQ',
696
                    'd' => 'jrDrO3Fo2GvD5Jn_lER0mnxtIb_kvYt5WyaYutbRN1u_SKhaVeklfWzkrSZb5DkV2LOE1JXfoEgvBnms1O9OSJXwqDrFF7NDebw95g6JzI-SbkIHw0Cb-_E9K92FjvW3Bi8j9PKIa8c_dpwIAIirc_q8uhSTf4WoIOHSFbSaQPE',
697
                    'q' => '6Sgna9gQw4dXN0jBSjOZSjl4S2_H3wHatclrvlYfbJVU6GlIlqWGaUkdFvCuEr9iXJAY4zpEQ4P370EZtsyVZQ',
698
                    'dp' => '5m79fpE1Jz0YE1ijT7ivOMAws-fnTCnR08eiB8-W36GBWplbHaXejrJFV1WMD-AWomnVD5VZ1LW29hEiqZp2QQ',
699
                    'dq' => 'JV2pC7CB50QeZx7C02h3jZyuObC9YHEEoxOXr9ZPjPBVvjV5S6NVajQsdEu4Kgr_8YOqaWgiHovcxTwyqcgZvQ',
700
                    'qi' => 'VZykPj-ugKQxuWTSE-hA-nJqkl7FzjfzHte4QYUSHLHFq6oLlHhgUoJ_4oFLaBmCvgZLAFRDDD6pnd5Fgzt9ow',
701
                ]),
702
                ['alg' => 'RS256']
703
            )
704
            ->build()
705
        ;
706
    }
707
708
    private function encryptAssertion(string $assertion): string
709
    {
710
        $jweBuilder = new JWEBuilder(
711
            new AlgorithmManager([new RSAOAEP256()]),
712
            new AlgorithmManager([new A256CBCHS512()]),
713
            new CompressionMethodManager([new Deflate()])
714
        );
715
        $jwe = $jweBuilder->create()
716
            ->withPayload($assertion)
717
            ->withSharedProtectedHeader(['alg' => 'RSA-OAEP-256', 'enc' => 'A256CBC-HS512'])
718
            ->addRecipient(new JWK([
719
                'kty' => 'RSA',
720
                'kid' => '[email protected]',
721
                'use' => 'enc',
722
                'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE',
723
                'e' => 'AQAB',
724
                'alg' => 'RSA-OAEP-256',
725
            ]))
726
            ->build()
727
        ;
728
729
        $serializer = new \Jose\Component\Encryption\Serializer\CompactSerializer();
730
731
        return $serializer->serialize($jwe, 0);
732
    }
733
734
    private function buildRequest(array $data): ObjectProphecy
735
    {
736
        $body = $this->prophesize(StreamInterface::class);
737
        $body->getContents()->willReturn(http_build_query($data));
738
        $request = $this->prophesize(ServerRequestInterface::class);
739
        $request->hasHeader('Content-Type')->willReturn(true);
740
        $request->getHeader('Content-Type')->willReturn(['application/x-www-form-urlencoded']);
741
        $request->getBody()->willReturn($body->reveal());
742
        $request->getParsedBody()->willReturn([]);
743
744
        return $request;
745
    }
746
}
747