Failed Conditions
Push — master ( f4dd73...badc21 )
by Luís
15s
created

parseMustRaiseExceptionWhenDealingWithInvalidClaims()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Lcobucci\JWT\Token;
5
6
use DateTimeImmutable;
7
use InvalidArgumentException;
8
use Lcobucci\Jose\Parsing\Decoder;
9
use PHPUnit\Framework\MockObject\MockObject;
10
use PHPUnit\Framework\TestCase;
11
use RuntimeException;
12
13
final class ParserTest extends TestCase
14
{
15
    /**
16
     * @var Decoder|MockObject
17
     */
18
    protected $decoder;
19
20
    /**
21
     * @before
22
     */
23
    public function createDependencies(): void
24
    {
25
        $this->decoder = $this->createMock(Decoder::class);
26
    }
27
28
    private function createParser(): Parser
29
    {
30
        return new Parser($this->decoder);
31
    }
32
33
    /**
34
     * @test
35
     *
36
     * @covers \Lcobucci\JWT\Token\Parser::__construct
37
     * @covers \Lcobucci\JWT\Token\Parser::parse
38
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
39
     */
40
    public function parseMustRaiseExceptionWhenTokenDoesNotHaveThreeParts(): void
41
    {
42
        $parser = $this->createParser();
43
44
        $this->expectException(InvalidArgumentException::class);
45
        $this->expectExceptionMessage('The JWT string must have two dots');
46
47
        $parser->parse('');
48
    }
49
50
    /**
51
     * @test
52
     *
53
     * @covers \Lcobucci\JWT\Token\Parser::__construct
54
     * @covers \Lcobucci\JWT\Token\Parser::parse
55
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
56
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
57
     */
58
    public function parseMustRaiseExceptionWhenHeaderCannotBeDecoded(): void
59
    {
60
        $this->decoder->method('base64UrlDecode')
61
                      ->with('a')
62
                      ->willReturn('b');
63
64
        $this->decoder->method('jsonDecode')
65
                      ->with('b')
66
                      ->willThrowException(new RuntimeException('Nope'));
67
68
        $parser = $this->createParser();
69
70
        $this->expectException(RuntimeException::class);
71
        $this->expectExceptionMessage('Nope');
72
73
        $parser->parse('a.b.');
74
    }
75
76
    /**
77
     * @test
78
     *
79
     * @covers \Lcobucci\JWT\Token\Parser::__construct
80
     * @covers \Lcobucci\JWT\Token\Parser::parse
81
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
82
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
83
     */
84
    public function parseMustRaiseExceptionWhenDealingWithInvalidHeaders(): void
85
    {
86
        $this->decoder->method('jsonDecode')
87
                      ->willReturn('A very invalid header');
88
89
        $parser = $this->createParser();
90
91
        $this->expectException(InvalidArgumentException::class);
92
        $this->expectExceptionMessage('Headers must be an array');
93
94
        $parser->parse('a.a.');
95
    }
96
97
    /**
98
     * @test
99
     *
100
     * @covers \Lcobucci\JWT\Token\Parser::__construct
101
     * @covers \Lcobucci\JWT\Token\Parser::parse
102
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
103
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
104
     */
105
    public function parseMustRaiseExceptionWhenTypeHeaderIsNotConfigured(): void
106
    {
107
        $this->decoder->method('jsonDecode')
108
                      ->willReturn(['alg' => 'none']);
109
110
        $parser = $this->createParser();
111
112
        $this->expectException(InvalidArgumentException::class);
113
        $this->expectExceptionMessage('The header "typ" must be present');
114
115
        $parser->parse('a.a.');
116
    }
117
118
    /**
119
     * @test
120
     *
121
     * @covers \Lcobucci\JWT\Token\Parser::__construct
122
     * @covers \Lcobucci\JWT\Token\Parser::parse
123
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
124
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
125
     */
126
    public function parseMustRaiseExceptionWhenHeaderIsFromAnEncryptedToken(): void
127
    {
128
        $this->decoder->method('jsonDecode')
129
                      ->willReturn(['enc' => 'AAA']);
130
131
        $parser = $this->createParser();
132
133
        $this->expectException(InvalidArgumentException::class);
134
        $this->expectExceptionMessage('Encryption is not supported yet');
135
136
        $parser->parse('a.a.');
137
    }
138
139
    /**
140
     * @test
141
     *
142
     * @covers \Lcobucci\JWT\Token\Parser::__construct
143
     * @covers \Lcobucci\JWT\Token\Parser::parse
144
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
145
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
146
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
147
     *
148
     * @uses \Lcobucci\JWT\Token\DataSet
149
     */
150
    public function parseMustRaiseExceptionWhenDealingWithInvalidClaims(): void
151
    {
152
        $this->decoder->method('jsonDecode')
153
                      ->willReturnOnConsecutiveCalls(['typ' => 'JWT'], 'A very invalid claim set');
154
155
        $parser = $this->createParser();
156
157
        $this->expectException(InvalidArgumentException::class);
158
        $this->expectExceptionMessage('Claims must be an array');
159
160
        $parser->parse('a.a.');
161
    }
162
163
    /**
164
     * @test
165
     *
166
     * @covers \Lcobucci\JWT\Token\Parser::__construct
167
     * @covers \Lcobucci\JWT\Token\Parser::parse
168
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
169
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
170
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
171
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
172
     *
173
     * @uses \Lcobucci\JWT\Token\Plain
174
     * @uses \Lcobucci\JWT\Token\Signature
175
     * @uses \Lcobucci\JWT\Token\DataSet
176
     */
177
    public function parseMustReturnAnUnsecuredTokenWhenSignatureIsNotInformed(): void
178
    {
179
        $this->decoder->expects(self::at(0))
180
                      ->method('base64UrlDecode')
181
                      ->with('a')
182
                      ->willReturn('a_dec');
183
184
        $this->decoder->expects(self::at(1))
185
                      ->method('jsonDecode')
186
                      ->with('a_dec')
187
                      ->willReturn(['typ' => 'JWT', 'alg' => 'none']);
188
189
        $this->decoder->expects(self::at(2))
190
                      ->method('base64UrlDecode')
191
                      ->with('b')
192
                      ->willReturn('b_dec');
193
194
        $this->decoder->expects(self::at(3))
195
                      ->method('jsonDecode')
196
                      ->with('b_dec')
197
                      ->willReturn([RegisteredClaims::AUDIENCE => 'test']);
198
199
        $parser = $this->createParser();
200
        $token  = $parser->parse('a.b.');
201
202
        self::assertInstanceOf(Plain::class, $token);
203
204
        $headers = new DataSet(['typ' => 'JWT', 'alg' => 'none'], 'a');
205
        $claims  = new DataSet([RegisteredClaims::AUDIENCE => ['test']], 'b');
206
207
        self::assertEquals($headers, $token->headers());
208
        self::assertEquals($claims, $token->claims());
209
        self::assertEquals(Signature::fromEmptyData(), $token->signature());
210
    }
211
212
    /**
213
     * @test
214
     *
215
     * @covers \Lcobucci\JWT\Token\Parser::__construct
216
     * @covers \Lcobucci\JWT\Token\Parser::parse
217
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
218
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
219
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
220
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
221
     *
222
     * @uses \Lcobucci\JWT\Token\Plain
223
     * @uses \Lcobucci\JWT\Token\Signature
224
     * @uses \Lcobucci\JWT\Token\DataSet
225
     */
226
    public function parseShouldReplicateClaimValueOnHeaderWhenNeeded(): void
227
    {
228
        $this->decoder->expects(self::at(0))
229
                      ->method('base64UrlDecode')
230
                      ->with('a')
231
                      ->willReturn('a_dec');
232
233
        $this->decoder->expects(self::at(1))
234
                      ->method('jsonDecode')
235
                      ->with('a_dec')
236
                      ->willReturn(['typ' => 'JWT', 'alg' => 'none', RegisteredClaims::AUDIENCE => 'test']);
237
238
        $this->decoder->expects(self::at(2))
239
                      ->method('base64UrlDecode')
240
                      ->with('b')
241
                      ->willReturn('b_dec');
242
243
        $this->decoder->expects(self::at(3))
244
                      ->method('jsonDecode')
245
                      ->with('b_dec')
246
                      ->willReturn([RegisteredClaims::AUDIENCE => 'test']);
247
248
        $parser = $this->createParser();
249
        $token  = $parser->parse('a.b.');
250
251
        self::assertInstanceOf(Plain::class, $token);
252
253
        $headers = new DataSet(['typ' => 'JWT', 'alg' => 'none', RegisteredClaims::AUDIENCE => 'test'], 'a');
254
        $claims  = new DataSet([RegisteredClaims::AUDIENCE => ['test']], 'b');
255
256
        self::assertEquals($headers, $token->headers());
257
        self::assertEquals($claims, $token->claims());
258
        self::assertEquals(Signature::fromEmptyData(), $token->signature());
259
    }
260
261
    /**
262
     * @test
263
     *
264
     * @covers \Lcobucci\JWT\Token\Parser::__construct
265
     * @covers \Lcobucci\JWT\Token\Parser::parse
266
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
267
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
268
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
269
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
270
     *
271
     * @uses \Lcobucci\JWT\Token\Plain
272
     * @uses \Lcobucci\JWT\Token\Signature
273
     * @uses \Lcobucci\JWT\Token\DataSet
274
     */
275
    public function parseMustReturnANonSignedTokenWhenSignatureAlgorithmIsMissing(): void
276
    {
277
        $this->decoder->expects(self::at(0))
278
                      ->method('base64UrlDecode')
279
                      ->with('a')
280
                      ->willReturn('a_dec');
281
282
        $this->decoder->expects(self::at(1))
283
                      ->method('jsonDecode')
284
                      ->with('a_dec')
285
                      ->willReturn(['typ' => 'JWT']);
286
287
        $this->decoder->expects(self::at(2))
288
                      ->method('base64UrlDecode')
289
                      ->with('b')
290
                      ->willReturn('b_dec');
291
292
        $this->decoder->expects(self::at(3))
293
                      ->method('jsonDecode')
294
                      ->with('b_dec')
295
                      ->willReturn([RegisteredClaims::AUDIENCE => 'test']);
296
297
        $parser = $this->createParser();
298
        $token  = $parser->parse('a.b.c');
299
300
        self::assertInstanceOf(Plain::class, $token);
301
302
        $headers = new DataSet(['typ' => 'JWT'], 'a');
303
        $claims  = new DataSet([RegisteredClaims::AUDIENCE => ['test']], 'b');
304
305
        self::assertEquals($headers, $token->headers());
306
        self::assertEquals($claims, $token->claims());
307
        self::assertEquals(Signature::fromEmptyData(), $token->signature());
308
    }
309
310
    /**
311
     * @test
312
     *
313
     * @covers \Lcobucci\JWT\Token\Parser::__construct
314
     * @covers \Lcobucci\JWT\Token\Parser::parse
315
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
316
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
317
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
318
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
319
     *
320
     * @uses \Lcobucci\JWT\Token\Plain
321
     * @uses \Lcobucci\JWT\Token\Signature
322
     * @uses \Lcobucci\JWT\Token\DataSet
323
     */
324
    public function parseMustReturnANonSignedTokenWhenSignatureAlgorithmIsNone(): void
325
    {
326
        $this->decoder->expects(self::at(0))
327
                      ->method('base64UrlDecode')
328
                      ->with('a')
329
                      ->willReturn('a_dec');
330
331
        $this->decoder->expects(self::at(1))
332
                      ->method('jsonDecode')
333
                      ->with('a_dec')
334
                      ->willReturn(['typ' => 'JWT', 'alg' => 'none']);
335
336
        $this->decoder->expects(self::at(2))
337
                      ->method('base64UrlDecode')
338
                      ->with('b')
339
                      ->willReturn('b_dec');
340
341
        $this->decoder->expects(self::at(3))
342
                      ->method('jsonDecode')
343
                      ->with('b_dec')
344
                      ->willReturn([RegisteredClaims::AUDIENCE => 'test']);
345
346
        $parser = $this->createParser();
347
        $token  = $parser->parse('a.b.c');
348
349
        self::assertInstanceOf(Plain::class, $token);
350
351
        $headers = new DataSet(['typ' => 'JWT', 'alg' => 'none'], 'a');
352
        $claims  = new DataSet([RegisteredClaims::AUDIENCE => ['test']], 'b');
353
354
        self::assertEquals($headers, $token->headers());
355
        self::assertEquals($claims, $token->claims());
356
        self::assertEquals(Signature::fromEmptyData(), $token->signature());
357
    }
358
359
    /**
360
     * @test
361
     *
362
     * @covers \Lcobucci\JWT\Token\Parser::__construct
363
     * @covers \Lcobucci\JWT\Token\Parser::parse
364
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
365
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
366
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
367
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
368
     *
369
     * @uses \Lcobucci\JWT\Token\Plain
370
     * @uses \Lcobucci\JWT\Token\Signature
371
     * @uses \Lcobucci\JWT\Token\DataSet
372
     */
373
    public function parseMustReturnASignedTokenWhenSignatureIsInformed(): void
374
    {
375
        $this->decoder->expects(self::at(0))
376
                      ->method('base64UrlDecode')
377
                      ->with('a')
378
                      ->willReturn('a_dec');
379
380
        $this->decoder->expects(self::at(1))
381
                      ->method('jsonDecode')
382
                      ->with('a_dec')
383
                      ->willReturn(['typ' => 'JWT', 'alg' => 'HS256']);
384
385
        $this->decoder->expects(self::at(2))
386
                      ->method('base64UrlDecode')
387
                      ->with('b')
388
                      ->willReturn('b_dec');
389
390
        $this->decoder->expects(self::at(3))
391
                      ->method('jsonDecode')
392
                      ->with('b_dec')
393
                      ->willReturn([RegisteredClaims::AUDIENCE => 'test']);
394
395
        $this->decoder->expects(self::at(4))
396
                      ->method('base64UrlDecode')
397
                      ->with('c')
398
                      ->willReturn('c_dec');
399
400
        $parser = $this->createParser();
401
        $token  = $parser->parse('a.b.c');
402
403
        self::assertInstanceOf(Plain::class, $token);
404
405
        $headers   = new DataSet(['typ' => 'JWT', 'alg' => 'HS256'], 'a');
406
        $claims    = new DataSet([RegisteredClaims::AUDIENCE => ['test']], 'b');
407
        $signature = new Signature('c_dec', 'c');
408
409
        self::assertEquals($headers, $token->headers());
410
        self::assertEquals($claims, $token->claims());
411
        self::assertEquals($signature, $token->signature());
412
    }
413
414
    /**
415
     * @test
416
     *
417
     * @covers \Lcobucci\JWT\Token\Parser::__construct
418
     * @covers \Lcobucci\JWT\Token\Parser::parse
419
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
420
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
421
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
422
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
423
     * @covers \Lcobucci\JWT\Token\Parser::convertDate
424
     *
425
     * @uses \Lcobucci\JWT\Token\Plain
426
     * @uses \Lcobucci\JWT\Token\Signature
427
     * @uses \Lcobucci\JWT\Token\DataSet
428
     */
429
    public function parseMustConvertDateClaimsToObjects(): void
430
    {
431
        $data = [
432
            RegisteredClaims::ISSUED_AT => 1486930663,
433
            RegisteredClaims::NOT_BEFORE => 1486930663,
434
            RegisteredClaims::EXPIRATION_TIME => '1486930757.023055',
435
        ];
436
437
        $this->decoder->expects(self::at(0))
438
                      ->method('base64UrlDecode')
439
                      ->with('a')
440
                      ->willReturn('a_dec');
441
442
        $this->decoder->expects(self::at(1))
443
                      ->method('jsonDecode')
444
                      ->with('a_dec')
445
                      ->willReturn(['typ' => 'JWT', 'alg' => 'HS256']);
446
447
        $this->decoder->expects(self::at(2))
448
                      ->method('base64UrlDecode')
449
                      ->with('b')
450
                      ->willReturn('b_dec');
451
452
        $this->decoder->expects(self::at(3))
453
                      ->method('jsonDecode')
454
                      ->with('b_dec')
455
                      ->willReturn($data);
456
457
        $token = $this->createParser()->parse('a.b.');
458
        self::assertInstanceOf(Plain::class, $token);
459
460
        $claims = $token->claims();
461
462
        self::assertEquals(
463
            DateTimeImmutable::createFromFormat('U', '1486930663'),
464
            $claims->get(RegisteredClaims::ISSUED_AT)
465
        );
466
467
        self::assertEquals(
468
            DateTimeImmutable::createFromFormat('U', '1486930663'),
469
            $claims->get(RegisteredClaims::NOT_BEFORE)
470
        );
471
472
        self::assertEquals(
473
            DateTimeImmutable::createFromFormat('U.u', '1486930757.023055'),
474
            $claims->get(RegisteredClaims::EXPIRATION_TIME)
475
        );
476
    }
477
478
    /**
479
     * @test
480
     *
481
     * @covers \Lcobucci\JWT\Token\Parser::__construct
482
     * @covers \Lcobucci\JWT\Token\Parser::parse
483
     * @covers \Lcobucci\JWT\Token\Parser::splitJwt
484
     * @covers \Lcobucci\JWT\Token\Parser::parseHeader
485
     * @covers \Lcobucci\JWT\Token\Parser::parseClaims
486
     * @covers \Lcobucci\JWT\Token\Parser::parseSignature
487
     * @covers \Lcobucci\JWT\Token\Parser::convertDate
488
     *
489
     * @uses \Lcobucci\JWT\Token\Plain
490
     * @uses \Lcobucci\JWT\Token\Signature
491
     * @uses \Lcobucci\JWT\Token\DataSet
492
     */
493
    public function parseShouldRaiseExceptionOnInvalidDate(): void
494
    {
495
        $data = [RegisteredClaims::ISSUED_AT => '14/10/2018 10:50:10.10 UTC'];
496
497
        $this->decoder->expects(self::at(0))
498
                      ->method('base64UrlDecode')
499
                      ->with('a')
500
                      ->willReturn('a_dec');
501
502
        $this->decoder->expects(self::at(1))
503
                      ->method('jsonDecode')
504
                      ->with('a_dec')
505
                      ->willReturn(['typ' => 'JWT', 'alg' => 'HS256']);
506
507
        $this->decoder->expects(self::at(2))
508
                      ->method('base64UrlDecode')
509
                      ->with('b')
510
                      ->willReturn('b_dec');
511
512
        $this->decoder->expects(self::at(3))
513
                      ->method('jsonDecode')
514
                      ->with('b_dec')
515
                      ->willReturn($data);
516
517
        $this->expectException(InvalidArgumentException::class);
518
        $this->expectExceptionMessage('Given value is not in the allowed format: 14/10/2018 10:50:10.10 UTC');
519
        $this->createParser()->parse('a.b.');
520
    }
521
}
522