1
|
|
|
<?php
|
2
|
|
|
|
3
|
|
|
namespace Sil\RouteSecurityBundle\Tests\Listener;
|
4
|
|
|
|
5
|
|
|
use PHPUnit\Framework\TestCase;
|
6
|
|
|
use Sil\RouteSecurityBundle\Event\AccessDeniedToRouteEvent;
|
7
|
|
|
use Sil\RouteSecurityBundle\Exception\LogicException;
|
8
|
|
|
use Sil\RouteSecurityBundle\Listener\AccessControlListener;
|
9
|
|
|
use Sil\RouteSecurityBundle\Security\AccessControl;
|
10
|
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
11
|
|
|
use Symfony\Component\HttpFoundation\Response;
|
12
|
|
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
13
|
|
|
use Symfony\Component\HttpFoundation\ParameterBag;
|
14
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
15
|
|
|
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
16
|
|
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
17
|
|
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
18
|
|
|
use Symfony\Component\Security\Core\User\UserInterface;
|
19
|
|
|
|
20
|
|
|
class AccessControlListenerTest extends TestCase
|
21
|
|
|
{
|
22
|
|
|
public function testWhenAccessControlIsDisabled()
|
23
|
|
|
{
|
24
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
25
|
|
|
$accessControl
|
26
|
|
|
->method('isEnable')
|
27
|
|
|
->willReturn(false);
|
28
|
|
|
$tokenStorage = $this->createMock(TokenStorageInterface::class);
|
29
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
30
|
|
|
$event = $this->mockGetResponseEvent();
|
31
|
|
|
|
32
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
33
|
|
|
$accessControlListener->onKernelRequest($event);
|
34
|
|
|
|
35
|
|
|
$this->assertNull($accessControlListener->onKernelRequest($event));
|
36
|
|
|
}
|
37
|
|
|
|
38
|
|
View Code Duplication |
public function testWithNonSecureRoute()
|
|
|
|
|
39
|
|
|
{
|
40
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
41
|
|
|
$accessControl
|
42
|
|
|
->method('isEnable')
|
43
|
|
|
->willReturn(true);
|
44
|
|
|
$accessControl
|
45
|
|
|
->method('isRouteSecure')
|
46
|
|
|
->with('non_secure_route')
|
47
|
|
|
->willReturn(false);
|
48
|
|
|
$tokenStorage = $this->createMock(TokenStorageInterface::class);
|
49
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
50
|
|
|
$event = $this->mockGetResponseEvent('non_secure_route');
|
51
|
|
|
|
52
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
53
|
|
|
$accessControlListener->onKernelRequest($event);
|
54
|
|
|
|
55
|
|
|
$this->assertNull($accessControlListener->onKernelRequest($event));
|
56
|
|
|
}
|
57
|
|
|
|
58
|
|
View Code Duplication |
public function testWithEmptyTokenStorage()
|
|
|
|
|
59
|
|
|
{
|
60
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
61
|
|
|
$accessControl
|
62
|
|
|
->method('isEnable')
|
63
|
|
|
->willReturn(true);
|
64
|
|
|
$accessControl
|
65
|
|
|
->method('isRouteSecure')
|
66
|
|
|
->with('secure_route')
|
67
|
|
|
->willReturn(true);
|
68
|
|
|
$tokenStorage = $this->createMock(TokenStorageInterface::class);
|
69
|
|
|
$tokenStorage
|
70
|
|
|
->method('getToken')
|
71
|
|
|
->willReturn(null);
|
72
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
73
|
|
|
$event = $this->mockGetResponseEvent('secure_route');
|
74
|
|
|
|
75
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
76
|
|
|
$this->expectException(LogicException::class);
|
77
|
|
|
$accessControlListener->onKernelRequest($event);
|
78
|
|
|
}
|
79
|
|
|
|
80
|
|
|
public function testWithInvalidTokenStorage()
|
81
|
|
|
{
|
82
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
83
|
|
|
$accessControl
|
84
|
|
|
->method('isEnable')
|
85
|
|
|
->willReturn(true);
|
86
|
|
|
$accessControl
|
87
|
|
|
->method('isRouteSecure')
|
88
|
|
|
->with('secure_route')
|
89
|
|
|
->willReturn(true);
|
90
|
|
|
$token = $this->createMock(TokenInterface::class);
|
91
|
|
|
$token
|
92
|
|
|
->method('getUser')
|
93
|
|
|
->willReturn('invalid user type');
|
94
|
|
|
$tokenStorage = $this->createMock(TokenStorageInterface::class);
|
95
|
|
|
$tokenStorage
|
96
|
|
|
->method('getToken')
|
97
|
|
|
->willReturn($token);
|
98
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
99
|
|
|
$event = $this->mockGetResponseEvent('secure_route');
|
100
|
|
|
|
101
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
102
|
|
|
$this->expectException(LogicException::class);
|
103
|
|
|
$accessControlListener->onKernelRequest($event);
|
104
|
|
|
}
|
105
|
|
|
|
106
|
|
View Code Duplication |
public function testWithCorrectAccessForUser()
|
|
|
|
|
107
|
|
|
{
|
108
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
109
|
|
|
$accessControl
|
110
|
|
|
->method('isEnable')
|
111
|
|
|
->willReturn(true);
|
112
|
|
|
$accessControl
|
113
|
|
|
->method('isRouteSecure')
|
114
|
|
|
->with('secure_route')
|
115
|
|
|
->willReturn(true);
|
116
|
|
|
$accessControl
|
117
|
|
|
->method('hasUserAccessToRoute')
|
118
|
|
|
->willReturn(true);
|
119
|
|
|
$tokenStorage = $this->mockTokenStorage();
|
120
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
121
|
|
|
$event = $this->mockGetResponseEvent('secure_route');
|
122
|
|
|
|
123
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
124
|
|
|
$this->assertNull($accessControlListener->onKernelRequest($event));
|
125
|
|
|
}
|
126
|
|
|
|
127
|
|
View Code Duplication |
public function testWithIncorrectAccessForUser()
|
|
|
|
|
128
|
|
|
{
|
129
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
130
|
|
|
$accessControl
|
131
|
|
|
->method('isEnable')
|
132
|
|
|
->willReturn(true);
|
133
|
|
|
$accessControl
|
134
|
|
|
->method('isRouteSecure')
|
135
|
|
|
->with('secure_route')
|
136
|
|
|
->willReturn(true);
|
137
|
|
|
$accessControl
|
138
|
|
|
->method('hasUserAccessToRoute')
|
139
|
|
|
->willReturn(false);
|
140
|
|
|
$tokenStorage = $this->mockTokenStorage();
|
141
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
142
|
|
|
$event = $this->mockGetResponseEvent('secure_route');
|
143
|
|
|
|
144
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
145
|
|
|
$this->expectException(AccessDeniedException::class);
|
146
|
|
|
$this->assertNull($accessControlListener->onKernelRequest($event));
|
147
|
|
|
}
|
148
|
|
|
|
149
|
|
|
public function testWithIncorrectAccessForUserAndCustomResponse()
|
150
|
|
|
{
|
151
|
|
|
$accessControl = $this->createMock(AccessControl::class);
|
152
|
|
|
$accessControl
|
153
|
|
|
->method('isEnable')
|
154
|
|
|
->willReturn(true);
|
155
|
|
|
$accessControl
|
156
|
|
|
->method('isRouteSecure')
|
157
|
|
|
->with('secure_route')
|
158
|
|
|
->willReturn(true);
|
159
|
|
|
$accessControl
|
160
|
|
|
->method('hasUserAccessToRoute')
|
161
|
|
|
->willReturn(false);
|
162
|
|
|
$tokenStorage = $this->mockTokenStorage();
|
163
|
|
|
$event = $this->mockGetResponseEvent('secure_route');
|
164
|
|
|
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
165
|
|
|
$response = new Response('Custom Response');
|
166
|
|
|
$eventDispatcher
|
167
|
|
|
->expects($this->once())
|
168
|
|
|
->method('dispatch')
|
169
|
|
|
->with(AccessDeniedToRouteEvent::ON_ACCESS_DENIED_TO_ROUTE, $this->isInstanceOf(AccessDeniedToRouteEvent::class))
|
170
|
|
|
->will($this->returnCallback(function ($name, $access_denied_event) use ($response) {
|
171
|
|
|
$access_denied_event->setResponse($response);
|
172
|
|
|
}));
|
173
|
|
|
|
174
|
|
|
$accessControlListener = new AccessControlListener($accessControl, $tokenStorage, $eventDispatcher);
|
175
|
|
|
$this->assertInstanceOf(GetResponseEvent::class, $accessControlListener->onKernelRequest($event));
|
176
|
|
|
}
|
177
|
|
|
|
178
|
|
|
protected function mockGetResponseEvent($route = null)
|
179
|
|
|
{
|
180
|
|
|
$event = $this->createMock(GetResponseEvent::class);
|
181
|
|
|
$request = $this->createMock(Request::class);
|
182
|
|
|
$parameterBag = $this->createMock(ParameterBag::class);
|
183
|
|
|
$parameterBag
|
184
|
|
|
->method('get')
|
185
|
|
|
->with('_route')
|
186
|
|
|
->willReturn($route);
|
187
|
|
|
|
188
|
|
|
$request->attributes = $parameterBag;
|
|
|
|
|
189
|
|
|
$event->method('getRequest')->willReturn($request);
|
190
|
|
|
|
191
|
|
|
return $event;
|
192
|
|
|
}
|
193
|
|
|
|
194
|
|
|
protected function mockTokenStorage($roles = [])
|
195
|
|
|
{
|
196
|
|
|
$tokenStorage = $this->createMock(TokenStorageInterface::class);
|
197
|
|
|
$user = $this->createMock(UserInterface::class);
|
198
|
|
|
$user
|
199
|
|
|
->method('getRoles')
|
200
|
|
|
->willReturn($roles);
|
201
|
|
|
$token = $this->createMock(TokenInterface::class);
|
202
|
|
|
$token
|
203
|
|
|
->method('getUser')
|
204
|
|
|
->willReturn($user);
|
205
|
|
|
$tokenStorage
|
206
|
|
|
->method('getToken')
|
207
|
|
|
->willReturn($token);
|
208
|
|
|
|
209
|
|
|
return $tokenStorage;
|
210
|
|
|
}
|
211
|
|
|
}
|
212
|
|
|
|
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.