Completed
Pull Request — master (#7)
by John
02:17
created

JwtKeyTest   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 276
Duplicated Lines 6.52 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
c 2
b 0
f 0
lcom 1
cbo 3
dl 18
loc 276
rs 10

23 Methods

Rating   Name   Duplication   Size   Complexity  
A constructionWillFailWhenSecretNorLoaderPassed() 0 4 1
A canOmitSecretWhenPassingLoader() 0 8 1
A cannotPassBothSecretAndLoader() 0 4 1
A serializingWillClearSecret() 0 9 1
A validateTokenWillCallVerifySignatureOnToken() 0 6 1
A canLoadSecretFromLoader() 0 12 1
A willGetRsaSignatureValidatorWhenTypeIsNotSpecified() 9 9 1
A willGetRsaSignatureValidatorWhenTypeIsRsa() 9 9 1
A validationWillFailWhenPrincipleIsMissing() 0 5 1
A validationWillFailWhenExpiredByExp() 0 5 1
A validationWillFailWhenExpiredByIatAndMinIssueTime() 0 5 1
A validationWillFailWhenNotValidYet() 0 5 1
A validationWillFailWhenIssuerDoesNotMatch() 0 5 1
A validationWillFailWhenAudienceDoesNotMatch() 0 5 1
A validationWillFailWhenIssuerIsConfiguredAndNotInClaims() 0 5 1
A validationWillFailWhenMinIssueTimeIsConfiguredAndIatNotInClaims() 0 5 1
A validationWillFailWhenAudienceIsConfiguredAndNotInClaims() 0 5 1
A validationWillFailWhenIgnoreOtherReservedAndArbitraryClaimsAreRequiredButNotInClaims() 0 7 1
A headerValidationWillFailWhenAlgoIsMissing() 0 7 1
A headerValidationWillFailWhenTypeIsMissing() 0 7 1
A headerValidationWillFailWhenAlgorithmDoesntMatchKey() 0 7 1
A headerValidationWillFailWhenTypeIsNotJwt() 0 7 1
A createTokenMock() 0 21 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
     * @expectedException \InvalidArgumentException
116
     */
117
    public function validationWillFailWhenPrincipleIsMissing()
118
    {
119
        $key = new JwtKey(['secret' => 'Buy the book']);
120
        $key->validateClaims([]);
121
    }
122
123
    /**
124
     * @test
125
     * @expectedException \InvalidArgumentException
126
     */
127
    public function validationWillFailWhenExpiredByExp()
128
    {
129
        $key = new JwtKey(['secret' => 'Buy the book']);
130
        $key->validateClaims(['prn' => 'john', 'exp' => time() - 2]);
131
    }
132
133
    /**
134
     * @test
135
     * @expectedException \InvalidArgumentException
136
     */
137
    public function validationWillFailWhenExpiredByIatAndMinIssueTime()
138
    {
139
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time() + 2]);
140
        $key->validateClaims(['prn' => 'john', 'iat' => time()]);
141
    }
142
143
    /**
144
     * @test
145
     * @expectedException \InvalidArgumentException
146
     */
147
    public function validationWillFailWhenNotValidYet()
148
    {
149
        $key = new JwtKey(['secret' => 'Buy the book']);
150
        $key->validateClaims(['prn' => 'john', 'nbf' => time() + 2]);
151
    }
152
153
    /**
154
     * @test
155
     * @expectedException \InvalidArgumentException
156
     */
157
    public function validationWillFailWhenIssuerDoesNotMatch()
158
    {
159
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
160
        $key->validateClaims(['prn' => 'john', 'iss' => 'you']);
161
    }
162
163
    /**
164
     * @test
165
     * @expectedException \InvalidArgumentException
166
     */
167
    public function validationWillFailWhenAudienceDoesNotMatch()
168
    {
169
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => 'me']);
170
        $key->validateClaims(['prn' => 'john', 'aud' => 'the neighbours']);
171
    }
172
173
174
    /**
175
     * @test
176
     * @expectedException \InvalidArgumentException
177
     */
