Completed
Pull Request — master (#15)
by Oguzhan
11:29
created

AuthenticatorTest::createToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 1
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\Authenticator;
11
use KleijnWeb\JwtBundle\Authenticator\JwtKey;
12
use KleijnWeb\JwtBundle\Authenticator\JwtToken;
13
use KleijnWeb\JwtBundle\User\UserInterface;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
16
use Symfony\Component\Security\Core\User\User;
17
18
/**
19
 * @author John Kleijn <[email protected]>
20
 */
21
class AuthenticatorTest extends \PHPUnit_Framework_TestCase
22
{
23
    // @codingStandardsIgnoreStart
24
25
    /**
26
     * Created using jwt.io
27
     */
28
    const TEST_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleU9uZSJ9.eyJwcm4iOiJqb2huIiwiaXNzIjoiaHR0cDovL2FwaS5zZXJ2ZXIxLmNvbS9vYXV0aDIvdG9rZW4ifQ._jXjAWMzwwG1v5N3ZOEUoLGSINtmwLsvQdfYkYAcWiY';
29
30
    const JKEY_CLASS = 'KleijnWeb\JwtBundle\Authenticator\JwtKey';
31
32
    /**
33
     * @var array
34
     */
35
    private static $keyConfig = [
36
        'keyOne' =>
37
            [
38
                'issuer' => 'http://api.server1.com/oauth2/token',
39
                'secret' => 'A Pre-Shared Key',
40
                'type'   => 'HS256',
41
            ],
42
        'keyTwo' =>
43
            [
44
                'issuer' => 'http://api.server2.com/oauth2/token',
45
                'type'   => 'RS256',
46
                'secret' => 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0F',
47
            ],
48
    ];
49
50
    // @codingStandardsIgnoreEnd
51
52
    /**
53
     * @var JwtKey[]
54
     */
55
    private $keys = [];
56
57
    protected function setUp()
58
    {
59
        foreach (self::$keyConfig as $keyId => $config) {
60
            $config['kid']      = $keyId;
61
            $this->keys[$keyId] = new JwtKey($config);
62
        }
63
    }
64
65
    /**
66
     * @test
67
     */
68
    public function getGetKeysUsingIndexesInConfig()
69
    {
70
        $authenticator = new Authenticator($this->keys);
71
72
        $this->assertInstanceOf(self::JKEY_CLASS, $authenticator->getKeyById('keyOne'));
73
        $this->assertInstanceOf(self::JKEY_CLASS, $authenticator->getKeyById('keyTwo'));
74
    }
75
76
    /**
77
     * @test
78
     */
79
    public function willGetSingleKeyWhenKeyIdIsNull()
80
    {
81
        $config = $this->keys;
82
        unset($config['keyTwo']);
83
84
        $authenticator = new Authenticator($config);
85
86
        $this->assertInstanceOf(self::JKEY_CLASS, $authenticator->getKeyById(null));
87
    }
88
89
    /**
90
     * @test
91
     * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationException
92
     */
93
    public function willFailWhenTryingToGetKeyWithoutIdWhenThereAreMoreThanOne()
94
    {
95
        $authenticator = new Authenticator($this->keys);
96
97
        $this->assertInstanceOf(self::JKEY_CLASS, $authenticator->getKeyById(null));
98
    }
99
100
    /**
101
     * @test
102
     * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationException
103
     */
104
    public function willFailWhenTryingToGetUnknownKey()
105
    {
106
        $authenticator = new Authenticator($this->keys);
107
108
        $this->assertInstanceOf(self::JKEY_CLASS, $authenticator->getKeyById('blah'));
109
    }
110
111
    /**
112
     * @test
113
     */
114
    public function authenticateTokenWillSetUserFetchedFromUserProviderOnToken()
115
    {
116
        $jwtToken      = $this->createToken(['sub' => 'john']);
117
        $authenticator = new Authenticator($this->keys);
118
        $anonToken     = new PreAuthenticatedToken('foo', $jwtToken, 'myprovider');
119
120
        $userProvider = $this->getMockBuilder(
121
            'Symfony\Component\Security\Core\User\UserProviderInterface'
122
        )->getMockForAbstractClass();
123
124
        $userProvider->expects($this->once())
125
            ->method('loadUserByUsername')
126
            ->with('john')
127
            ->willReturn(new User('john', 'hi there'));
128
129
        $authenticator->authenticateToken($anonToken, $userProvider, 'myprovider');
130
    }
131
132
    /**
133
     * @test
134
     * @expectedException \UnexpectedValueException
135
     */
136 View Code Duplication
    public function authenticateTokenWillFailIfCredentialsAreNotJwtToken()
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
        $authenticator = new Authenticator($this->keys);
139
        $anonToken     = new PreAuthenticatedToken('foo', ['sub' => 'john'], 'myprovider');
140
141
        $userProvider = $this->getMockBuilder(
142
            'Symfony\Component\Security\Core\User\UserProviderInterface'
143
        )->getMockForAbstractClass();
144
145
        $authenticator->authenticateToken($anonToken, $userProvider, 'myprovider');
146
    }
147
148
    /**
149
     * @test
150
     */
151 View Code Duplication
    public function supportsPreAuthToken()
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...
152
    {
153
        $authenticator = new Authenticator($this->keys);
154
155
        $securityToken = new PreAuthenticatedToken('foo', 'bar', 'myprovider');
156
        $actual        = $authenticator->supportsToken($securityToken, 'myprovider');
157
        $this->assertTrue($actual);
158
    }
159
160
    /**
161
     * @test
162
     * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
163
     */
164
    public function willFailWhenApiKeyNotFoundInHeader()
165
    {
166
        $authenticator = new Authenticator($this->keys);
167
        $request       = new Request();
168
        $authenticator->createToken($request, 'myprovider');
169
    }
170
171
    /**
172
     * @test
173
     */
174
    public function canGetAnonTokenWithClaims()
175
    {
176
        $authenticator = new Authenticator($this->keys);
177
        $request       = new Request();
178
        $request->headers->set('Authorization', 'Bearer ' . self::TEST_TOKEN);
179
        $token = $authenticator->createToken($request, 'myprovider');
180
181
        $expected = new JwtToken(self::TEST_TOKEN);
182
        $this->assertEquals($expected, $token->getCredentials());
183
    }
184
185
    /**
186
     * @test
187
     */
188
    public function willAddRolesFromAudienceClaimsInToken()
189
    {
190
        $authenticator = new Authenticator($this->keys);
191
        $token         = $this->createToken(['sub' => 'john', 'aud' => 'guests']);
192
        $anonToken     = new PreAuthenticatedToken('foo', $token, 'myprovider');
193
194
        $user          = $this->getMockBuilder(
195
            'KleijnWeb\JwtBundle\User\UserInterface'
196
        )->getMockForAbstractClass();
197
198
        $userProvider = $this->getMockBuilder(
199
            'Symfony\Component\Security\Core\User\UserProviderInterface'
200
        )->getMockForAbstractClass();
201
202
        $userProvider->expects($this->once())
203
            ->method('loadUserByUsername')
204
            ->willReturn($user);
205
206
        $user->expects($this->once())
207
            ->method('addRole')
208
            ->with('guests');
209
210
        $user->expects($this->once())
211
            ->method('getRoles')
212
            ->willReturn(['guests']);
213
214
        $authenticator->authenticateToken($anonToken, $userProvider, 'myprovider');
215
    }
216
217
    /**
218
     * @test
219
     */
220
    public function willAddMultipleRolesFromAudienceClaimsInToken()
221
    {
222
        $authenticator = new Authenticator($this->keys);
223
        $token         = $this->createToken(['sub' => 'john', 'aud' => ['guests', 'users']]);
224
        $anonToken     = new PreAuthenticatedToken('foo', $token, 'myprovider');
225
226
        $user          = $this->getMockBuilder(
227
            'KleijnWeb\JwtBundle\User\UserInterface'
228
        )->getMockForAbstractClass();
229
230
        $userProvider = $this->getMockBuilder(
231
            'Symfony\Component\Security\Core\User\UserProviderInterface'
232
        )->getMockForAbstractClass();
233
234
        $userProvider->expects($this->once())
235
            ->method('loadUserByUsername')
236
            ->willReturn($user);
237
238
        $user->expects($this->exactly(2))
239
            ->method('addRole');
240
241
        $user->expects($this->once())
242
            ->method('getRoles')
243
            ->willReturn(['guests', 'users']);
244
245
        $authenticator->authenticateToken($anonToken, $userProvider, 'myprovider');
246
    }
247
248
    /**
249
     * @param array $claims
250
     *
251
     * @return JwtToken
252
     */
253
    private function createToken(array $claims)
254
    {
255
        return new JwtToken([
256
            'header' => [
257
                'alg' => 'HS256',
258
                'typ' => 'JWT',
259
                'kid' => 'keyOne'
260
            ],
261
            'claims' => $claims,
262
            'secret' => 'secret'
263
        ]);
264
    }
265
}
266