Failed Conditions
Push — master ( b5a0b4...819484 )
by Florent
08:00
created

theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreNotSetBecauseTrustedIssuer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 10
rs 10
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-2018 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 Http\Message\MessageFactory\DiactorosMessageFactory;
17
use Jose\Component\Checker\ClaimCheckerManager;
18
use Jose\Component\Checker\HeaderCheckerManager;
19
use Jose\Component\Core\AlgorithmManager;
20
use Jose\Component\Core\Converter\StandardConverter;
21
use Jose\Component\Core\JWK;
22
use Jose\Component\Core\JWKSet;
23
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
24
use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256;
25
use Jose\Component\Encryption\Compression\CompressionMethodManager;
26
use Jose\Component\Encryption\Compression\Deflate;
27
use Jose\Component\Encryption\JWEBuilder;
28
use Jose\Component\Encryption\JWEDecrypter;
29
use Jose\Component\Encryption\JWELoader;
30
use Jose\Component\Encryption\JWETokenSupport;
31
use Jose\Component\Encryption\Serializer\JWESerializerManager;
32
use Jose\Component\KeyManagement\JKUFactory;
33
use Jose\Component\Signature\Algorithm\HS256;
34
use Jose\Component\Signature\Algorithm\RS256;
35
use Jose\Component\Signature\JWS;
36
use Jose\Component\Signature\JWSBuilder;
37
use Jose\Component\Signature\JWSTokenSupport;
38
use Jose\Component\Signature\JWSVerifier;
39
use Jose\Component\Signature\Serializer\CompactSerializer;
40
use OAuth2Framework\Component\ClientAuthentication\AuthenticationMethodManager;
41
use OAuth2Framework\Component\ClientAuthentication\ClientAssertionJwt;
42
use OAuth2Framework\Component\Core\Client\Client;
43
use OAuth2Framework\Component\Core\Client\ClientId;
44
use OAuth2Framework\Component\Core\DataBag\DataBag;
45
use OAuth2Framework\Component\Core\Message\OAuth2Error;
46
use OAuth2Framework\Component\Core\TrustedIssuer\TrustedIssuer;
47
use OAuth2Framework\Component\Core\TrustedIssuer\TrustedIssuerRepository;
48
use PHPUnit\Framework\TestCase;
49
use Prophecy\Prophecy\ObjectProphecy;
50
use Psr\Http\Message\ServerRequestInterface;
51
use Psr\Http\Message\StreamInterface;
52
53
/**
54
 * @group TokenEndpoint
55
 * @group ClientAuthentication
56
 */
