Failed Conditions
Push — ng ( 6dd952...0976bc )
by Florent
16:09
created

AuthorizationRequestLoaderTest   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 563
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 9
dl 0
loc 563
rs 8.8
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A basicCalls() 0 16 1
A theAuthorizationRequestMustContainAClientId() 0 19 2
A theClientDoesNotExist() 0 22 2
B theClientIsDeleted() 0 25 2
A theClientExistsAndTheParametersAreReturned() 0 22 1
A theRequestObjectIsNotAValidAssertion() 0 21 2
A theRequestObjectPayloadDoesNotContainClaims() 0 21 2
A theRequestObjectParametersDoesNotContainAClientId() 0 21 2
B theClientHasNoPublicKeysAndCannotUseTheRequestObjectParameters() 0 28 2
B theClientDidNotReferencedAnySignatureAlgorithmAndTheUsedAlgorithmIsNotSupported() 0 30 2
B theSignatureAlgorithmIsNotAllowedForThatClient() 0 31 2
B theSignatureVerificationFailed() 0 31 2
B theAssertionIsVerified() 0 31 1
B theRequestObjectUriIsVerified() 0 32 1
B theRequestUriIsNotAllowedForTheClient() 0 33 2
A theRequestUriMustNotContainPathTraversal() 0 21 2
A getAuthorizationRequestLoader() 0 16 2
A getJWSVerifier() 0 14 2
A getSignatureAlgorithmManager() 0 7 1
A getClaimCheckerManager() 0 9 1
A getHttpClient() 0 20 2
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\AuthorizationEndpoint\Tests;
15
16
use Http\Mock\Client;
17
use Jose\Component\Checker\ClaimCheckerManager;
18
use Jose\Component\Core\AlgorithmManager;
19
use Jose\Component\Core\JWKSet;
20
use Jose\Component\Encryption\JWELoader;
21
use Jose\Component\Signature\JWS;
22
use Jose\Component\Signature\JWSVerifier;
23
use OAuth2Framework\Component\AuthorizationEndpoint\AuthorizationRequestLoader;
24
use OAuth2Framework\Component\Core\Client\ClientRepository;
25
use OAuth2Framework\Component\Core\Exception\OAuth2Exception;
26
use PHPUnit\Framework\TestCase;
27
use Prophecy\Argument;
28
use Psr\Http\Message\RequestInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Zend\Diactoros\Response;
31
use Zend\Diactoros\Uri;
32
33
/**
34
 * @group AuthorizationEndpoint
35
 * @group AuthorizationRequestLoader
36
 */
37
class AuthorizationRequestLoaderTest extends TestCase
38
{
39
    /**
40
     * @test
41
     */
42
    public function basicCalls()
43
    {
44
        $clientRepository = $this->prophesize(ClientRepository::class);
45
        $loader = $this->getAuthorizationRequestLoader(
46
            $clientRepository->reveal()
47
        );
48
        self::assertEquals([], $loader->getSupportedKeyEncryptionAlgorithms());
49
        self::assertEquals([], $loader->getSupportedContentEncryptionAlgorithms());
50
        self::assertEquals(['RS256'], $loader->getSupportedSignatureAlgorithms());
51
        self::assertTrue($loader->isRequestObjectSupportEnabled());
52
        self::assertTrue($loader->isRequestUriRegistrationRequired());
53
        self::assertTrue($loader->isRequestObjectReferenceSupportEnabled());
54
        self::assertFalse($loader->isEncryptedRequestSupportEnabled());
55
56
        //$this->authorizationRequestLoader->enableEncryptedRequestObjectSupport($jweLoader, $keyset, false);
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
57
    }
58
59
    /**
60
     * @test
61
     */
62
    public function theAuthorizationRequestMustContainAClientId()
63
    {
64
        $clientRepository = $this->prophesize(ClientRepository::class);
65
        $request = $this->prophesize(ServerRequestInterface::class);
66
        $request->getQueryParams()
67
            ->willReturn([])
68
            ->shouldBeCalled();
69
70
        try {
71
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
72
                $request->reveal()
73
            );
74
            $this->fail('The expected exception has not been thrown.');
75
        } catch (OAuth2Exception $e) {
76
            self::assertEquals(400, $e->getCode());
77
            self::assertEquals('invalid_request', $e->getMessage());
78
            self::assertEquals('Parameter "client_id" missing or invalid.', $e->getErrorDescription());
79
        }
80
    }
