Completed
Push — master ( 529931...9d1388 )
by John
02:22
created

validationWillFailWhenIssuerIsConfiguredAndNotInClaims()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
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 canLoadSecretFromLoader()
75
    {
76
        $secret = rand();
77
        $token  = $this->createTokenMock($secret);
78
79
        $loaderMock = $this->getMockBuilder('KleijnWeb\JwtBundle\Authenticator\SecretLoader')->getMock();
80
        $loaderMock->expects($this->once())->method('load')->with($token)->willReturn($secret);
81
82
        $key = new JwtKey(['loader' => $loaderMock]);
83
84
        $key->validateToken($token);
85
    }
86
87
    /**
88
     * @test
89
     */
90 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...
91
    {
92
        $key    = new JwtKey(['secret' => 'Buy the book']);
93
        $actual = $key->getSignatureValidator();
94
        $this->assertInstanceOf(
95
            'KleijnWeb\JwtBundle\Authenticator\SignatureValidator\HmacValidator',
96
            $actual
97
        );
98
    }
99
100
    /**
101
     * @test
102
     */
103 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...
104
    {
105
        $key    = new JwtKey(['secret' => 'Buy the book', 'type' => JwtKey::TYPE_RSA]);
106
        $actual = $key->getSignatureValidator();
107
        $this->assertInstanceOf(
108
            'KleijnWeb\JwtBundle\Authenticator\SignatureValidator\RsaValidator',
109
            $actual
110
        );
111
    }
112
113
    /**
114
     * @test
115
     */
116 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...
117
    {
118
        $claims = ['prn' => 'joe'];
119
120
        $key = new JwtKey(['secret' => 'Buy the book']);
121
        $key->validateClaims($claims);
122
123
        unset($claims['prn']);
124
125
        $this->setExpectedException('\InvalidArgumentException');
126
127
        $key = new JwtKey(['secret' => 'Buy the book']);
128
        $key->validateClaims($claims);
129
    }
130
131
132
133
    /**
134
     * @test
135
     */
136 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...
137
    {
138
        $claims = ['sub' => 'joe'];
139
140
        $key = new JwtKey(['secret' => 'Buy the book']);
141
        $key->validateClaims($claims);
142
143
        unset($claims['sub']);
144
145
        $this->setExpectedException('\InvalidArgumentException');
146
147
        $key = new JwtKey(['secret' => 'Buy the book']);
148
        $key->validateClaims($claims);
149
    }
150
151
    /**
152
     * @test
153
     * @expectedException \InvalidArgumentException
154
     */
155
    public function validationWillFailWhenExpiredByExp()
156
    {
157
        $key = new JwtKey(['secret' => 'Buy the book']);
158
        $key->validateClaims(['sub' => 'john', 'exp' => time() - 2]);
159
    }
160
161
    /**
162
     * @test
163
     * @expectedException \InvalidArgumentException
164
     */
165
    public function validationWillNotFailWhenExpiredByExpButWithinLeeway()
166
    {
167
        $key = new JwtKey(['secret' => 'Buy the book']);
168
        $key->validateClaims(['sub' => 'john', 'exp' => time() - 2]);
169
    }
170
171
    /**
172
     * @test
173
     */
174
    public function validationWillFailWhenExpiredByIatAndMinIssueTime()
175
    {
176
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time() + 2, 'leeway' => 3]);
177
        $key->validateClaims(['sub' => 'john', 'iat' => time()]);
178
    }
179
180
    /**
181
     * @test
182
     * @expectedException \InvalidArgumentException
183
     */
184
    public function validationWillFailWhenNotValidYet()
185
    {
186
        $key = new JwtKey(['secret' => 'Buy the book']);
187
        $key->validateClaims(['sub' => 'john', 'nbf' => time() + 2]);
188
    }
189
190
    /**
191
     * @test
192
     */
193
    public function validationWillFailNotFailWhenNotValidYetButWithinLeeway()
194
    {
195
        $key = new JwtKey(['secret' => 'Buy the book', 'leeway' => 3]);
196
        $key->validateClaims(['sub' => 'john', 'nbf' => time() + 2]);
197
    }
198
199
    /**
200
     * @test
201
     * @expectedException \InvalidArgumentException
202
     */
203
    public function validationWillFailWhenIssuerDoesNotMatch()
