Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8215d34

Browse files
committed
#27121 reusing AuthorizationChecker into AccessListener
- added deprecation notice about old-signature - added deprecation annotation to properties - added legacy group to old unit tests - added new unit tests - adjusted security.access_listener
1 parent 3af6406 commit 8215d34

File tree

4 files changed

+210
-9
lines changed

4 files changed

+210
-9
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ CHANGELOG
1919
* Added support for the new Argon2i password encoder
2020
* added `stateless` option to the `switch_user` listener
2121
* deprecated auto picking the first registered provider when no configured provider on a firewall and ambiguous
22+
* `AccessListener` reuses logic of `AuthorizationCheckerInterface`.
23+
`AccessListener::__construct` now accepts `TokenStorageInterface`, `AccessMapInterface` and `AuthorizationCheckerInterface`,
24+
if old signature is used `E_USER_DEPRECATED` will be triggered
2225

2326
3.3.0
2427
-----

src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,8 @@
248248
<service id="security.access_listener" class="Symfony\Component\Security\Http\Firewall\AccessListener">
249249
<tag name="monolog.logger" channel="security" />
250250
<argument type="service" id="security.token_storage" />
251-
<argument type="service" id="security.access.decision_manager" />
252251
<argument type="service" id="security.access_map" />
253-
<argument type="service" id="security.authentication.manager" />
252+
<argument type="service" id="security.authorization_checker"/>
254253
</service>
255254
</services>
256255
</container>

src/Symfony/Component/Security/Http/Firewall/AccessListener.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
1616
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1717
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
18+
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
1819
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
1920
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
2021
use Symfony\Component\Security\Http\AccessMapInterface;
@@ -27,15 +28,42 @@
2728
class AccessListener implements ListenerInterface
2829
{
2930
private $tokenStorage;
31+
32+
/**
33+
* @deprecated since Symfony 4.3
34+
*/
3035
private $accessDecisionManager;
3136
private $map;
37+
38+
/**
39+
* @deprecated since Symfony 4.3
40+
*/
3241
private $authManager;
42+
private $authorizationChecker;
3343

34-
public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager)
44+
/**
45+
* @param AccessDecisionManagerInterface|AccessMapInterface $map
46+
* @param AccessMapInterface|AuthorizationCheckerInterface $authorizationChecker
47+
* @param AuthenticationManagerInterface|null $authManager
48+
*/
49+
public function __construct(TokenStorageInterface $tokenStorage, $map, $authorizationChecker, $authManager = null)
3550
{
51+
if ($authorizationChecker instanceof AccessMapInterface) {
52+
@trigger_error(sprintf('Signature "%s()" has changed since Symfony 4.2, now it accepts TokenStorageInterface, AccessMapInterface, AuthorizationCheckerInterface.', __METHOD__), E_USER_DEPRECATED);
53+
$accessDecisionManager = $map;
54+
$map = $authorizationChecker;
55+
$authorizationChecker = null;
56+
} elseif (!$authorizationChecker instanceof AuthorizationCheckerInterface) {
57+
throw new \InvalidArgumentException(sprintf('Argument 3 passed to %s() must be an instance of %s or null, %s given.', __METHOD__, AuthorizationCheckerInterface::class, \is_object($authorizationChecker) ? \get_class($authorizationChecker) : \gettype($authorizationChecker)));
58+
} else {
59+
$accessDecisionManager = null;
60+
$authManager = null;
61+
}
62+
3663
$this->tokenStorage = $tokenStorage;
37-
$this->accessDecisionManager = $accessDecisionManager;
3864
$this->map = $map;
65+
$this->authorizationChecker = $authorizationChecker;
66+
$this->accessDecisionManager = $accessDecisionManager;
3967
$this->authManager = $authManager;
4068
}
4169

@@ -59,6 +87,18 @@ public function handle(GetResponseEvent $event)
5987
return;
6088
}
6189