81
82
    /**
83
     * @test
84
     */
85
    public function theClientDoesNotExist()
86
    {
87
        $clientRepository = $this->prophesize(ClientRepository::class);
88
        $clientRepository->find(Argument::any())->willReturn(null)->shouldBeCalled();
89
        $request = $this->prophesize(ServerRequestInterface::class);
90
        $request->getQueryParams()
91
            ->willReturn([
92
                'client_id' => 'BAD_CLIENT_ID',
93
            ])
94
            ->shouldBeCalled();
95
96
        try {
97
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
98
                $request->reveal()
99
            );
100
            $this->fail('The expected exception has not been thrown.');
101
        } catch (OAuth2Exception $e) {
102
            self::assertEquals(400, $e->getCode());
103
            self::assertEquals('invalid_request', $e->getMessage());
104
            self::assertEquals('Parameter "client_id" missing or invalid.', $e->getErrorDescription());
105
        }
106
    }
107
108
    /**
109
     * @test
110
     */
111
    public function theClientIsDeleted()
112
    {
113
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
114
        $client->isDeleted()->willReturn(true)->shouldBeCalled();
115
116
        $clientRepository = $this->prophesize(ClientRepository::class);
117
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
118
        $request = $this->prophesize(ServerRequestInterface::class);
119
        $request->getQueryParams()
120
            ->willReturn([
121
                'client_id' => 'DELETED_CLIENT_ID',
122
            ])
123
            ->shouldBeCalled();
124
125
        try {
126
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
127
                $request->reveal()
128
            );
129
            $this->fail('The expected exception has not been thrown.');
130
        } catch (OAuth2Exception $e) {
131
            self::assertEquals(400, $e->getCode());
132
            self::assertEquals('invalid_request', $e->getMessage());
133
            self::assertEquals('Parameter "client_id" missing or invalid.', $e->getErrorDescription());
134
        }
135
    }
136
137
    /**
138
     * @test
139
     */
140
    public function theClientExistsAndTheParametersAreReturned()
141
    {
142
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
143
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
144
145
        $clientRepository = $this->prophesize(ClientRepository::class);
146
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
147
        $request = $this->prophesize(ServerRequestInterface::class);
148
        $request->getQueryParams()
149
            ->willReturn([
150
                'client_id' => 'CLIENT_ID',
151
            ])
152
            ->shouldBeCalled();
153
154
        $authorization = $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
155
            $request->reveal()
156
        );
157
158
        self::assertTrue($authorization->hasQueryParam('client_id'));
159
        self::assertEquals('CLIENT_ID', $authorization->getQueryParam('client_id'));
160
        self::assertInstanceOf(\OAuth2Framework\Component\Core\Client\Client::class, $authorization->getClient());
161
    }
162
163
    /**
164
     * @test
165
     */
166
    public function theRequestObjectIsNotAValidAssertion()
167
    {
168
        $clientRepository = $this->prophesize(ClientRepository::class);
169
        $request = $this->prophesize(ServerRequestInterface::class);
170
        $request->getQueryParams()
171
            ->willReturn([
172
                'request' => 'INVALID_ASSERTION',
173
            ])
174
            ->shouldBeCalled();
175
176
        try {
177
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
178
                $request->reveal()
179
            );
180
            $this->fail('The expected exception has not been thrown.');
181
        } catch (OAuth2Exception $e) {
182
            self::assertEquals(400, $e->getCode());
183
            self::assertEquals('invalid_request_object', $e->getMessage());
184
            self::assertEquals('Unsupported input', $e->getErrorDescription());
185
        }
