Completed
Push — master ( 28c8cd...7e44c6 )
by André
18:53
created

getUsernamePasswordTokenMock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the RestSessionBasedAuthenticatorTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\REST\Server\Tests\Security;
10
11
use eZ\Publish\API\Repository\Values\User\User;
12
use eZ\Publish\Core\MVC\ConfigResolverInterface;
13
use eZ\Publish\Core\REST\Server\Security\RestAuthenticator;
14
use eZ\Publish\Core\MVC\Symfony\Security\User as EzUser;
15
use PHPUnit\Framework\TestCase;
16
use Psr\Log\LoggerInterface;
17
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
21
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
22
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
23
use Symfony\Component\Security\Core\User\UserInterface;
24
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
25
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
26
use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;
27
use Symfony\Component\Security\Http\SecurityEvents;
28
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
29
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
30
31
class RestSessionBasedAuthenticatorTest extends TestCase
32
{
33
    const PROVIDER_KEY = 'test_key';
34
35
    /**
36
     * @var \PHPUnit_Framework_MockObject_MockObject
37
     */
38
    private $tokenStorage;
39
40
    /**
41
     * @var \PHPUnit_Framework_MockObject_MockObject
42
     */
43
    private $authenticationManager;
44
45
    /**
46
     * @var \PHPUnit_Framework_MockObject_MockObject
47
     */
48
    private $eventDispatcher;
49
50
    /**
51
     * @var \PHPUnit_Framework_MockObject_MockObject
52
     */
53
    private $configResolver;
54
55
    /**
56
     * @var \PHPUnit_Framework_MockObject_MockObject
57
     */
58
    private $sessionStorage;
59
60
    /**
61
     * @var \PHPUnit_Framework_MockObject_MockObject
62
     */
63
    private $logger;
64
65
    /**
66
     * @var \eZ\Publish\Core\REST\Server\Security\RestAuthenticator
67
     */
68
    private $authenticator;
69
70
    protected function setUp()
71
    {
72
        parent::setUp();
73
        $this->tokenStorage = $this->createMock(TokenStorageInterface::class);
74
        $this->authenticationManager = $this->createMock(AuthenticationManagerInterface::class);
75
        $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
76
        $this->configResolver = $this->createMock(ConfigResolverInterface::class);
77
        $this->sessionStorage = $this->createMock(SessionStorageInterface::class);
78
        $this->logger = $this->createMock(LoggerInterface::class);
79
        $this->authenticator = new RestAuthenticator(
80
            $this->tokenStorage,
81
            $this->authenticationManager,
82
            self::PROVIDER_KEY,
83
            $this->eventDispatcher,
84
            $this->configResolver,
85
            $this->sessionStorage,
86
            $this->logger
87
        );
88
    }
89
90
    public function testAuthenticateAlreadyHaveSessionToken()
91
    {
92
        $username = 'foo_user';
93
        $password = 'publish';
94
95
        $existingToken = $this->getTokenInterfaceMock();
96
        $this->tokenStorage
97
            ->expects($this->once())
98
            ->method('getToken')
99
            ->will($this->returnValue($existingToken));
100
101
        $existingToken
102
            ->expects($this->once())
103
            ->method('getUsername')
104
            ->will($this->returnValue($username));
105
        $existingToken
106
            ->expects($this->once())
107
            ->method('setAttribute')
108
            ->with('isFromSession', true);
109
110
        $request = new Request();
111
        $request->attributes->set('username', $username);
112
        $request->attributes->set('password', $password);
113
114
        $this->assertSame($existingToken, $this->authenticator->authenticate($request));
115
    }
116
117
    /**
118
     * @expectedException \Symfony\Component\Security\Core\Exception\TokenNotFoundException
119
     */
120
    public function testAuthenticateNoTokenFound()
121
    {
122
        $username = 'foo_user';
123
        $password = 'publish';
124
125
        $existingToken = $this->getTokenInterfaceMock();
126
        $this->tokenStorage
127
            ->expects($this->once())
128
            ->method('getToken')
129
            ->will($this->returnValue($existingToken));
130
131
        $existingToken
132
            ->expects($this->once())
133
            ->method('getUsername')
134
            ->will($this->returnValue(__METHOD__));
135
136
        $request = new Request();
137
        $request->attributes->set('username', $username);
138
        $request->attributes->set('password', $password);
139
140
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
141
        $this->authenticationManager
142
            ->expects($this->once())
143
            ->method('authenticate')
144
            ->with($this->equalTo($usernamePasswordToken))
145
            ->will($this->returnValue(null));
146
147
        $this->logger
148
            ->expects($this->once())
149
            ->method('error');
150
151
        $this->authenticator->authenticate($request);
152
    }
153
154
    /**
155
     * @expectedException \eZ\Publish\Core\REST\Server\Exceptions\InvalidUserTypeException
156
     */
157
    public function testAuthenticateInvalidUser()
158
    {
159
        $username = 'foo_user';
160
        $password = 'publish';
161
162
        $existingToken = $this->getTokenInterfaceMock();
163
        $existingToken
164
            ->expects($this->once())
165
            ->method('getUsername')
166
            ->will($this->returnValue(__METHOD__));
167
168
        $request = new Request();
169
        $request->attributes->set('username', $username);
170
        $request->attributes->set('password', $password);
171
172
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
173
        $authenticatedToken = $this->getUsernamePasswordTokenMock();
174
        $this->authenticationManager
175
            ->expects($this->once())
176
            ->method('authenticate')
177
            ->with($this->equalTo($usernamePasswordToken))
178
            ->will($this->returnValue($authenticatedToken));
179
180
        $this->tokenStorage
181
            ->expects($this->once())
182
            ->method('setToken')
183
            ->with($authenticatedToken);
184
185
        $this->eventDispatcher
186
            ->expects($this->once())
187
            ->method('dispatch')
188
            ->with(
189
                SecurityEvents::INTERACTIVE_LOGIN,
190
                $this->equalTo(new InteractiveLoginEvent($request, $authenticatedToken))
191
            );
192
193
        $this->tokenStorage
194
            ->expects($this->exactly(2))
195
            ->method('getToken')
196
            ->will(
197
                $this->onConsecutiveCalls($existingToken, $authenticatedToken)
198
            );
199
200
        $authenticatedToken
201
            ->expects($this->once())
202
            ->method('getUser')
203
            ->will($this->returnValue('not_an_ez_user'));
204
205
        $this->logger
206
            ->expects($this->once())
207
            ->method('error');
208
209
        $this->authenticator->authenticate($request);
210
    }
211
212
    /**
213
     * @param $userId
214
     *
215
     * @return EzUser
216
     */
217
    private function createUser($userId)
218
    {
219
        $apiUser = $this->createMock(User::class);
220
        $apiUser
221
            ->expects($this->any())
222
            ->method('getUserId')
223
            ->will($this->returnValue($userId));
224
225
        return new EzUser($apiUser);
226
    }
227
228
    /**
229
     * @expectedException \eZ\Publish\Core\REST\Server\Exceptions\UserConflictException
230
     */
231
    public function testAuthenticateUserConflict()
232
    {
233
        $username = 'foo_user';
234
        $password = 'publish';
235
236
        $existingUser = $this->createUser(123);
237
        $existingToken = $this->getUsernamePasswordTokenMock();
238
        $existingToken
239
            ->expects($this->once())
240
            ->method('getUsername')
241
            ->will($this->returnValue(__METHOD__));
242
        $existingToken
243
            ->expects($this->once())
244
            ->method('getUser')
245
            ->will($this->returnValue($existingUser));
246
247
        $request = new Request();
248
        $request->attributes->set('username', $username);
249
        $request->attributes->set('password', $password);
250
251
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
252
        $authenticatedToken = $this->getUsernamePasswordTokenMock();
253
        $this->authenticationManager
254
            ->expects($this->once())
255
            ->method('authenticate')
256
            ->with($this->equalTo($usernamePasswordToken))
257
            ->will($this->returnValue($authenticatedToken));
258
259
        $this->eventDispatcher
260
            ->expects($this->once())
261
            ->method('dispatch')
262
            ->with(
263
                SecurityEvents::INTERACTIVE_LOGIN,
264
                $this->equalTo(new InteractiveLoginEvent($request, $authenticatedToken))
265
            );
266
267
        $this->tokenStorage
268
            ->expects($this->at(0))
269
            ->method('getToken')
270
            ->will($this->returnValue($existingToken));
271
        $this->tokenStorage
272
            ->expects($this->at(1))
273
            ->method('setToken')
274
            ->with($authenticatedToken);
275
        $this->tokenStorage
276
            ->expects($this->at(2))
277
            ->method('getToken')
278
            ->will($this->returnValue($authenticatedToken));
279
        $this->tokenStorage
280
            ->expects($this->at(3))
281
            ->method('setToken')
282
            ->with($existingToken);
283
284
        $authenticatedUser = $this->createUser(456);
285
        $authenticatedToken
286
            ->expects($this->once())
287
            ->method('getUser')
288
            ->will($this->returnValue($authenticatedUser));
289
290
        $this->configResolver
291
            ->expects($this->once())
292
            ->method('getParameter')
293
            ->with('anonymous_user_id')
294
            ->will($this->returnValue(10));
295
296
        $this->authenticator->authenticate($request);
297
    }
298
299
    public function testAuthenticatePreviouslyAnonymous()
300
    {
301
        $username = 'foo_user';
302
        $password = 'publish';
303
304
        $anonymousUserId = 10;
305
        $existingUser = $this->createUser($anonymousUserId);
306
        $existingToken = $this->getUsernamePasswordTokenMock();
307
        $existingToken
308
            ->expects($this->once())
309
            ->method('getUsername')
310
            ->will($this->returnValue(__METHOD__));
311
        $existingToken
312
            ->expects($this->once())
313
            ->method('getUser')
314
            ->will($this->returnValue($existingUser));
315
316
        $request = new Request();
317
        $request->attributes->set('username', $username);
318
        $request->attributes->set('password', $password);
319
320
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
321
        $authenticatedToken = $this->getUsernamePasswordTokenMock();
322
        $this->authenticationManager
323
            ->expects($this->once())
324
            ->method('authenticate')
325
            ->with($this->equalTo($usernamePasswordToken))
326
            ->will($this->returnValue($authenticatedToken));
327
328
        $this->eventDispatcher
329
            ->expects($this->once())
330
            ->method('dispatch')
331
            ->with(
332
                SecurityEvents::INTERACTIVE_LOGIN,
333
                $this->equalTo(new InteractiveLoginEvent($request, $authenticatedToken))
334
            );
335
336
        $this->tokenStorage
337
            ->expects($this->at(0))
338
            ->method('getToken')
339
            ->will($this->returnValue($existingToken));
340
        $this->tokenStorage
341
            ->expects($this->at(1))
342
            ->method('setToken')
343
            ->with($authenticatedToken);
344
        $this->tokenStorage
345
            ->expects($this->at(2))
346
            ->method('getToken')
347
            ->will($this->returnValue($authenticatedToken));
348
349
        $authenticatedUser = $this->createUser(456);
350
        $authenticatedToken
351
            ->expects($this->once())
352
            ->method('getUser')
353
            ->will($this->returnValue($authenticatedUser));
354
355
        $this->configResolver
356
            ->expects($this->once())
357
            ->method('getParameter')
358
            ->with('anonymous_user_id')
359
            ->will($this->returnValue($anonymousUserId));
360
361
        $this->assertSame($authenticatedToken, $this->authenticator->authenticate($request));
362
    }
363
364 View Code Duplication
    public function testAuthenticate()
365
    {
366
        $username = 'foo_user';
367
        $password = 'publish';
368
369
        $existingToken = $this->getTokenInterfaceMock();
370
        $existingToken
371
            ->expects($this->once())
372
            ->method('getUsername')
373
            ->will($this->returnValue(__METHOD__));
374
375
        $request = new Request();
376
        $request->attributes->set('username', $username);
377
        $request->attributes->set('password', $password);
378
379
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
380
        $authenticatedToken = $this->getUsernamePasswordTokenMock();
381
        $this->authenticationManager
382
            ->expects($this->once())
383
            ->method('authenticate')
384
            ->with($this->equalTo($usernamePasswordToken))
385
            ->will($this->returnValue($authenticatedToken));
386
387
        $this->eventDispatcher
388
            ->expects($this->once())
389
            ->method('dispatch')
390
            ->with(
391
                SecurityEvents::INTERACTIVE_LOGIN,
392
                $this->equalTo(new InteractiveLoginEvent($request, $authenticatedToken))
393
            );
394
395
        $this->tokenStorage
396
            ->expects($this->at(0))
397
            ->method('getToken')
398
            ->will($this->returnValue($existingToken));
399
        $this->tokenStorage
400
            ->expects($this->at(1))
401
            ->method('setToken')
402
            ->with($authenticatedToken);
403
        $this->tokenStorage
404
            ->expects($this->at(2))
405
            ->method('getToken')
406
            ->will($this->returnValue($authenticatedToken));
407
408
        $authenticatedUser = $this->createUser(456);
409
        $authenticatedToken
410
            ->expects($this->once())
411
            ->method('getUser')
412
            ->will($this->returnValue($authenticatedUser));
413
414
        $this->assertSame($authenticatedToken, $this->authenticator->authenticate($request));
415
    }
416
417
    public function testAuthenticatePreviousUserNonEz()
418
    {
419
        $username = 'foo_user';
420
        $password = 'publish';
421
422
        $existingUser = $this->createMock(UserInterface::class);
423
        $existingToken = $this->getUsernamePasswordTokenMock();
424
        $existingToken
425
            ->expects($this->once())
426
            ->method('getUsername')
427
            ->will($this->returnValue(__METHOD__));
428
        $existingToken
429
            ->expects($this->once())
430
            ->method('getUser')
431
            ->will($this->returnValue($existingUser));
432
433
        $request = new Request();
434
        $request->attributes->set('username', $username);
435
        $request->attributes->set('password', $password);
436
437
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
438
        $authenticatedToken = $this->getUsernamePasswordTokenMock();
439
        $this->authenticationManager
440
            ->expects($this->once())
441
            ->method('authenticate')
442
            ->with($this->equalTo($usernamePasswordToken))
443
            ->will($this->returnValue($authenticatedToken));
444
445
        $this->eventDispatcher
446
            ->expects($this->once())
447
            ->method('dispatch')
448
            ->with(
449
                SecurityEvents::INTERACTIVE_LOGIN,
450
                $this->equalTo(new InteractiveLoginEvent($request, $authenticatedToken))
451
            );
452
453
        $this->tokenStorage
454
            ->expects($this->at(0))
455
            ->method('getToken')
456
            ->will($this->returnValue($existingToken));
457
        $this->tokenStorage
458
            ->expects($this->at(1))
459
            ->method('setToken')
460
            ->with($authenticatedToken);
461
        $this->tokenStorage
462
            ->expects($this->at(2))
463
            ->method('getToken')
464
            ->will($this->returnValue($authenticatedToken));
465
466
        $authenticatedUser = $this->createUser(456);
467
        $authenticatedToken
468
            ->expects($this->once())
469
            ->method('getUser')
470
            ->will($this->returnValue($authenticatedUser));
471
472
        $this->assertSame($authenticatedToken, $this->authenticator->authenticate($request));
473
    }
474
475 View Code Duplication
    public function testAuthenticatePreviousTokenNotUsernamePassword()
476
    {
477
        $username = 'foo_user';
478
        $password = 'publish';
479
480
        $existingToken = $this->getTokenInterfaceMock();
481
        $existingToken
482
            ->expects($this->once())
483
            ->method('getUsername')
484
            ->will($this->returnValue(__METHOD__));
485
486
        $request = new Request();
487
        $request->attributes->set('username', $username);
488
        $request->attributes->set('password', $password);
489
490
        $usernamePasswordToken = new UsernamePasswordToken($username, $password, self::PROVIDER_KEY);
491
        $authenticatedToken = $this->getUsernamePasswordTokenMock();
492
        $this->authenticationManager
493
            ->expects($this->once())
494
            ->method('authenticate')
495
            ->with($this->equalTo($usernamePasswordToken))
496
            ->will($this->returnValue($authenticatedToken));
497
498
        $this->eventDispatcher
499
            ->expects($this->once())
500
            ->method('dispatch')
501
            ->with(
502
                SecurityEvents::INTERACTIVE_LOGIN,
503
                $this->equalTo(new InteractiveLoginEvent($request, $authenticatedToken))
504
            );
505
506
        $this->tokenStorage
507
            ->expects($this->at(0))
508
            ->method('getToken')
509
            ->will($this->returnValue($existingToken));
510
        $this->tokenStorage
511
            ->expects($this->at(1))
512
            ->method('setToken')
513
            ->with($authenticatedToken);
514
        $this->tokenStorage
515
            ->expects($this->at(2))
516
            ->method('getToken')
517
            ->will($this->returnValue($authenticatedToken));
518
519
        $authenticatedUser = $this->createUser(456);
520
        $authenticatedToken
521
            ->expects($this->once())
522
            ->method('getUser')
523
            ->will($this->returnValue($authenticatedUser));
524
525
        $this->assertSame($authenticatedToken, $this->authenticator->authenticate($request));
526
    }
527
528
    public function testLogout()
529
    {
530
        $sessionLogoutHandler = $this->createMock(SessionLogoutHandler::class);
531
        $sessionLogoutHandler
532
            ->expects($this->never())
533
            ->method('logout');
534
535
        $token = $this->getTokenInterfaceMock();
536
        $this->tokenStorage
537
            ->expects($this->once())
538
            ->method('getToken')
539
            ->will($this->returnValue($token));
540
541
        $request = new Request();
542
        $logoutHandler1 = $this->createMock(LogoutHandlerInterface::class);
543
        $logoutHandler1
544
            ->expects($this->once())
545
            ->method('logout')
546
            ->with(
547
                $request,
548
                $this->isInstanceOf(Response::class),
549
                $token
550
            );
551
        $logoutHandler2 = $this->createMock(LogoutHandlerInterface::class);
552
        $logoutHandler2
553
            ->expects($this->once())
554
            ->method('logout')
555
            ->with(
556
                $request,
557
                $this->isInstanceOf(Response::class),
558
                $token
559
            );
560
561
        $this->authenticator->addLogoutHandler($sessionLogoutHandler);
562
        $this->authenticator->addLogoutHandler($logoutHandler1);
563
        $this->authenticator->addLogoutHandler($logoutHandler2);
564
565
        $this->assertInstanceOf(
566
            Response::class,
567
            $this->authenticator->logout($request)
568
        );
569
    }
570
571
    protected function getTokenInterfaceMock()
572
    {
573
        return $this->createMock(TokenInterface::class);
574
    }
575
576
    protected function getUsernamePasswordTokenMock()
577
    {
578
        return $this->createMock(UsernamePasswordToken::class);
579
    }
580
}
581