Skip to content

Commit 7a5658c

Browse 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 3b496b4 commit 7a5658c

File tree

4 files changed

+121
-7
lines changed

4 files changed

+121
-7
lines changed

Authentication/AuthenticationTrustResolver.php

Lines 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
/**

Authentication/Token/NullToken.php

Lines 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 <[email protected]>
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 <[email protected]>
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+
}

Authorization/AuthorizationChecker.php

Lines 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);

Tests/Authorization/AuthorizationCheckerTest.php

Lines 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
/**

0 commit comments

Comments
 (0)