186
    }
187
188
    /**
189
     * @test
190
     */
191
    public function theRequestObjectPayloadDoesNotContainClaims()
192
    {
193
        $clientRepository = $this->prophesize(ClientRepository::class);
194
        $request = $this->prophesize(ServerRequestInterface::class);
195
        $request->getQueryParams()
196
            ->willReturn([
197
                'request' => 'eyJhbGciOiJub25lIn0.SEVMTE8gV09STEQh.',
198
            ])
199
            ->shouldBeCalled();
200
201
        try {
202
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
203
                $request->reveal()
204
            );
205
            $this->fail('The expected exception has not been thrown.');
206
        } catch (OAuth2Exception $e) {
207
            self::assertEquals(400, $e->getCode());
208
            self::assertEquals('invalid_request_object', $e->getMessage());
209
            self::assertEquals('Invalid assertion. The payload must contain claims.', $e->getErrorDescription());
210
        }
211
    }
212
213
    /**
214
     * @test
215
     */
216
    public function theRequestObjectParametersDoesNotContainAClientId()
217
    {
218
        $clientRepository = $this->prophesize(ClientRepository::class);
219
        $request = $this->prophesize(ServerRequestInterface::class);
220
        $request->getQueryParams()
221
            ->willReturn([
222
                'request' => 'eyJhbGciOiJub25lIn0.e30.',
223
            ])
224
            ->shouldBeCalled();
225
226
        try {
227
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
228
                $request->reveal()
229
            );
230
            $this->fail('The expected exception has not been thrown.');
231
        } catch (OAuth2Exception $e) {
232
            self::assertEquals(400, $e->getCode());
233
            self::assertEquals('invalid_request', $e->getMessage());
234
            self::assertEquals('Parameter "client_id" missing or invalid.', $e->getErrorDescription());
235
        }
236
    }
237
238
    /**
239
     * @test
240
     */
241
    public function theClientHasNoPublicKeysAndCannotUseTheRequestObjectParameters()
242
    {
243
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
244
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
245
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
246
        $client->has('jwks_uri')->willReturn(false)->shouldBeCalled();
247
        $client->has('client_secret')->willReturn(false)->shouldBeCalled();
248
249
        $clientRepository = $this->prophesize(ClientRepository::class);
250
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
251
        $request = $this->prophesize(ServerRequestInterface::class);
252
        $request->getQueryParams()
253
            ->willReturn([
254
                'request' => 'eyJhbGciOiJub25lIn0.eyJjbGllbnRfaWQiOiJOT19LRVlfQ0xJRU5UX0lEIn0.',
255
            ])
256
            ->shouldBeCalled();
257
258
        try {
259
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
260
                $request->reveal()
261
            );
262
            $this->fail('The expected exception has not been thrown.');
263
        } catch (OAuth2Exception $e) {
264
            self::assertEquals(400, $e->getCode());
265
            self::assertEquals('invalid_request_object', $e->getMessage());
266
            self::assertEquals('The client has no key or key set.', $e->getErrorDescription());
267
        }
268
    }
269
270
    /**
271
     * @test
272
     */
273
    public function theClientDidNotReferencedAnySignatureAlgorithmAndTheUsedAlgorithmIsNotSupported()
274
    {
275
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
276
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
277
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
278
        $client->has('client_secret')->willReturn(true)->shouldBeCalled();
279
        $client->get('client_secret')->willReturn('SECRET')->shouldBeCalled();
280
        $client->has('request_object_signing_alg')->willReturn(false)->shouldBeCalled();
281
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt')->shouldBeCalled();
282
283
        $clientRepository = $this->prophesize(ClientRepository::class);
284
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
285
        $request = $this->prophesize(ServerRequestInterface::class);
286
        $request->getQueryParams()
287
            ->willReturn([
288
                'request' => 'eyJhbGciOiJub25lIn0.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.',
289
            ])
290
            ->shouldBeCalled();
291
292
        try {
293
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
294
                $request->reveal()
295
            );
296
            $this->fail('The expected exception has not been thrown.');
297
        } catch (OAuth2Exception $e) {
298
            self::assertEquals(400, $e->getCode());
299
            self::assertEquals('invalid_request_object', $e->getMessage());
300
            self::assertEquals('The algorithm "none" is not allowed for request object signatures. Please use one of the following algorithm(s): RS256', $e->getErrorDescription());
301
        }