178
    public function validationWillFailWhenIssuerIsConfiguredAndNotInClaims()
179
    {
180
        $key = new JwtKey(['secret' => 'Buy the book', 'issuer' => 'me']);
181
        $key->validateClaims(['prn' => 'john']);
182
    }
183
184
    /**
185
     * @test
186
     * @expectedException \InvalidArgumentException
187
     */
188
    public function validationWillFailWhenMinIssueTimeIsConfiguredAndIatNotInClaims()
189
    {
190
        $key = new JwtKey(['secret' => 'Buy the book', 'minIssueTime' => time()]);
191
        $key->validateClaims(['prn' => 'john']);
192
    }
193
194
    /**
195
     * @test
196
     * @expectedException \InvalidArgumentException
197
     */
198
    public function validationWillFailWhenAudienceIsConfiguredAndNotInClaims()
199
    {
200
        $key = new JwtKey(['secret' => 'Buy the book', 'audience' => time()]);
201
        $key->validateClaims(['prn' => 'john']);
202
    }
203
204
    /**
205
     * @test
206
     * @expectedException \InvalidArgumentException
207
     */
208
    public function validationWillFailWhenIgnoreOtherReservedAndArbitraryClaimsAreRequiredButNotInClaims()
209
    {
210
        $key = new JwtKey(
211
            ['secret' => 'Buy the book', 'require' => ['jti', 'typ', 'and now for something completely different']]
212
        );
213
        $key->validateClaims(['prn' => 'john']);
214
    }
215
216
    /**
217
     * @test
218
     * @expectedException \InvalidArgumentException
219
     */
220
    public function headerValidationWillFailWhenAlgoIsMissing()
221
    {
222
        $key = new JwtKey(
223
            ['secret' => 'Buy the book']
224
        );
225
        $key->validateHeader(['typ' => 'JWT']);
226
    }
227
228
    /**
229
     * @test
230
     * @expectedException \InvalidArgumentException
231
     */
232
    public function headerValidationWillFailWhenTypeIsMissing()
233
    {
234
        $key = new JwtKey(
235
            ['secret' => 'Buy the book']
236
        );
237
        $key->validateHeader(['alg' => JwtKey::TYPE_HMAC]);
238
    }
239
240
    /**
241
     * @test
242
     * @expectedException \InvalidArgumentException
243
     */
244
    public function headerValidationWillFailWhenAlgorithmDoesntMatchKey()
245
    {
246
        $key = new JwtKey(
247
            ['secret' => 'Buy the book']
248
        );
249
        $key->validateHeader(['alg' => JwtKey::TYPE_RSA]);
250
    }
251
252
    /**
253
     * @test
254
     * @expectedException \InvalidArgumentException
255
     */
256
    public function headerValidationWillFailWhenTypeIsNotJwt()
257
    {
258
        $key = new JwtKey(
259
            ['secret' => 'Buy the book']
260
        );
261
        $key->validateHeader(['typ' => 'Something']);
262
    }
263
264
    /**
265
     * @param string      $secret
266
     * @param JwtKey|null $key
267
     *
268
     * @return JwtToken
269
     */
270
    private function createTokenMock($secret, JwtKey $key = null)
271
    {
272
        /** @var JwtToken $token */
273
        $token = $tokenMock = $this->getMockBuilder(
274
            'KleijnWeb\JwtBundle\Authenticator\JwtToken'
275
        )->disableOriginalConstructor()->getMock();
276
277
        $tokenMock->expects($this->once())
278
            ->method('validateSignature')
279
            ->with($secret, $key ? $key->getSignatureValidator() : $this->anything());
280
281
        $tokenMock->expects($this->once())
282
            ->method('getClaims')
283
            ->willReturn(['prn' => 'john']);
284
285
        $tokenMock->expects($this->once())
286
            ->method('getHeader')
287
            ->willReturn(['alg' => JwtKey::TYPE_HMAC, 'typ' => 'JWT']);
288
289
        return $token;
290
    }
291
}
292