57
final class ClientAssertionJwtAuthenticationMethodTest extends TestCase
58
{
59
    /**
60
     * @test
61
     */
62
    public function genericCalls()
63
    {
64
        $method = $this->getMethod();
65
66
        static::assertEquals([], $method->getSchemesParameters());
67
        static::assertEquals(['client_secret_jwt', 'private_key_jwt'], $method->getSupportedMethods());
68
        static::assertEquals(['HS256', 'RS256'], $method->getSupportedSignatureAlgorithms());
69
        static::assertEquals([], $method->getSupportedKeyEncryptionAlgorithms());
70
        static::assertEquals([], $method->getSupportedContentEncryptionAlgorithms());
71
    }
72
73
    /**
74
     * @test
75
     */
76
    public function genericCallsWithEncryptionSupport()
77
    {
78
        $method = $this->getMethodWithEncryptionSupport(false);
79
80
        static::assertEquals([], $method->getSchemesParameters());
81
        static::assertEquals(['client_secret_jwt', 'private_key_jwt'], $method->getSupportedMethods());
82
        static::assertEquals(['HS256', 'RS256'], $method->getSupportedSignatureAlgorithms());
83
        static::assertEquals(['RSA-OAEP-256'], $method->getSupportedKeyEncryptionAlgorithms());
84
        static::assertEquals(['A256CBC-HS512'], $method->getSupportedContentEncryptionAlgorithms());
85
    }
86
87
    /**
88
     * @test
89
     */
90
    public function theClientIdCannotBeFoundInTheRequest()
91
    {
92
        $method = $this->getMethod();
93
        $request = $this->buildRequest([]);
94
        $request->getParsedBody()->willReturn([]);
95
        $request->getHeader('Authorization')->willReturn([]);
96
97
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
98
        static::assertNull($clientId);
99
        static::assertNull($credentials);
100
    }
101
102
    /**
103
     * @test
104
     */
105
    public function theClientAssertionTypeIsNotSupported()
106
    {
107
        $method = $this->getMethod();
108
        $request = $this->buildRequest([
109
            'client_assertion_type' => 'foo',
110
        ]);
111
112
        $request->getHeader('Authorization')->willReturn([]);
113
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
114
        static::assertNull($clientId);
115
        static::assertNull($credentials);
116
    }
117
118
    /**
119
     * @test
120
     */
121
    public function theClientAssertionIsMissing()
122
    {
123
        $method = $this->getMethod();
124
        $request = $this->buildRequest([
125
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
126
        ]);
127
128
        $request->getHeader('Authorization')->willReturn([]);
129
130
        try {
131
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
132
            static::fail('An OAuth2 exception should be thrown.');
133
        } catch (OAuth2Error $e) {
134
            static::assertEquals('invalid_request', $e->getMessage());
135
            static::assertEquals('Parameter "client_assertion" is missing.', $e->getErrorDescription());
136
        }
137
    }
138
139
    /**
140
     * @test
141
     */
142
    public function theClientAssertionIsInvalid()
143
    {
144
        $method = $this->getMethod();
145
        $request = $this->buildRequest([
146
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
147
            'client_assertion' => 'foo',
148
        ]);
149
150
        $request->getHeader('Authorization')->willReturn([]);
151
152
        try {
153
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
154
            static::fail('An OAuth2 exception should be thrown.');
155
        } catch (OAuth2Error $e) {
156
            static::assertEquals('invalid_request', $e->getMessage());
157
            static::assertEquals('Unable to load, decrypt or verify the client assertion.', $e->getErrorDescription());
158
        }
159
    }
160
161
    /**
162
     * @test
163
     */
164
    public function theClientAssertionSignedByTheClientIsInvalidBecauseOfMissingClaims()
165
    {
166
        $assertion = $this->serializeJWS(
167
            $this->createInvalidClientAssertionSignedByTheClient()
168
        );
169
        $method = $this->getMethod();
170
        $request = $this->buildRequest([
171
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
172
            'client_assertion' => $assertion,
173
        ]);
174
175
        $request->getHeader('Authorization')->willReturn([]);
176
177
        try {
178
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
179
            static::fail('An OAuth2 exception should be thrown.');
180
        } catch (OAuth2Error $e) {
181
            static::assertEquals('invalid_request', $e->getMessage());
182
            static::assertEquals('The following claim(s) is/are mandatory: "iss, sub, aud, exp".', $e->getErrorDescription());
183
        }
184
    }
185
186
    /**
187
     * @test
188
     */
189
    public function theClientAssertionSignedByTheClientIsRejectedBecauseEncryptionIsMandatory()
190
    {
191
        $assertion = $this->serializeJWS(
192
            $this->createInvalidClientAssertionSignedByTheClient()
193
        );
194
        $method = $this->getMethodWithEncryptionSupport(true);
195
        $request = $this->buildRequest([
196
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
197
            'client_assertion' => $assertion,
198
        ]);
199
200
        $request->getHeader('Authorization')->willReturn([]);
201
202
        try {
203
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
204
            static::fail('An OAuth2 exception should be thrown.');
205
        } catch (OAuth2Error $e) {
206
            static::assertEquals('invalid_request', $e->getMessage());
207
            static::assertEquals('The encryption of the assertion is mandatory but the decryption of the assertion failed.', $e->getErrorDescription());
208
        }
209
    }
210
211
    /**
212
     * @test
213
     */
214
    public function theEncryptedClientAssertionSignedAndEncryptedByTheClientIsInvalidBecauseOfMissingClaims()
215
    {
216
        $assertion = $this->encryptAssertion(
217
            $this->serializeJWS(
218
                $this->createInvalidClientAssertionSignedByTheClient()
219
            )
220
        );
221
        $method = $this->getMethodWithEncryptionSupport(false);
222
        $request = $this->buildRequest([
223
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
224
            'client_assertion' => $assertion,
225
        ]);
226
227
        $request->getHeader('Authorization')->willReturn([]);
228
229
        try {
230
            $method->findClientIdAndCredentials($request->reveal(), $credentials);
231
            static::fail('An OAuth2 exception should be thrown.');
232
        } catch (OAuth2Error $e) {
233
            static::assertEquals('invalid_request', $e->getMessage());
234
            static::assertEquals('The following claim(s) is/are mandatory: "iss, sub, aud, exp".', $e->getErrorDescription());
235
        }
236
    }
237
238
    /**
239
     * @test
240
     */
241
    public function theClientAssertionIsValidAndTheClientIdIsRetrieved()
242
    {
243
        $assertion = $this->serializeJWS(
244
            $this->createValidClientAssertionSignedByTheClient()
245
        );
246
        $method = $this->getMethod();
247
        $request = $this->buildRequest([
248
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
249
            'client_assertion' => $assertion,
250
        ]);
251
252
        $request->getHeader('Authorization')->willReturn([]);
253
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
254
        static::assertEquals('ClientId', $clientId->getValue());
255
    }
256
257
    /**
258
     * @test
259
     */
260
    public function theEncryptedClientAssertionIsValidAndTheClientIdIsRetrieved()
261
    {
262
        $assertion = $this->encryptAssertion(
263
            $this->serializeJWS(
264
                $this->createValidClientAssertionSignedByTheClient()
265
            )
266
        );
267
        $method = $this->getMethodWithEncryptionSupport(false);
268
        $request = $this->buildRequest([
269
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
270
            'client_assertion' => $assertion,
271
        ]);
272
        $request->getHeader('Authorization')->willReturn([]);
273
274
        $clientId = $method->findClientIdAndCredentials($request->reveal(), $credentials);
275
        static::assertEquals('ClientId', $clientId->getValue());
276
    }
277
278
    /**
279
     * @test
280
     */
281
    public function theClientUsesAnotherAuthenticationMethod()
282
    {
283
        $jws = $this->createInvalidClientAssertionSignedByTheClient();
284
        $assertion = $this->encryptAssertion(
285
            $this->serializeJWS(
286
                $jws
287
            )
288
        );
289
        $method = $this->getMethodWithEncryptionSupport(false);
290
        $manager = new AuthenticationMethodManager();
291
        $manager->add($method);
292
293
        $client = $this->prophesize(Client::class);
294
        $client->isPublic()->willReturn(false);
295
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
296
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
297
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_post');
298
299
        $request = $this->buildRequest([
300
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
301
            'client_assertion' => $assertion,
302
        ]);
303
304
        static::assertFalse($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
305
    }
306
307
    /**
308
     * @test
309
     */
310
    public function theClientWithPrivateKeyIsAuthenticated()
311
    {
312
        $jws = $this->createValidClientAssertionSignedByTheClient();
313
        $assertion = $this->encryptAssertion(
314
            $this->serializeJWS(
315
                $jws
316
            )
317
        );
318
        $method = $this->getMethodWithEncryptionSupport(false);
319
        $manager = new AuthenticationMethodManager();
320
        $manager->add($method);
321
322
        $client = $this->prophesize(Client::class);
323
        $client->isPublic()->willReturn(false);
324
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
325
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
326
        $client->get('token_endpoint_auth_method')->willReturn('private_key_jwt');
327
        $client->getTokenEndpointAuthenticationMethod()->willReturn('private_key_jwt');
328
        $client->has('jwks')->willReturn(true);
329
        $client->get('jwks')->willReturn(\Safe\json_decode('{"keys":[{"kty":"oct","k":"U0VDUkVU"}]}', true));
330
        $client->areClientCredentialsExpired()->willReturn(false);
331
332
        $request = $this->buildRequest([
333
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
334
            'client_assertion' => $assertion,
335
        ]);
336
337
        static::assertTrue($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
338
    }
339
340
    /**
341
     * @test
342
     */
343
    public function theClientWithClientSecretIsAuthenticated()
344
    {
345
        $jws = $this->createValidClientAssertionSignedByTheClient();
346
        $assertion = $this->encryptAssertion(
347
            $this->serializeJWS(
348
                $jws
349
            )
350
        );
351
        $method = $this->getMethodWithEncryptionSupport(false);
352
        $manager = new AuthenticationMethodManager();
353
        $manager->add($method);
354
355
        $client = $this->prophesize(Client::class);
356
        $client->isPublic()->willReturn(false);
357
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
358
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
359
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_jwt');
360
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt');
361
        $client->has('jwks')->willReturn(false);
362
        $client->has('client_secret')->willReturn(true);
363
        $client->get('client_secret')->willReturn('SECRET');
364
        $client->areClientCredentialsExpired()->willReturn(false);
365
366
        $request = $this->buildRequest([
367
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
368
            'client_assertion' => $assertion,
369
        ]);
370
371
        static::assertTrue($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
372
    }
373
374
    /**
375
     * @test
376
     */
377
    public function theClientWithTrustedIssuerAssertionIsAuthenticated()
378
    {
379
        $jws = $this->createValidClientAssertionSignedByATrustedIssuer();
380
        $assertion = $this->serializeJWS(
381
            $jws
382
        );
383
        $method = $this->getMethodWithTrustedIssuerSupport();
384
        $manager = new AuthenticationMethodManager();
385
        $manager->add($method);
386
387
        $client = $this->prophesize(Client::class);
388
        $client->isPublic()->willReturn(false);
389
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
390
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
391
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_jwt');
392
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt');
393
        $client->has('jwks')->willReturn(false);
394
        $client->has('client_secret')->willReturn(false);
395
        $client->areClientCredentialsExpired()->willReturn(false);
396
397
        $request = $this->buildRequest([
398
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
399
            'client_assertion' => $assertion,
400
        ]);
401
402
        static::assertTrue($manager->isClientAuthenticated($request->reveal(), $client->reveal(), $method, $jws));
403
    }
404
405
    /**
406
     * @test
407
     */
408
    public function theClientConfigurationCanBeCheckedWithClientSecretJwt()
409
    {
410
        $method = $this->getMethod();
411
        $commandParameters = new DataBag([
412
            'token_endpoint_auth_method' => 'client_secret_jwt',
413
        ]);
414
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
415
416
        static::assertTrue($validatedParameters->has('client_secret'));
417
        static::assertTrue($validatedParameters->has('client_secret_expires_at'));
418
    }
419
420
    /**
421
     * @test
422
     * @expectedException \InvalidArgumentException
423
     * @expectedExceptionMessage Either the parameter "jwks" or "jwks_uri" must be set.
424
     */
425
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreSet()
426
    {
427
        $method = $this->getMethod();
428
        $commandParameters = new DataBag([
429
            'token_endpoint_auth_method' => 'private_key_jwt',
430
            'jwks' => 'foo',
431
            'jwks_uri' => 'bar',
432
        ]);
433
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
434
435
        static::assertTrue($validatedParameters->has('token_endpoint_auth_method'));
436
        static::assertEquals('private_key_jwt', $validatedParameters->get('token_endpoint_auth_method'));
437
    }
438
439
    /**
440
     * @test
441
     * @expectedException \InvalidArgumentException
442
     * @expectedExceptionMessage Either the parameter "jwks" or "jwks_uri" must be set.
443
     */
444
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreNotSetBecauseTrustedIssuerSupportIsDisabled()
445
    {
446
        $method = $this->getMethod();
447
        $commandParameters = new DataBag([
448
            'token_endpoint_auth_method' => 'private_key_jwt',
449
        ]);
450
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
451
452
        static::assertTrue($validatedParameters->has('token_endpoint_auth_method'));
453
        static::assertEquals('private_key_jwt', $validatedParameters->get('token_endpoint_auth_method'));
454
    }
455
456
    /**
457
     * @test
458
     */
459
    public function theClientConfigurationCanBeCheckedWithPrivateKeyJwtIfBothJwksAndJwksUriAreNotSetBecauseTrustedIssuerSupportIsEnabled()
460
    {
461
        $method = $this->getMethodWithTrustedIssuerSupport();
462
        $commandParameters = new DataBag([
463
            'token_endpoint_auth_method' => 'private_key_jwt',
464
        ]);
465
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
466
467
        static::assertFalse($validatedParameters->has('jwks'));
468
        static::assertFalse($validatedParameters->has('jwks_uri'));
469
    }
470
471
    /**
472
     * @test
473
     */
474
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfJwksIsNotAValidKeySet()
475
    {
476
        $method = $this->getMethod();
477
        $commandParameters = new DataBag([
478
            'token_endpoint_auth_method' => 'private_key_jwt',
479
            'jwks' => 'foo',
480
        ]);
481
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
482
        static::assertTrue($validatedParameters->has('jwks'));
483
    }
484
485
    /**
486
     * @test
487
     */
488
    public function theClientConfigurationCanBeCheckedWithPrivateKeyJwtIfJwksIsValid()
489
    {
490
        $method = $this->getMethod();
491
        $commandParameters = new DataBag([
492
            'token_endpoint_auth_method' => 'private_key_jwt',
493
            'jwks' => \Safe\json_decode('{"keys":[{"kty":"oct","k":"U0VDUkVU"}]}', true),
494
        ]);
495
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
496
497
        static::assertTrue($validatedParameters->has('jwks'));
498
        static::assertEquals(\Safe\json_decode('{"keys":[{"kty":"oct","k":"U0VDUkVU"}]}', true), $validatedParameters->get('jwks'));
499
    }
500
501
    /**
502
     * @test
503
     */
504
    public function theClientConfigurationCannotBeCheckedWithPrivateKeyJwtIfJwksUriFactoryIsNotAvailable()
505
    {
506
        $method = $this->getMethod();
507
        $commandParameters = new DataBag([
508
            'token_endpoint_auth_method' => 'private_key_jwt',
509
            'jwks_uri' => 'foo',
510
        ]);
511
        $validatedParameters = $method->checkClientConfiguration($commandParameters, new DataBag([]));
512
513
        static::assertTrue($validatedParameters->has('jwks_uri'));
514
    }
515
516
    /**
517
     * @var ClientAssertionJwt|null
518
     */
519
    private $method = null;
520
521
    private function getMethod(): ClientAssertionJwt
522
    {
523
        if (null === $this->method) {
524
            $this->method = new ClientAssertionJwt(
525
                new StandardConverter(),
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

525
                /** @scrutinizer ignore-deprecated */ new StandardConverter(),
Loading history...
526
                new JWSVerifier(AlgorithmManager::create([new HS256(), new RS256()])),
527
                HeaderCheckerManager::create([], [new JWSTokenSupport()]),
528
                ClaimCheckerManager::create([]),
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
                JWESerializerManager::create([new \Jose\Component\Encryption\Serializer\CompactSerializer(new StandardConverter())]),
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

542
                JWESerializerManager::create([new \Jose\Component\Encryption\Serializer\CompactSerializer(/** @scrutinizer ignore-deprecated */ new StandardConverter())]),
Loading history...
543
                new JWEDecrypter(
544
                    AlgorithmManager::create([new RSAOAEP256()]),
545
                    AlgorithmManager::create([new A256CBCHS512()]),
546
                    CompressionMethodManager::create([new Deflate()])
547
                ),
548
                HeaderCheckerManager::create([], [new JWETokenSupport()])
549
            ),
550
            JWKSet::createFromKeys([JWK::create([
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(JWKSet::createFromKeys([JWK::create([
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 getJkuFactory(\Http\Mock\Client $client): JKUFactory
0 ignored issues
show
Unused Code introduced by
The method getJkuFactory() 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...
595
    {
596
        return new JKUFactory(
597
            new StandardConverter(),
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

597
            /** @scrutinizer ignore-deprecated */ new StandardConverter(),
Loading history...
598
            $client,
599
            new DiactorosMessageFactory()
600
        );
601
    }
602
603
    private function getHttpClient(): \Http\Mock\Client
0 ignored issues
show
Unused Code introduced by
The method getHttpClient() 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...
604
    {
605
        return new \Http\Mock\Client(
606
            new DiactorosMessageFactory()
607
        );
608
    }
609
610
    private function serializeJWS(JWS $jws): string
611
    {
612
        $jsonConverter = new StandardConverter();
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

612
        $jsonConverter = /** @scrutinizer ignore-deprecated */ new StandardConverter();
Loading history...
613
        $serializer = new CompactSerializer($jsonConverter);
614
615
        return $serializer->serialize($jws, 0);
616
    }
617
618
    private function createValidClientAssertionSignedByTheClient(): JWS
619
    {
620
        $jsonConverter = new StandardConverter();
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

620
        $jsonConverter = /** @scrutinizer ignore-deprecated */ new StandardConverter();
Loading history...
621
        $jwsBuilder = new JWSBuilder(
622
            $jsonConverter,
623
            AlgorithmManager::create([
624
                new HS256(),
625
            ])
626
        );
627
628
        return $jwsBuilder
629
            ->create()
630
            ->withPayload($jsonConverter->encode([
631
                'iss' => 'ClientId',
632
                'sub' => 'ClientId',
633
                'aud' => 'My Server',
634
                'exp' => \time() + 3600,
635
            ]))
636
            ->addSignature(
637
                JWK::createFromJson('{"kty":"oct","k":"U0VDUkVU"}'),
638
                ['alg' => 'HS256']
639
            )
640
            ->build();
641
    }
642
643
    private function createValidClientAssertionSignedByATrustedIssuer(): JWS
644
    {
645
        $jsonConverter = new StandardConverter();
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

645
        $jsonConverter = /** @scrutinizer ignore-deprecated */ new StandardConverter();
Loading history...
646
        $jwsBuilder = new JWSBuilder(
647
            $jsonConverter,
648
            AlgorithmManager::create([
649
                new RS256(),
650
            ])
651
        );
652
653
        return $jwsBuilder
654
            ->create()
655
            ->withPayload($jsonConverter->encode([
656
                'iss' => 'TRUSTED_ISSUER',
657
                'sub' => 'ClientId',
658
                'aud' => 'My Server',
659
                'exp' => \time() + 3600,
660
            ]))
661
            ->addSignature(
662
                JWK::create([
663
                    'kty' => 'RSA',
664
                    'n' => '33WRDEG5rN7daMgI2N5H8cPwTeQPOnz34uG2fe0yKyHjJDGE2XoESRpu5LelSPdYM_r4AWMFWoDWPd-7xaq7uFEkM8c6zaQIgj4uEiq-pBMvH-e805SFbYOKYqfQe4eeXAk4OrQwcUkSrlGskf6YUaw_3IwbPgzEDTgTZFVtQlE',
665
                    'e' => 'AQAB',
666
                    'p' => '9Vovb8pySyOZUoTrNMD6JmTsDa12u9y4_HImQuKD0rerVo2y5y7D_r00i1MhGHkBrI3W2PsubIiZgKp1f0oQfQ',
667
                    'd' => 'jrDrO3Fo2GvD5Jn_lER0mnxtIb_kvYt5WyaYutbRN1u_SKhaVeklfWzkrSZb5DkV2LOE1JXfoEgvBnms1O9OSJXwqDrFF7NDebw95g6JzI-SbkIHw0Cb-_E9K92FjvW3Bi8j9PKIa8c_dpwIAIirc_q8uhSTf4WoIOHSFbSaQPE',
668
                    'q' => '6Sgna9gQw4dXN0jBSjOZSjl4S2_H3wHatclrvlYfbJVU6GlIlqWGaUkdFvCuEr9iXJAY4zpEQ4P370EZtsyVZQ',
669
                    'dp' => '5m79fpE1Jz0YE1ijT7ivOMAws-fnTCnR08eiB8-W36GBWplbHaXejrJFV1WMD-AWomnVD5VZ1LW29hEiqZp2QQ',
670
                    'dq' => 'JV2pC7CB50QeZx7C02h3jZyuObC9YHEEoxOXr9ZPjPBVvjV5S6NVajQsdEu4Kgr_8YOqaWgiHovcxTwyqcgZvQ',
671
                    'qi' => 'VZykPj-ugKQxuWTSE-hA-nJqkl7FzjfzHte4QYUSHLHFq6oLlHhgUoJ_4oFLaBmCvgZLAFRDDD6pnd5Fgzt9ow',
672
                ]),
673
                ['alg' => 'RS256']
674
            )
675
            ->build();
676
    }
677
678
    private function createInvalidClientAssertionSignedByTheClient(): JWS
679
    {
680
        $jsonConverter = new StandardConverter();
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

680
        $jsonConverter = /** @scrutinizer ignore-deprecated */ new StandardConverter();
Loading history...
681
        $jwsBuilder = new JWSBuilder(
682
            $jsonConverter,
683
            AlgorithmManager::create([
684
                new HS256(),
685
            ])
686
        );
687
688
        return $jwsBuilder
689
            ->create()
690
            ->withPayload($jsonConverter->encode([]))
691
            ->addSignature(
692
                JWK::createFromJson('{"kty":"oct","k":"U0VDUkVU"}'),
693
                ['alg' => 'HS256']
694
            )
695
            ->build();
696
    }
697
698
    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...
699
    {
700
        $jsonConverter = new StandardConverter();
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

700
        $jsonConverter = /** @scrutinizer ignore-deprecated */ new StandardConverter();
Loading history...
701
        $jwsBuilder = new JWSBuilder(
702
            $jsonConverter,
703
            AlgorithmManager::create([
704
                new RS256(),
705
            ])
706
        );
707
708
        return $jwsBuilder
709
            ->create()
710
            ->withPayload($jsonConverter->encode([
711
            ]))
712
            ->addSignature(
713
                JWK::create([
714
                    'kty' => 'RSA',
715
                    'n' => '33WRDEG5rN7daMgI2N5H8cPwTeQPOnz34uG2fe0yKyHjJDGE2XoESRpu5LelSPdYM_r4AWMFWoDWPd-7xaq7uFEkM8c6zaQIgj4uEiq-pBMvH-e805SFbYOKYqfQe4eeXAk4OrQwcUkSrlGskf6YUaw_3IwbPgzEDTgTZFVtQlE',
716
                    'e' => 'AQAB',
717
                    'p' => '9Vovb8pySyOZUoTrNMD6JmTsDa12u9y4_HImQuKD0rerVo2y5y7D_r00i1MhGHkBrI3W2PsubIiZgKp1f0oQfQ',
718
                    'd' => 'jrDrO3Fo2GvD5Jn_lER0mnxtIb_kvYt5WyaYutbRN1u_SKhaVeklfWzkrSZb5DkV2LOE1JXfoEgvBnms1O9OSJXwqDrFF7NDebw95g6JzI-SbkIHw0Cb-_E9K92FjvW3Bi8j9PKIa8c_dpwIAIirc_q8uhSTf4WoIOHSFbSaQPE',
719
                    'q' => '6Sgna9gQw4dXN0jBSjOZSjl4S2_H3wHatclrvlYfbJVU6GlIlqWGaUkdFvCuEr9iXJAY4zpEQ4P370EZtsyVZQ',
720
                    'dp' => '5m79fpE1Jz0YE1ijT7ivOMAws-fnTCnR08eiB8-W36GBWplbHaXejrJFV1WMD-AWomnVD5VZ1LW29hEiqZp2QQ',
721
                    'dq' => 'JV2pC7CB50QeZx7C02h3jZyuObC9YHEEoxOXr9ZPjPBVvjV5S6NVajQsdEu4Kgr_8YOqaWgiHovcxTwyqcgZvQ',
722
                    'qi' => 'VZykPj-ugKQxuWTSE-hA-nJqkl7FzjfzHte4QYUSHLHFq6oLlHhgUoJ_4oFLaBmCvgZLAFRDDD6pnd5Fgzt9ow',
723
                ]),
724
                ['alg' => 'RS256']
725
            )
726
            ->build();
727
    }
728
729
    private function encryptAssertion(string $assertion): string
730
    {
731
        $jsonConverter = new StandardConverter();
0 ignored issues
show
Deprecated Code introduced by
The class Jose\Component\Core\Converter\StandardConverter has been deprecated: This class is deprecated in v1.3 and will be removed in v2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

731
        $jsonConverter = /** @scrutinizer ignore-deprecated */ new StandardConverter();
Loading history...
732
        $jweBuilder = new JWEBuilder(
733
            $jsonConverter,
734
            AlgorithmManager::create([new RSAOAEP256()]),
735
            AlgorithmManager::create([new A256CBCHS512()]),
736
            CompressionMethodManager::create([new Deflate()])
737
        );
738
        $jwe = $jweBuilder->create()
739
            ->withPayload($assertion)
740
            ->withSharedProtectedHeader(['alg' => 'RSA-OAEP-256', 'enc' => 'A256CBC-HS512'])
741
            ->addRecipient(JWK::create([
742
                'kty' => 'RSA',
743
                'kid' => '[email protected]',
744
                'use' => 'enc',
745
                'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE',
746
                'e' => 'AQAB',
747
                'alg' => 'RSA-OAEP-256',
748
            ]))
749
            ->build();
750
751
        $serializer = new \Jose\Component\Encryption\Serializer\CompactSerializer($jsonConverter);
752
753
        return $serializer->serialize($jwe, 0);
754
    }
755
756
    private function buildRequest(array $data): ObjectProphecy
757
    {
758
        $body = $this->prophesize(StreamInterface::class);
759
        $body->getContents()->willReturn(\http_build_query($data));
760
        $request = $this->prophesize(ServerRequestInterface::class);
761
        $request->hasHeader('Content-Type')->willReturn(true);
762
        $request->getHeader('Content-Type')->willReturn(['application/x-www-form-urlencoded']);
763
        $request->getBody()->willReturn($body->reveal());
764
        $request->getParsedBody()->willReturn([]);
765
766
        return $request;
767
    }
768
}
769