302
    }
303
304
    /**
305
     * @test
306
     */
307
    public function theSignatureAlgorithmIsNotAllowedForThatClient()
308
    {
309
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
310
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
311
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
312
        $client->has('client_secret')->willReturn(true)->shouldBeCalled();
313
        $client->get('client_secret')->willReturn('SECRET')->shouldBeCalled();
314
        $client->has('request_object_signing_alg')->willReturn(true)->shouldBeCalled();
315
        $client->get('request_object_signing_alg')->willReturn('RS256')->shouldBeCalled();
316
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt')->shouldBeCalled();
317
318
        $clientRepository = $this->prophesize(ClientRepository::class);
319
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
320
        $request = $this->prophesize(ServerRequestInterface::class);
321
        $request->getQueryParams()
322
            ->willReturn([
323
                'request' => 'eyJhbGciOiJub25lIn0.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.',
324
            ])
325
            ->shouldBeCalled();
326
327
        try {
328
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
329
                $request->reveal()
330
            );
331
            $this->fail('The expected exception has not been thrown.');
332
        } catch (OAuth2Exception $e) {
333
            self::assertEquals(400, $e->getCode());
334
            self::assertEquals('invalid_request_object', $e->getMessage());
335
            self::assertEquals('Request Object signature algorithm not allowed for the client.', $e->getErrorDescription());
336
        }
337
    }
338
339
    /**
340
     * @test
341
     */
342
    public function theSignatureVerificationFailed()
343
    {
344
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
345
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
346
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
347
        $client->has('client_secret')->willReturn(true)->shouldBeCalled();
348
        $client->get('client_secret')->willReturn('SECRET')->shouldBeCalled();
349
        $client->has('request_object_signing_alg')->willReturn(true)->shouldBeCalled();
350
        $client->get('request_object_signing_alg')->willReturn('RS256')->shouldBeCalled();
351
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt')->shouldBeCalled();
352
353
        $clientRepository = $this->prophesize(ClientRepository::class);
354
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
355
        $request = $this->prophesize(ServerRequestInterface::class);
356
        $request->getQueryParams()
357
            ->willReturn([
358
                'request' => 'eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.',
359
            ])
360
            ->shouldBeCalled();
361
362
        try {
363
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
364
                $request->reveal()
365
            );
366
            $this->fail('The expected exception has not been thrown.');
367
        } catch (OAuth2Exception $e) {
368
            self::assertEquals(400, $e->getCode());
369
            self::assertEquals('invalid_request_object', $e->getMessage());
370
            self::assertEquals('The verification of the request object failed.', $e->getErrorDescription());
371
        }
372
    }
373
374
    /**
375
     * @test
376
     */
377
    public function theAssertionIsVerified()
378
    {
379
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
380
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
381
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
382
        $client->has('client_secret')->willReturn(true)->shouldBeCalled();
383
        $client->get('client_secret')->willReturn('SECRET')->shouldBeCalled();
384
        $client->has('request_object_signing_alg')->willReturn(true)->shouldBeCalled();
385
        $client->get('request_object_signing_alg')->willReturn('RS256')->shouldBeCalled();
386
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt')->shouldBeCalled();
387
388
        $clientRepository = $this->prophesize(ClientRepository::class);
389
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
390
        $request = $this->prophesize(ServerRequestInterface::class);
391
        $request->getQueryParams()
392
            ->willReturn([
393
                'request' => 'eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU',
394
            ])
395
            ->shouldBeCalled();
396
397
        $authorization = $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
398
            $request->reveal()
399
        );
400
401
402
        self::assertTrue($authorization->hasQueryParam('client_id'));
