Completed
Push — master ( 3ef1d3...dea670 )
by John
02:57
created

supportsJwtAuthenticationToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
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\Authentication;
9
10
use KleijnWeb\JwtBundle\Authentication\JwtAuthenticatedToken;
11
use KleijnWeb\JwtBundle\Authentication\JwtAuthenticationProvider;
12
use KleijnWeb\JwtBundle\Authentication\JwtAuthenticationToken;
13
use KleijnWeb\JwtBundle\Jwt\JwtKey;
14
use KleijnWeb\JwtBundle\Jwt\JwtToken;
15
use KleijnWeb\JwtBundle\User\JwtUserProvider;
16
use KleijnWeb\JwtBundle\User\UnsafeGroupsUserInterface;
17
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
18
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
19
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
20
use Symfony\Component\Security\Core\User\User;
21
use Symfony\Component\Security\Core\User\UserProviderInterface;
22
23
/**
24
 * @author John Kleijn <[email protected]>
25
 */
26
class JwtAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
27
{
28
    const ISSUER = 'http://api.server1.com/oauth2/token';
29
    const SECRET = 'A Pre-Shared Key';
30
31
    // @codingStandardsIgnoreStart
32
    /**
33
     * Created using jwt.io
34
     */
35
    const TEST_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleU9uZSJ9.eyJwcm4iOiJqb2huIiwiaXNzIjoiaHR0cDovL2FwaS5zZXJ2ZXIxLmNvbS9vYXV0aDIvdG9rZW4ifQ._jXjAWMzwwG1v5N3ZOEUoLGSINtmwLsvQdfYkYAcWiY';
36
    // @codingStandardsIgnoreEnd
37
38
    /**
39
     * @var array
40
     */
41
    private static $keyConfig = [
42
        'keyOne' =>
43
            [
44
                'issuer' => self::ISSUER,
45
                'secret' => self::SECRET,
46
                'type'   => 'HS256',
47
            ],
48
        'keyTwo' =>
49
            [
50
                'issuer' => self::ISSUER,
51
                'type'   => 'RS256',
52
                'secret' => 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0F',
53
            ],
54
    ];
55
56
    /**
57
     * @var JwtKey[]
58
     */
59
    private $keys = [];
60
61
    /**
62
     * @var UserProviderInterface
63
     */
64
    private $standardUserProviderMock;
65
66
    protected function setUp()
67
    {
68
        foreach (self::$keyConfig as $keyId => $config) {
69
            $config['kid']      = $keyId;
70
            $this->keys[$keyId] = new JwtKey($config);
71
        }
72
73
        $this->standardUserProviderMock = $this->getMockForAbstractClass(UserProviderInterface::class);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getMockForAbstrac...oviderInterface::class) of type object<PHPUnit_Framework_MockObject_MockObject> is incompatible with the declared type object<Symfony\Component...\UserProviderInterface> of property $standardUserProviderMock.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
74
    }
75
76
    /**
77
     * @test
78
     */
79
    public function getGetKeysUsingIndexesInConfig()
80
    {
81
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
82
83
        $this->assertInstanceOf(JwtKey::class, $jwtAuthenticationProvider->getKeyById('keyOne'));
84
        $this->assertInstanceOf(JwtKey::class, $jwtAuthenticationProvider->getKeyById('keyTwo'));
85
    }
86
87
    /**
88
     * @test
89
     */
90
    public function willGetSingleKeyWhenKeyIdIsNull()
91
    {
92
        $config = $this->keys;
93
        unset($config['keyTwo']);
94
95
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $config);
96
97
        $this->assertInstanceOf(JwtKey::class, $jwtAuthenticationProvider->getKeyById(null));
98
    }
99
100
    /**
101
     * @test
102
     * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationException
103
     */
104
    public function willFailWhenTryingToGetKeyWithoutIdWhenThereAreMoreThanOne()
