Completed
Pull Request — master (#14)
by Oguzhan
02:24
created

JwtKeyTest::canOmitSecretWhenPassingLoader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 0
1
<?php
2
/*
3
 * This file is part of the KleijnWeb\JwtBundle package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
namespace KleijnWeb\JwtBundle\Tests\Authenticator;
9
10
use KleijnWeb\JwtBundle\Authenticator\JwtKey;
11
use KleijnWeb\JwtBundle\Authenticator\JwtToken;
12
13
/**
14
 * @author John Kleijn <[email protected]>
15
 */
16
class JwtKeyTest extends \PHPUnit_Framework_TestCase
17
{
18
    /**
19
     * @test
20
     * @expectedException \InvalidArgumentException
21
     */
22
    public function constructionWillFailWhenSecretNorLoaderPassed()
23
    {
24
        new JwtKey([]);
25
    }
26
27
    /**
28
     * @test
29
     */
30
    public function canOmitSecretWhenPassingLoader()
31
    {
32
        $actual   = new JwtKey(['loader' => 'foo']);
33
        $refl     = new \ReflectionClass($actual);
34
        $property = $refl->getProperty('secret');
35
        $property->setAccessible(true);
36
        $this->assertNull($property->getValue($actual));
37
    }
38
39
    /**
40
     * @test
41
     * @expectedException \InvalidArgumentException
42
     */
43
    public function cannotPassBothSecretAndLoader()
44
    {
45
        new JwtKey(['loader' => 'foo', 'secret' => 'bar']);
46
    }
47
48
    /**
49
     * @test
50
     */
51
    public function serializingWillClearSecret()
52
    {
53
        $key      = new JwtKey(['secret' => 'Buy the book']);
54
        $actual   = unserialize(serialize($key));
55
        $refl     = new \ReflectionClass($actual);
56
        $property = $refl->getProperty('secret');
57
        $property->setAccessible(true);
58
        $this->assertNull($property->getValue($actual));
59
    }
60
61
    /**
62
     * @test
63
     */
64
    public function validateTokenWillCallVerifySignatureOnToken()
65
    {
66
        $secret = rand();
67
        $key    = new JwtKey(['secret' => $secret]);
68
        $key->validateToken($this->createTokenMock($secret, $key));
69
    }
70
71
    /**
72
     * @test
73
     */
74
    public function willValidateIfAudienceIsConfiguredAndMatchedAny()
75
    {
76
        $key = new JwtKey(['secret'=> 'Buy the book', 'audience' => ['author', 'reader']]);
77
        $key->validateClaims(['sub' => 'john', 'aud' => 'reader']);
78
    }
79
80
    /**
81
     * @test
82
     */
83
    public function canLoadSecretFromLoader()
84
    {
85
        $secret = rand();
86
        $token  = $this->createTokenMock($secret);
87
88
        $loaderMock = $this->getMockBuilder('KleijnWeb\JwtBundle\Authenticator\SecretLoader')->getMock();
89
        $loaderMock->expects($this->once())->method('load')->with($token)->willReturn($secret);
90
91
        $key = new JwtKey(['loader' => $loaderMock]);
92
93
        $key->validateToken($token);
94
    }
95
96
    /**
97
     * @test
98
     */
99 View Code Duplication
    public function willGetRsaSignatureValidatorWhenTypeIsNotSpecified()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
100
    {
101
        $key    = new JwtKey(['secret' => 'Buy the book']);
102
        $actual = $key->getSignatureValidator();
103
        $this->assertInstanceOf(
104
            'KleijnWeb\JwtBundle\Authenticator\SignatureValidator\HmacValidator',
105
            $actual
106
        );
107
    }
108
109
    /**
110
     * @test
111
     */
112 View Code Duplication
    public function willGetRsaSignatureValidatorWhenTypeIsRsa()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
    {
114
        $key    = new JwtKey(['secret' => 'Buy the book', 'type' => JwtKey::TYPE_RSA]);
115
        $actual = $key->getSignatureValidator();
116
        $this->assertInstanceOf(
117
            'KleijnWeb\JwtBundle\Authenticator\SignatureValidator\RsaValidator',
118
            $actual
119
        );
120
    }
121
122
    /**
123
     * @test
124
     */
125 View Code Duplication
    public function validationWillFailWhenPrincipleIsMissing()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
    {
127
        $claims = ['prn' => 'joe'];
128
129
        $key = new JwtKey(['secret' => 'Buy the book']);
130
        $key->validateClaims($claims);
131
132
        unset($claims['prn']);
133
134
        $this->setExpectedException('\InvalidArgumentException');
135
136
        $key = new JwtKey(['secret' => 'Buy the book']);
137
        $key->validateClaims($claims);
138
    }
139
140
141
142
    /**
143
     * @test
144
     */
145 View Code Duplication
    public function validationWillFailWhenSubjectMissing()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
    {
147
        $claims = ['sub' => 'joe'];
148
149
        $key = new JwtKey(['secret' => 'Buy the book']);
150
        $key->validateClaims($claims);
151
152
        unset($claims['sub']);
153
154
        $this->setExpectedException('\InvalidArgumentException');
155
156
        $key = new JwtKey(['secret' => 'Buy the book']);
157
        $key->validateClaims($claims);
158
    }
159
160
    /**
161
     * @test
162
     * @expectedException \InvalidArgumentException
163
     */
164
    public function validationWillFailWhenExpiredByExp()
165
    {
166
        $key = new JwtKey(['secret' => 'Buy the book']);
167
        $key->validateClaims(['sub' => 'john', 'exp' => time() - 2]);
168
    }
169
170
    /**
171
     * @test
172
     * @expectedException \InvalidArgumentException
173
     */
174
    public function validationWillNotFailWhenExpiredByExpButWithinLeeway()
175
    {
176
        $key = new JwtKey(['secret' => 'Buy the book']);
177
        $key->validateClaims(['sub' => 'john', 'exp' => time() - 2]);
178
    }
179
180
    /**
181
     * @test
182
     */
183
    public function validationWillFailWhenExpiredByIatAndMinIssueTime()
184
    {
185
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time() + 2, 'leeway' => 3]);
186
        $key->validateClaims(['sub' => 'john', 'iat' => time()]);
187
    }