403
        self::assertTrue($authorization->hasQueryParam('request'));
404
        self::assertEquals('CLIENT_ID', $authorization->getQueryParam('client_id'));
405
        self::assertEquals('eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU', $authorization->getQueryParam('request'));
406
        self::assertInstanceOf(\OAuth2Framework\Component\Core\Client\Client::class, $authorization->getClient());
407
    }
408
409
    /**
410
     * @test
411
     */
412
    public function theRequestObjectUriIsVerified()
413
    {
414
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
415
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
416
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
417
        $client->has('client_secret')->willReturn(true)->shouldBeCalled();
418
        $client->get('client_secret')->willReturn('SECRET')->shouldBeCalled();
419
        $client->has('request_object_signing_alg')->willReturn(true)->shouldBeCalled();
420
        $client->get('request_object_signing_alg')->willReturn('RS256')->shouldBeCalled();
421
        $client->has('request_uris')->willReturn(true)->shouldBeCalled();
422
        $client->get('request_uris')->willReturn(['https://www.foo.bar/'])->shouldBeCalled();
423
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt')->shouldBeCalled();
424
425
        $clientRepository = $this->prophesize(ClientRepository::class);
426
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
427
        $request = $this->prophesize(ServerRequestInterface::class);
428
        $request->getQueryParams()
429
            ->willReturn([
430
                'request_uri' => 'https://www.foo.bar/eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU',
431
            ])
432
            ->shouldBeCalled();
433
434
        $authorization = $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
435
            $request->reveal()
436
        );
437
438
        self::assertTrue($authorization->hasQueryParam('client_id'));
439
        self::assertTrue($authorization->hasQueryParam('request_uri'));
440
        self::assertEquals('CLIENT_ID', $authorization->getQueryParam('client_id'));
441
        self::assertEquals('https://www.foo.bar/eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU', $authorization->getQueryParam('request_uri'));
442
        self::assertInstanceOf(\OAuth2Framework\Component\Core\Client\Client::class, $authorization->getClient());
443
    }
444
445
    /**
446
     * @test
447
     */
448
    public function theRequestUriIsNotAllowedForTheClient()
449
    {
450
        $client = $this->prophesize(\OAuth2Framework\Component\Core\Client\Client::class);
451
        $client->isDeleted()->willReturn(false)->shouldBeCalled();
452
        $client->has('jwks')->willReturn(false)->shouldBeCalled();
453
        $client->has('client_secret')->willReturn(true)->shouldBeCalled();
454
        $client->get('client_secret')->willReturn('SECRET')->shouldBeCalled();
455
        $client->has('request_object_signing_alg')->willReturn(true)->shouldBeCalled();
456
        $client->get('request_object_signing_alg')->willReturn('RS256')->shouldBeCalled();
457
        $client->has('request_uris')->willReturn(true)->shouldBeCalled();
458
        $client->get('request_uris')->willReturn(['https://www.foo.bar/'])->shouldBeCalled();
459
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_jwt')->shouldBeCalled();
460
461
        $clientRepository = $this->prophesize(ClientRepository::class);
462
        $clientRepository->find(Argument::any())->willReturn($client->reveal())->shouldBeCalled();
463
        $request = $this->prophesize(ServerRequestInterface::class);
464
        $request->getQueryParams()
465
            ->willReturn([
466
                'request_uri' => 'https://www.bad.host/eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU',
467
            ])
468
            ->shouldBeCalled();
469
470
        try {
471
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
472
                $request->reveal()
473
            );
474
            $this->fail('The expected exception has not been thrown.');
475
        } catch (OAuth2Exception $e) {
476
            self::assertEquals(400, $e->getCode());
477
            self::assertEquals('invalid_request_uri', $e->getMessage());
478
            self::assertEquals('The request Uri is not allowed.', $e->getErrorDescription());
479
        }
480
    }
481
482
    /**
483
     * @test
484
     */
485
    public function theRequestUriMustNotContainPathTraversal()