204
    {
205
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
206
        $key->validateClaims(['sub' => 'john', 'iss' => 'you']);
207
    }
208
209
    /**
210
     * @test
211
     * @expectedException \InvalidArgumentException
212
     */
213
    public function validationWillFailWhenAudienceDoesNotMatch()
214
    {
215
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => 'me']);
216
        $key->validateClaims(['sub' => 'john', 'aud' => 'the neighbours']);
217
    }
218
219
220
    /**
221
     * @test
222
     * @expectedException \InvalidArgumentException
223
     */
224
    public function validationWillFailWhenIssuerIsConfiguredAndNotInClaims()
225
    {
226
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
227
        $key->validateClaims(['sub' => 'john']);
228
    }
229
230
    /**
231
     * @test
232
     * @expectedException \InvalidArgumentException
233
     */
234
    public function validationWillFailWhenMinIssueTimeIsConfiguredAndIatNotInClaims()
235
    {
236
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time()]);
237
        $key->validateClaims(['sub' => 'john']);
238
    }
239
240
    /**
241
     * @test
242
     * @expectedException \InvalidArgumentException
243
     */
244
    public function validationWillFailWhenAudienceIsConfiguredAndNotInClaims()
245
    {
246
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => time()]);
247
        $key->validateClaims(['sub' => 'john']);
248
    }
249
250
    /**
251
     * @test
252
     * @expectedException \InvalidArgumentException
253
     */
254
    public function validationWillFailWhenIgnoreOtherReservedAndArbitraryClaimsAreRequiredButNotInClaims()
255
    {
256
        $key = new JwtKey(
257
            ['secret' => 'Buy the book', 'require' => ['jti', 'typ', 'and now for something completely different']]
258
        );
259
        $key->validateClaims(['sub' => 'john']);
260
    }
261
262
    /**
263
     * @test
264
     * @expectedException \InvalidArgumentException
265
     */
266
    public function headerValidationWillFailWhenAlgoIsMissing()
267
    {
268
        $key = new JwtKey(
269
            ['secret' => 'Buy the book']
270
        );
271
        $key->validateHeader(['typ' => 'JWT']);
272
    }
273
274
    /**
275
     * @test
276
     * @expectedException \InvalidArgumentException
277
     */
278
    public function headerValidationWillFailWhenTypeIsMissing()
279
    {
280
        $key = new JwtKey(
281
            ['secret' => 'Buy the book']
282
        );
283
        $key->validateHeader(['alg' => JwtKey::TYPE_HMAC]);
284
    }
285
286
    /**
287
     * @test
288
     * @expectedException \InvalidArgumentException
289
     */
290
    public function headerValidationWillFailWhenAlgorithmDoesntMatchKey()
291
    {
292
        $key = new JwtKey(
293
            ['secret' => 'Buy the book']
294
        );
295
        $key->validateHeader(['alg' => JwtKey::TYPE_RSA]);
296
    }
297
298
    /**
299
     * @test
300
     * @expectedException \InvalidArgumentException
301
     */
302
    public function headerValidationWillFailWhenTypeIsNotJwt()
303
    {
304
        $key = new JwtKey(
305
            ['secret' => 'Buy the book']
306
        );
307
        $key->validateHeader(['typ' => 'Something']);
308
    }
309
310
    /**
311
     * @param string      $secret
312
     * @param JwtKey|null $key
313
     *
314
     * @return JwtToken
315
     */
316
    private function createTokenMock($secret, JwtKey $key = null)
317
    {
318
        /** @var JwtToken $token */
319
        $token = $tokenMock = $this->getMockBuilder(
320
            'KleijnWeb\JwtBundle\Authenticator\JwtToken'
321
        )->disableOriginalConstructor()->getMock();
322
323
        $tokenMock->expects($this->once())
324
            ->method('validateSignature')
325
            ->with($secret, $key ? $key->getSignatureValidator() : $this->anything());
326
327
        $tokenMock->expects($this->once())
328
            ->method('getClaims')
329
            ->willReturn(['sub' => 'john']);
330
331
        $tokenMock->expects($this->once())
332
            ->method('getHeader')
333
            ->willReturn(['alg' => JwtKey::TYPE_HMAC, 'typ' => 'JWT']);
334
335
        return $token;
336
    }
337
}
338