Completed
Push — master ( ee280a...529931 )
by John
01:02 queued 57s
created

validateTokenWillCallVerifySignatureOnToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 4
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 validationWillFailWhenExpiredByIatAndMinIssueTime()
166
    {
167
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time() + 2]);
168
        $key->validateClaims(['sub' => 'john', 'iat' => time()]);
169
    }
170
171
    /**
172
     * @test
173
     * @expectedException \InvalidArgumentException
174
     */
175
    public function validationWillFailWhenNotValidYet()
176
    {
177
        $key = new JwtKey(['secret' => 'Buy the book']);
178
        $key->validateClaims(['sub' => 'john', 'nbf' => time() + 2]);
179
    }
180
181
    /**
182
     * @test
183
     * @expectedException \InvalidArgumentException
184
     */
185
    public function validationWillFailWhenIssuerDoesNotMatch()
186
    {
187
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
188
        $key->validateClaims(['sub' => 'john', 'iss' => 'you']);
189
    }
190
191
    /**
192
     * @test
193
     * @expectedException \InvalidArgumentException
194
     */
195
    public function validationWillFailWhenAudienceDoesNotMatch()
196
    {
197
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => 'me']);
198
        $key->validateClaims(['sub' => 'john', 'aud' => 'the neighbours']);
199
    }
200
201
202
    /**
203
     * @test
204
     * @expectedException \InvalidArgumentException
205
     */
206
    public function validationWillFailWhenIssuerIsConfiguredAndNotInClaims()
207
    {
208
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
209
        $key->validateClaims(['sub' => 'john']);
210
    }
211
212
    /**
213
     * @test
214
     * @expectedException \InvalidArgumentException
215
     */
216
    public function validationWillFailWhenMinIssueTimeIsConfiguredAndIatNotInClaims()
217
    {
218
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time()]);
219
        $key->validateClaims(['sub' => 'john']);
220
    }
221
222
    /**
223
     * @test
224
     * @expectedException \InvalidArgumentException
225
     */
226
    public function validationWillFailWhenAudienceIsConfiguredAndNotInClaims()
227
    {
228
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => time()]);
229
        $key->validateClaims(['sub' => 'john']);
230
    }
231
232
    /**
233
     * @test
234
     * @expectedException \InvalidArgumentException
235
     */
236
    public function validationWillFailWhenIgnoreOtherReservedAndArbitraryClaimsAreRequiredButNotInClaims()
237
    {
238
        $key = new JwtKey(
239
            ['secret' => 'Buy the book', 'require' => ['jti', 'typ', 'and now for something completely different']]
240
        );
241
        $key->validateClaims(['sub' => 'john']);
242
    }
243
244
    /**
245
     * @test
246
     * @expectedException \InvalidArgumentException
247
     */
248
    public function headerValidationWillFailWhenAlgoIsMissing()
249
    {
250
        $key = new JwtKey(
251
            ['secret' => 'Buy the book']
252
        );
253
        $key->validateHeader(['typ' => 'JWT']);
254
    }
255
256
    /**
257
     * @test
258
     * @expectedException \InvalidArgumentException
259
     */
260
    public function headerValidationWillFailWhenTypeIsMissing()
261
    {
262
        $key = new JwtKey(
263
            ['secret' => 'Buy the book']
264
        );
265
        $key->validateHeader(['alg' => JwtKey::TYPE_HMAC]);
266
    }
267
268
    /**
269
     * @test
270
     * @expectedException \InvalidArgumentException
271
     */
272
    public function headerValidationWillFailWhenAlgorithmDoesntMatchKey()
273
    {
274
        $key = new JwtKey(
275
            ['secret' => 'Buy the book']
276
        );
277
        $key->validateHeader(['alg' => JwtKey::TYPE_RSA]);
278
    }
279
280
    /**
281
     * @test
282
     * @expectedException \InvalidArgumentException
283
     */
284
    public function headerValidationWillFailWhenTypeIsNotJwt()
285
    {
286
        $key = new JwtKey(
287
            ['secret' => 'Buy the book']
288
        );
289
        $key->validateHeader(['typ' => 'Something']);
290
    }
291
292
    /**
293
     * @param string      $secret
294
     * @param JwtKey|null $key
295
     *
296
     * @return JwtToken
297
     */
298
    private function createTokenMock($secret, JwtKey $key = null)
299
    {
300
        /** @var JwtToken $token */
301
        $token = $tokenMock = $this->getMockBuilder(
302
            'KleijnWeb\JwtBundle\Authenticator\JwtToken'
303
        )->disableOriginalConstructor()->getMock();
304
305
        $tokenMock->expects($this->once())
306
            ->method('validateSignature')
307
            ->with($secret, $key ? $key->getSignatureValidator() : $this->anything());
308
309
        $tokenMock->expects($this->once())
310
            ->method('getClaims')
311
            ->willReturn(['sub' => 'john']);
312
313
        $tokenMock->expects($this->once())
314
            ->method('getHeader')
315
            ->willReturn(['alg' => JwtKey::TYPE_HMAC, 'typ' => 'JWT']);
316
317
        return $token;
318
    }
319
}
320