105
    {
106
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
107
108
        $this->assertInstanceOf(JwtKey::class, $jwtAuthenticationProvider->getKeyById(null));
109
    }
110
111
    /**
112
     * @test
113
     * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationException
114
     */
115
    public function willFailWhenTryingToGetUnknownKey()
116
    {
117
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
118
119
        $this->assertInstanceOf(JwtKey::class, $jwtAuthenticationProvider->getKeyById('blah'));
120
    }
121
122
    /**
123
     * @test
124
     */
125
    public function supportsJwtAuthenticationToken()
126
    {
127
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
128
129
        $this->assertTrue($jwtAuthenticationProvider->supports(new JwtAuthenticationToken()));
130
    }
131
132
    /**
133
     * @test
134
     */
135
    public function doesNotSupportAnonToken()
136
    {
137
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
138
139
        $this->assertFalse($jwtAuthenticationProvider->supports(new AnonymousToken('secret', 'john')));
140
    }
141
142
    /**
143
     * @test
144
     */
145 View Code Duplication
    public function authenticateTokenWillThrowExceptionWhenTokenUnsupportedType()
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
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
148
        $anonToken                 = new PreAuthenticatedToken('foo', '', 'myprovider');
149
150
        $this->expectException(\LogicException::class);
151
152
        $jwtAuthenticationProvider->authenticate($anonToken);
153
    }
154
155
    /**
156
     * @test
157
     */
158 View Code Duplication
    public function authenticateWillReturnAuthenticatedToken()
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...
159
    {
160
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
161
        $authToken                 = new JwtAuthenticationToken([], self::TEST_TOKEN);
162
163
        /** @var \PHPUnit_Framework_MockObject_MockObject $mock */
164
        $mock = $this->standardUserProviderMock;
165
        $mock
166
            ->expects($this->once())
167
            ->method('loadUserByUsername')
168
            ->willReturn(new User('john', 'hi there'));
169
170
        $this->assertInstanceOf(JwtAuthenticatedToken::class, $jwtAuthenticationProvider->authenticate($authToken));
171
    }
172
173
    /**
174
     * @test
175
     */
176 View Code Duplication
    public function authenticateTokenWillSetUserFetchedFromUserProviderOnToken()
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...
177
    {
178
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
179
        $authToken                 = new JwtAuthenticationToken([], self::TEST_TOKEN);
180
181
        /** @var \PHPUnit_Framework_MockObject_MockObject $mock */
182
        $mock = $this->standardUserProviderMock;
183
        $mock
184
            ->expects($this->once())
185
            ->method('loadUserByUsername')
186
            ->with('john')
187
            ->willReturn(new User('john', 'hi there'));
188
189
        $jwtAuthenticationProvider->authenticate($authToken);
190
    }
191
192
    /**
193
     * @test
194
     * @expectedException \UnexpectedValueException
195
     */
196 View Code Duplication
    public function authenticateTokenWillFailWhenTokenStringInvalid()
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...
197
    {
198
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
199
        $authToken                 = new JwtAuthenticationToken([], 'invalid');
200
201
        $this->expectException(BadCredentialsException::class);
202
203
        $jwtAuthenticationProvider->authenticate($authToken);
204
    }
205
206
    /**
207
     * @test
208
     * @expectedException \UnexpectedValueException
209
     */
210 View Code Duplication
    public function authenticateTokenWillWillNotCallUserProviderWhenTokenStringInvalid()
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...
211
    {
212
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
213
        $authToken                 = new JwtAuthenticationToken([], 'invalid');
214
215
        /** @var \PHPUnit_Framework_MockObject_MockObject $mock */
216
        $mock = $this->standardUserProviderMock;
217
        $mock
218
            ->expects($this->never())
219
            ->method('loadUserByUsername')
220
            ->with('john')
221
            ->willReturn(new User('john', 'hi there'));
222
223
        $this->expectException(BadCredentialsException::class);
224
225
        $jwtAuthenticationProvider->authenticate($authToken);
226
    }