486
    {
487
        $clientRepository = $this->prophesize(ClientRepository::class);
488
        $request = $this->prophesize(ServerRequestInterface::class);
489
        $request->getQueryParams()
490
            ->willReturn([
491
                'request_uri' => 'https://www.foo.bar/../eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU',
492
            ])
493
            ->shouldBeCalled();
494
495
        try {
496
            $this->getAuthorizationRequestLoader($clientRepository->reveal())->load(
497
                $request->reveal()
498
            );
499
            $this->fail('The expected exception has not been thrown.');
500
        } catch (OAuth2Exception $e) {
501
            self::assertEquals(400, $e->getCode());
502
            self::assertEquals('invalid_request_uri', $e->getMessage());
503
            self::assertEquals('The request Uri is not allowed.', $e->getErrorDescription());
504
        }
505
    }
506
507
    /**
508
     * @var null|AuthorizationRequestLoader
509
     */
510
    private $authorizationRequestLoader;
511
512
    /**
513
     * @param ClientRepository $clientRepository
514
     *
515
     * @return AuthorizationRequestLoader
516
     */
517
    private function getAuthorizationRequestLoader(ClientRepository $clientRepository): AuthorizationRequestLoader
518
    {
519
        if (null === $this->authorizationRequestLoader) {
520
            $this->authorizationRequestLoader = new AuthorizationRequestLoader($clientRepository);
521
            $this->authorizationRequestLoader->enableSignedRequestObjectSupport(
522
                $this->getJWSVerifier(),
523
                $this->getClaimCheckerManager()
524
            );
525
            $this->authorizationRequestLoader->enableRequestObjectReferenceSupport(
526
                $this->getHttpClient(),
527
                true
528
            );
529
        }
530
531
        return $this->authorizationRequestLoader;
532
    }
533
534
    /**
535
     * @return JWSVerifier
536
     */
537
    private function getJWSVerifier(): JWSVerifier
538
    {
539
        $verifier = $this->prophesize(JWSVerifier::class);
540
        $verifier->getSignatureAlgorithmManager()->willReturn(
541
            $this->getSignatureAlgorithmManager()
542
        );
543
        $verifier->verifyWithKeySet(Argument::type(JWS::class), Argument::type(JWKSet::class), 0, null)->will(function(array $args) {
544
            return
545
                ($args[0])->getSignature(0)->getProtectedHeaderParameter('alg') === 'RS256' &&
546
                ($args[0])->getSignature(0)->getSignature() !== '';
547
        });
548
549
        return $verifier->reveal();
550
    }
551
552
    /**
553
     * @return AlgorithmManager
554
     */
555
    private function getSignatureAlgorithmManager(): AlgorithmManager
556
    {
557
        $manager = $this->prophesize(AlgorithmManager::class);
558
        $manager->list()->willReturn(['RS256']);
559
560
        return $manager->reveal();
561
    }
562
563
    /**
564
     * @return ClaimCheckerManager
565
     */
566
    private function getClaimCheckerManager(): ClaimCheckerManager
567
    {
568
        $manager = $this->prophesize(ClaimCheckerManager::class);
569
        $manager->check(Argument::any())->will(function (array $args) {
570
            return $args[0];
571
        });
572
573
        return $manager->reveal();
574
    }
575
576
    /**
577
     * @return Client
578
     */
579
    private function getHttpClient(): Client
580
    {
581
582
583
        $client = $this->prophesize(Client::class);
584
        $client->sendRequest(Argument::type(RequestInterface::class))->will(function (array $args) {
585
            /** @var Uri $uri */
586
            $uri = ($args[0])->getUri();
587
            switch ($uri->getPath()) {
588
                case '/eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU':
589
                    $response = new Response();
590
                    $response->getBody()->write('eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJDTElFTlRfSUQifQ.R09PRF9TSUdOQVRVUkU');
591
                    $response->getBody()->rewind();
592
593
                    return $response;
594
            }
595
        });
596
597
        return $client->reveal();
598
    }
599
}
600