188
189
    /**
190
     * @test
191
     * @expectedException \InvalidArgumentException
192
     */
193
    public function validationWillFailWhenNotValidYet()
194
    {
195
        $key = new JwtKey(['secret' => 'Buy the book']);
196
        $key->validateClaims(['sub' => 'john', 'nbf' => time() + 2]);
197
    }
198
199
    /**
200
     * @test
201
     */
202
    public function validationWillFailNotFailWhenNotValidYetButWithinLeeway()
203
    {
204
        $key = new JwtKey(['secret' => 'Buy the book', 'leeway' => 3]);
205
        $key->validateClaims(['sub' => 'john', 'nbf' => time() + 2]);
206
    }
207
208
    /**
209
     * @test
210
     * @expectedException \InvalidArgumentException
211
     */
212
    public function validationWillFailWhenIssuerDoesNotMatch()
213
    {
214
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
215
        $key->validateClaims(['sub' => 'john', 'iss' => 'you']);
216
    }
217
218
    /**
219
     * @test
220
     * @expectedException \InvalidArgumentException
221
     */
222
    public function validationWillFailWhenAudienceDoesNotMatch()
223
    {
224
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => 'me']);
225
        $key->validateClaims(['sub' => 'john', 'aud' => 'the neighbours']);
226
    }
227
228
229
    /**
230
     * @test
231
     * @expectedException \InvalidArgumentException
232
     */
233
    public function validationWillFailWhenIssuerIsConfiguredAndNotInClaims()
234
    {
235
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
236
        $key->validateClaims(['sub' => 'john']);
237
    }
238
239
    /**
240
     * @test
241
     * @expectedException \InvalidArgumentException
242
     */
243
    public function validationWillFailWhenMinIssueTimeIsConfiguredAndIatNotInClaims()
244
    {
245
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time()]);
246
        $key->validateClaims(['sub' => 'john']);
247
    }
248
249
    /**
250
     * @test
251
     * @expectedException \InvalidArgumentException
252
     */
253
    public function validationWillFailWhenAudienceIsConfiguredAndNotInClaims()
254
    {
255
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => time()]);
256
        $key->validateClaims(['sub' => 'john']);
257
    }
258
259
    /**
260
     * @test
261
     * @expectedException \InvalidArgumentException
262
     */
263
    public function validationWillFailWhenIgnoreOtherReservedAndArbitraryClaimsAreRequiredButNotInClaims()
264
    {
265
        $key = new JwtKey(
266
            ['secret' => 'Buy the book', 'require' => ['jti', 'typ', 'and now for something completely different']]
267
        );
268
        $key->validateClaims(['sub' => 'john']);
269
    }
270
271
    /**
272
     * @test
273
     * @expectedException \InvalidArgumentException
274
     */
275
    public function headerValidationWillFailWhenAlgoIsMissing()
276
    {
277
        $key = new JwtKey(
278
            ['secret' => 'Buy the book']
279
        );
280
        $key->validateHeader(['typ' => 'JWT']);
281
    }
282
283
    /**
284
     * @test
285
     * @expectedException \InvalidArgumentException
286
     */
287
    public function headerValidationWillFailWhenTypeIsMissing()
288
    {
289
        $key = new JwtKey(
290
            ['secret' => 'Buy the book']
291
        );
292
        $key->validateHeader(['alg' => JwtKey::TYPE_HMAC]);
293
    }
294
295
    /**
296
     * @test
297
     * @expectedException \InvalidArgumentException
298
     */
299
    public function headerValidationWillFailWhenAlgorithmDoesntMatchKey()
300
    {
301
        $key = new JwtKey(
302
            ['secret' => 'Buy the book']
303
        );
304
        $key->validateHeader(['alg' => JwtKey::TYPE_RSA]);
305
    }
306
307
    /**
308
     * @test
309
     * @expectedException \InvalidArgumentException
310
     */
311
    public function headerValidationWillFailWhenTypeIsNotJwt()
312
    {
313
        $key = new JwtKey(
314
            ['secret' => 'Buy the book']
315
        );
316
        $key->validateHeader(['typ' => 'Something']);
317
    }
318
319
    /**
320
     * @param string      $secret
321
     * @param JwtKey|null $key
322
     *
323
     * @return JwtToken
324
     */
325
    private function createTokenMock($secret, JwtKey $key = null)
326
    {
327
        /** @var JwtToken $token */
328
        $token = $tokenMock = $this->getMockBuilder(
329
            'KleijnWeb\JwtBundle\Authenticator\JwtToken'
330
        )->disableOriginalConstructor()->getMock();
331
332
        $tokenMock->expects($this->once())
333
            ->method('validateSignature')
334
            ->with($secret, $key ? $key->getSignatureValidator() : $this->anything());
335
336
        $tokenMock->expects($this->once())
337
            ->method('getClaims')
338
            ->willReturn(['sub' => 'john']);
339
340
        $tokenMock->expects($this->once())
341
            ->method('getHeader')
342
            ->willReturn(['alg' => JwtKey::TYPE_HMAC, 'typ' => 'JWT']);
343
344
        return $token;
345
    }
346
}
347