227
228
    /**
229
     * @test
230
     */
231
    public function willSetClaimsOnJwtUserProvider()
232
    {
233
        $userProvider = $this->getMockBuilder(JwtUserProvider::class)->disableOriginalConstructor()->getMock();
234
235
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($userProvider, $this->keys);
236
        $authToken                 = new JwtAuthenticationToken([], self::TEST_TOKEN);
237
238
        $user = $this->getMockBuilder(UnsafeGroupsUserInterface::class)->getMockForAbstractClass();
239
240
        $userProvider
241
            ->expects($this->once())
242
            ->method('loadUserByUsername')
243
            ->willReturn($user);
244
245
        $userProvider
246
            ->expects($this->once())
247
            ->method('setClaimsUsingToken')
248
            ->with($this->isInstanceOf(JwtToken::class));
249
250
        $user->expects($this->once())
251
            ->method('getRoles')
252
            ->willReturn(['ROLE_GUESTS']);
253
254
        $jwtAuthenticationProvider->authenticate($authToken);
255
    }
256
257
    /**
258
     * @deprecated
259
     * @test
260
     */
261
    public function willAddRolesFromAudienceClaimsInToken()
262
    {
263
        $token = $this->createToken(['sub' => 'john', 'aud' => 'guests', 'iss' => self::ISSUER]);
264
265
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
266
        $authToken                 = new JwtAuthenticationToken([], $token->getTokenString());
267
268
        $user = $this->getMockBuilder(UnsafeGroupsUserInterface::class)->getMockForAbstractClass();
269
270
        /** @var \PHPUnit_Framework_MockObject_MockObject $mock */
271
        $mock = $this->standardUserProviderMock;
272
        $mock
273
            ->expects($this->once())
274
            ->method('loadUserByUsername')
275
            ->willReturn($user);
276
277
        $user
278
            ->expects($this->once())
279
            ->method('addRole');
280
281
        $user->expects($this->once())
282
            ->method('getRoles')
283
            ->willReturn(['ROLE_GUESTS']);
284
285
        $jwtAuthenticationProvider->authenticate($authToken);
286
    }
287
288
    /**
289
     * @deprecated
290
     * @test
291
     */
292
    public function willAddMultipleRolesFromAudienceClaimsInToken()
293
    {
294
        $token = $this->createToken(['sub' => 'john', 'aud' => ['guests', 'users'], 'iss' => self::ISSUER]);
295
296
        $jwtAuthenticationProvider = new JwtAuthenticationProvider($this->standardUserProviderMock, $this->keys);
297
        $authToken                 = new JwtAuthenticationToken([], $token->getTokenString());
298
299
        $user = $this->getMockBuilder(UnsafeGroupsUserInterface::class)->getMockForAbstractClass();
300
301
        /** @var \PHPUnit_Framework_MockObject_MockObject $mock */
302
        $mock = $this->standardUserProviderMock;
303
        $mock
304
            ->expects($this->once())
305
            ->method('loadUserByUsername')
306
            ->willReturn($user);
307
308
        $user->expects($this->exactly(2))
309
            ->method('addRole');
310
311
        $user
312
            ->expects($this->once())
313
            ->method('getRoles')
314
            ->willReturn(['ROLE_GUESTS', 'ROLE_USERS']);
315
316
        $jwtAuthenticationProvider->authenticate($authToken);
317
    }
318
319
    /**
320
     * @param array $claims
321
     *
322
     * @return JwtToken
323
     */
324 View Code Duplication
    private function createToken(array $claims)
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...
325
    {
326
        return new JwtToken([
327
            'header' => [
328
                'alg' => 'HS256',
329
                'typ' => 'JWT',
330
                'kid' => 'keyOne'
331
            ],
332
            'claims' => $claims,
333
            'secret' => self::SECRET
334
        ]);
335
    }
336
}
337