getMethodWithTrustedIssuerSupport()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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