Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b9f3c41

Browse filesBrowse files
committed
Use NullToken while checking authorization
This allows to e.g. have some objects that can be viewed by anyone (even unauthenticated users).
1 parent 8a7c776 commit b9f3c41
Copy full SHA for b9f3c41

File tree

8 files changed

+153
-28
lines changed
Filter options

8 files changed

+153
-28
lines changed

‎UPGRADE-5.2.md

Copy file name to clipboardExpand all lines: UPGRADE-5.2.md
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,9 @@ Validator
4343
* })
4444
*/
4545
```
46+
47+
Security
48+
--------
49+
50+
* [BC break] In the experimental authenticator-based system, * `TokenInterface::getUser()`
51+
returns `null` in case of unauthenticated session.

‎src/Symfony/Component/Security/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/CHANGELOG.md
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ CHANGELOG
44
5.2.0
55
-----
66

7-
* Added attributes on ``Passport``
7+
* Added attributes on `Passport`
8+
* Changed `AuthorizationChecker` to call the access decision manager in unauthenticated sessions with a `NullToken`
89

910
5.1.0
1011
-----

‎src/Symfony/Component/Security/Core/Authentication/AuthenticationTrustResolver.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authentication/AuthenticationTrustResolver.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Core\Authentication;
1313

1414
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
15+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1516
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
1617
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1718

@@ -31,7 +32,7 @@ public function isAnonymous(TokenInterface $token = null)
3132
return false;
3233
}
3334

34-
return $token instanceof AnonymousToken;
35+
return $token instanceof AnonymousToken || $token instanceof NullToken;
3536
}
3637

3738
/**
+105Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Core\Authentication\Token;
13+
14+
/**
15+
* @author Wouter de Jong <wouter@wouterj.nl>
16+
*/
17+
class NullToken implements TokenInterface
18+
{
19+
public function __toString(): string
20+
{
21+
return '';
22+
}
23+
24+
public function getRoleNames(): array
25+
{
26+
return [];
27+
}
28+
29+
public function getCredentials()
30+
{
31+
return '';
32+
}
33+
34+
public function getUser()
35+
{
36+
return null;
37+
}
38+
39+
public function setUser($user)
40+
{
41+
throw new \BadMethodCallException('Cannot set user on a NullToken.');
42+
}
43+
44+
public function getUsername()
45+
{
46+
return '';
47+
}
48+
49+
public function isAuthenticated()
50+
{
51+
return true;
52+
}
53+
54+
public function setAuthenticated(bool $isAuthenticated)
55+
{
56+
throw new \BadMethodCallException('Cannot change authentication state of NullToken.');
57+
}
58+
59+
public function eraseCredentials()
60+
{
61+
}
62+
63+
public function getAttributes()
64+
{
65+
return [];
66+
}
67+
68+
public function setAttributes(array $attributes)
69+
{
70+
throw new \BadMethodCallException('Cannot set attributes of NullToken.');
71+
}
72+
73+
public function hasAttribute(string $name)
74+
{
75+
return false;
76+
}
77+
78+
public function getAttribute(string $name)
79+
{
80+
return null;
81+
}
82+
83+
public function setAttribute(string $name, $value)
84+
{
85+
throw new \BadMethodCallException('Cannot add attribute to NullToken.');
86+
}
87+
88+
public function __serialize(): array
89+
{
90+
return [];
91+
}
92+
93+
public function __unserialize(array $data): void
94+
{
95+
}
96+
97+
public function serialize()
98+
{
99+
return '';
100+
}
101+
102+
public function unserialize($serialized)
103+
{
104+
}
105+
}

‎src/Symfony/Component/Security/Core/Authorization/AuthorizationChecker.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/AuthorizationChecker.php
+6-5Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Core\Authorization;
1313

1414
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
15+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1516
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1617
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
1718

@@ -52,11 +53,11 @@ final public function isGranted($attribute, $subject = null): bool
5253
throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
5354
}
5455

55-
return false;
56-
}
57-
58-
if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {
59-
$this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token));
56+
$token = new NullToken();
57+
} else {
58+
if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {
59+
$this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token));
60+
}
6061
}
6162

6263
return $this->accessDecisionManager->decide($token, [$attribute], $subject);

‎src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php
+8-1Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Core\Tests\Authorization;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1516
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
1617
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
1718
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
@@ -77,7 +78,13 @@ public function testVoteWithoutAuthenticationTokenAndExceptionOnNoTokenIsFalse()
7778
{
7879
$authorizationChecker = new AuthorizationChecker($this->tokenStorage, $this->authenticationManager, $this->accessDecisionManager, false, false);
7980

80-
$this->assertFalse($authorizationChecker->isGranted('ROLE_FOO'));
81+
$this->accessDecisionManager
82+
->expects($this->once())
83+
->method('decide')
84+
->with($this->isInstanceOf(NullToken::class))
85+
->willReturn(true);
86+
87+
$this->assertTrue($authorizationChecker->isGranted('ANONYMOUS'));
8188
}
8289

8390
/**

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/Firewall/AccessListener.php
+2-13Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\HttpFoundation\Request;
1515
use Symfony\Component\HttpKernel\Event\RequestEvent;
1616
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
17+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1718
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1819
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
1920
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
@@ -89,19 +90,7 @@ public function authenticate(RequestEvent $event)
8990
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
9091
}
9192

92-
if ([AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes) {
93-
trigger_deprecation('symfony/security-http', '5.1', 'Using "IS_AUTHENTICATED_ANONYMOUSLY" in your access_control rules when using the authenticator Security system is deprecated, use "PUBLIC_ACCESS" instead.');
94-
95-
return;
96-
}
97-
98-
if ([self::PUBLIC_ACCESS] !== $attributes) {
99-
throw $this->createAccessDeniedException($request, $attributes);
100-
}
101-
}
102-
103-
if ([self::PUBLIC_ACCESS] === $attributes) {
104-
return;
93+
$token = new NullToken();
10594
}
10695

10796
if (!$token->isAuthenticated()) {

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/Tests/Firewall/AccessListenerTest.php
+22-7Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\HttpKernel\Event\RequestEvent;
1717
use Symfony\Component\HttpKernel\HttpKernelInterface;
1818
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
19+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1920
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
2021
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
2122
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
@@ -245,9 +246,15 @@ public function testHandleWhenTheSecurityTokenStorageHasNoTokenAndExceptionOnTok
245246
->willReturn([['foo' => 'bar'], null])
246247
;
247248

249+
$accessDecisionManager = $this->createMock(AccessDecisionManagerInterface::class);
250+
$accessDecisionManager->expects($this->once())
251+
->method('decide')
252+
->with($this->isInstanceOf(NullToken::class))
253+
->willReturn(false);
254+
248255
$listener = new AccessListener(
249256
$tokenStorage,
250-
$this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock(),
257+
$accessDecisionManager,
251258
$accessMap,
252259
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(),
253260
false
@@ -268,17 +275,21 @@ public function testHandleWhenPublicAccessIsAllowedAndExceptionOnTokenIsFalse()
268275
->willReturn([[AccessListener::PUBLIC_ACCESS], null])
269276
;
270277

278+
$accessDecisionManager = $this->createMock(AccessDecisionManagerInterface::class);
279+
$accessDecisionManager->expects($this->once())
280+
->method('decide')
281+
->with($this->isInstanceOf(NullToken::class), [AccessListener::PUBLIC_ACCESS])
282+
->willReturn(true);
283+
271284
$listener = new AccessListener(
272285
$tokenStorage,
273-
$this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock(),
286+
$accessDecisionManager,
274287
$accessMap,
275288
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(),
276289
false
277290
);
278291

279292
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST));
280-
281-
$this->expectNotToPerformAssertions();
282293
}
283294

284295
public function testHandleWhenPublicAccessWhileAuthenticated()
@@ -295,17 +306,21 @@ public function testHandleWhenPublicAccessWhileAuthenticated()
295306
->willReturn([[AccessListener::PUBLIC_ACCESS], null])
296307
;
297308

309+
$accessDecisionManager = $this->createMock(AccessDecisionManagerInterface::class);
310+
$accessDecisionManager->expects($this->once())
311+
->method('decide')
312+
->with($this->equalTo($token), [AccessListener::PUBLIC_ACCESS])
313+
->willReturn(true);
314+
298315
$listener = new AccessListener(
299316
$tokenStorage,
300-
$this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock(),
317+
$accessDecisionManager,
301318
$accessMap,
302319
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(),
303320
false
304321
);
305322

306323
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST));
307-
308-
$this->expectNotToPerformAssertions();
309324
}
310325

311326
public function testHandleMWithultipleAttributesShouldBeHandledAsAnd()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.