90+
if (null !== $this->authorizationChecker) {
91+
if (!$this->authorizationChecker->isGranted($attributes, $request)) {
92+
$exception = new AccessDeniedException();
93+
$exception->setAttributes($attributes);
94+
$exception->setSubject($request);
95+
96+
throw $exception;
97+
}
98+
99+
return;
100+
}
101+
62102
if (!$token->isAuthenticated()) {
63103
$token = $this->authManager->authenticate($token);
64104
$this->tokenStorage->setToken($token);

src/Symfony/Component/Security/Http/Tests/Firewall/AccessListenerTest.php

Lines changed: 164 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,37 @@
1717
class AccessListenerTest extends TestCase
1818
{
1919
/**
20+
* @expectedException \InvalidArgumentException
21+
*/
22+
public function testBadConstructorSignature()
23+
{
24+
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
25+
26+
new AccessListener($tokenStorage, null, null, null);
27+
}
28+
29+
/**
30+
* @deprecated
31+
* @group legacy
32+
* @expectedDeprecation Signature "Symfony\Component\Security\Http\Firewall\AccessListener::__construct()" has changed since Symfony 4.2, now it accepts TokenStorageInterface, AccessMapInterface, AuthorizationCheckerInterface.
33+
*/
34+
public function testOldConstructorSignature()
35+
{
36+
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
37+
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
38+
$accessDecisionManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock();
39+
$authManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock();
40+
41+
new AccessListener($tokenStorage, $accessDecisionManager, $accessMap, $authManager);
42+
}
43+
44+
/**
45+
* @deprecated
46+
* @group legacy
47+
* @expectedDeprecation Signature "Symfony\Component\Security\Http\Firewall\AccessListener::__construct()" has changed since Symfony 4.2, now it accepts TokenStorageInterface, AccessMapInterface, AuthorizationCheckerInterface.
2048
* @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException
2149
*/
22-
public function testHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
50+
public function testOldHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
2351
{
2452
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
2553

@@ -70,7 +98,56 @@ public function testHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
7098
$listener->handle($event);
7199
}
72100

73-
public function testHandleWhenTheTokenIsNotAuthenticated()
101+
/**
102+
* @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException
103+
*/
104+
public function testHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
105+
{
106+
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
107+
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
108+
$authorizationChecker = $this->getMockBuilder('\Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface')->getMock();
109+
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
110+
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
111+
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')->disableOriginalConstructor()->getMock();
112+
$attributes = ['foo' => 'bar'];
113+
114+
$tokenStorage
115+
->expects($this->any())
116+
->method('getToken')
117+
->will($this->returnValue($token))
118+
;
119+
120+
$accessMap
121+
->expects($this->any())
122+
->method('getPatterns')
123+
->with($this->equalTo($request))
124+
->will($this->returnValue([$attributes, null]))
125+
;
126+
127+
$authorizationChecker
128+
->expects($this->once())
129+
->method('isGranted')
130+
->with($this->equalTo($attributes), $this->equalTo($request))
131+
->will($this->returnValue(false))
132+
;
133+
134+
$listener = new AccessListener($tokenStorage, $accessMap, $authorizationChecker);
135+
136+
$event
137+
->expects($this->any())
138+
->method('getRequest')
139+
->will($this->returnValue($request))
140+
;
141+
142+
$listener->handle($event);
143+
}
144+
145+
/**
146+
* @deprecated
147+
* @group legacy
148+
* @expectedDeprecation Signature "Symfony\Component\Security\Http\Firewall\AccessListener::__construct()" has changed since Symfony 4.2, now it accepts TokenStorageInterface, AccessMapInterface, AuthorizationCheckerInterface.
149+
*/
150+
public function testOldHandleWhenTheTokenIsNotAuthenticated()
74151
{
75152
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
76153

@@ -141,7 +218,12 @@ public function testHandleWhenTheTokenIsNotAuthenticated()
141218
$listener->handle($event);
142219
}
143220

144-
public function testHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
221+
/**
222+
* @deprecated
223+
* @group legacy
224+
* @expectedDeprecation Signature "Symfony\Component\Security\Http\Firewall\AccessListener::__construct()" has changed since Symfony 4.2, now it accepts TokenStorageInterface, AccessMapInterface, AuthorizationCheckerInterface.
225+
*/
226+
public function testOldHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
145227
{
146228
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
147229

@@ -183,10 +265,51 @@ public function testHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
183265
$listener->handle($event);
184266
}
185267

268+
public function testHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
269+
{
270+
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
271+
$authorizationChecker = $this->getMockBuilder('\Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface')->getMock();
272+
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')->disableOriginalConstructor()->getMock();
273+
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
274+
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
275+
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
276+
277+
$tokenStorage
278+
->expects($this->any())
279+
->method('getToken')
280+
->will($this->returnValue($token))
281+
;
282+
283+
$event
284+
->expects($this->any())
285+
->method('getRequest')
286+
->will($this->returnValue($request))
287+
;
288+
289+
$accessMap
290+
->expects($this->any())
291+
->method('getPatterns')
292+
->with($this->equalTo($request))
293+
->will($this->returnValue([null, null]))
294+
;
295+
296+
$authorizationChecker
297+
->expects($this->never())
298+
->method('isGranted')
299+
;
300+
301+
$listener = new AccessListener($tokenStorage, $accessMap, $authorizationChecker);
302+
303+
$listener->handle($event);
304+
}
305+
186306
/**
307+
* @deprecated
308+
* @group legacy
309+
* @expectedDeprecation Signature "Symfony\Component\Security\Http\Firewall\AccessListener::__construct()" has changed since Symfony 4.2, now it accepts TokenStorageInterface, AccessMapInterface, AuthorizationCheckerInterface.
187310
* @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
188311
*/
189-
public function testHandleWhenTheSecurityTokenStorageHasNoToken()
312+
public function testOldHandleWhenTheSecurityTokenStorageHasNoToken()
190313
{
191314
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
192315
$tokenStorage
@@ -195,14 +318,50 @@ public function testHandleWhenTheSecurityTokenStorageHasNoToken()
195318
->will($this->returnValue(null))
196319
;
197320

321+
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
322+
323+
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
324+
$accessMap
325+
->expects($this->any())
326+
->method('getPatterns')
327+
->with($this->equalTo($request))
328+
->will($this->returnValue([['foo' => 'bar'], null]))
329+
;
330+
198331
$listener = new AccessListener(
199332
$tokenStorage,
200333
$this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock(),
201-
$this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock(),
334+
$accessMap,
202335
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock()
203336
);
204337

205338
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')->disableOriginalConstructor()->getMock();
339+
$event
340+
->expects($this->any())
341+
->method('getRequest')
342+
->will($this->returnValue($request))
343+
;
344+
345+
$listener->handle($event);
346+
}
347+
348+
/**
349+
* @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
350+
*/
351+
public function testHandleWhenTheSecurityTokenStorageHasNoToken()
352+
{
353+
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
354+
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
355+
$authorizationChecker = $this->getMockBuilder('\Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface')->getMock();
356+
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')->disableOriginalConstructor()->getMock();
357+
358+
$tokenStorage
359+
->expects($this->any())
360+
->method('getToken')
361+
->will($this->returnValue(null))
362+
;
363+
364+
$listener = new AccessListener($tokenStorage, $accessMap, $authorizationChecker);
206365

207366
$listener->handle($event);
208367
}

0 commit comments

Comments
 (0)