Skip to content

Navigation Menu

Sign in
Appearance settings

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 157f6f7

Browse filesBrowse files
committed
#21571 updated AbstractToken to compare Roles, added test case
1 parent 0f35e5b commit 157f6f7
Copy full SHA for 157f6f7

File tree

9 files changed

+211
-0
lines changed
Filter options

9 files changed

+211
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Controller;
4+
5+
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
6+
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
7+
use Symfony\Component\HttpFoundation\Response;
8+
9+
class AdminController implements ContainerAwareInterface
10+
{
11+
use ContainerAwareTrait;
12+
13+
public function indexAction()
14+
{
15+
return new Response('admin');
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
admin:
2+
path: /admin
3+
defaults: { _controller: SecuredPageBundle:Admin:index }
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle;
4+
5+
use Symfony\Component\HttpKernel\Bundle\Bundle;
6+
7+
class SecuredPageBundle extends Bundle
8+
{
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User;
4+
5+
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
6+
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
7+
use Symfony\Component\Security\Core\User\User;
8+
use Symfony\Component\Security\Core\User\UserInterface;
9+
use Symfony\Component\Security\Core\User\UserProviderInterface;
10+
11+
class ArrayUserProvider implements UserProviderInterface
12+
{
13+
/** @var User[] */
14+
private $users = [];
15+
16+
public function addUser(User $user)
17+
{
18+
$this->users[$user->getUsername()] = $user;
19+
}
20+
21+
public function setUser($username, User $user)
22+
{
23+
$this->users[$username] = $user;
24+
}
25+
26+
public function getUser($username)
27+
{
28+
return $this->users[$username];
29+
}
30+
31+
public function loadUserByUsername($username)
32+
{
33+
$user = $this->getUser($username);
34+
35+
if (null === $user) {
36+
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
37+
}
38+
39+
return $user;
40+
}
41+
42+
public function refreshUser(UserInterface $user)
43+
{
44+
if (!$user instanceof User) {
45+
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
46+
}
47+
48+
$storedUser = $this->getUser($user->getUsername());
49+
50+
return new User($storedUser->getUsername(), $storedUser->getPassword(), $storedUser->getRoles(), $storedUser->isEnabled(), $storedUser->isAccountNonExpired(), $storedUser->isCredentialsNonExpired() && $storedUser->getPassword() === $user->getPassword(), $storedUser->isAccountNonLocked());
51+
}
52+
53+
public function supportsClass($class)
54+
{
55+
return 'Symfony\Component\Security\Core\User\User' === $class;
56+
}
57+
}

‎src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php
+39Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
1313

14+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User\ArrayUserProvider;
1415
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
16+
use Symfony\Component\Security\Core\Role\Role;
1517
use Symfony\Component\Security\Core\User\User;
1618

1719
class SecurityTest extends WebTestCase
@@ -31,4 +33,41 @@ public function testServiceIsFunctional()
3133
$this->assertTrue($security->isGranted('ROLE_USER'));
3234
$this->assertSame($token, $security->getToken());
3335
}
36+
37+
public function userWillBeMarkedAsChangedIfRolesHasChangedProvider()
38+
{
39+
return [
40+
[new Role('ROLE_ADMIN'), new Role('ROLE_USER')],
41+
['ROLE_ADMIN', 'ROLE_USER'],
42+
];
43+
}
44+
45+
/**
46+
* @dataProvider userWillBeMarkedAsChangedIfRolesHasChangedProvider
47+
*/
48+
public function testUserWillBeMarkedAsChangedIfRolesHasChanged($adminRole, $userRole)
49+
{
50+
$client = $this->createClient(['test_case' => 'AbstractTokenCompareRoles', 'root_config' => 'config.yml']);
51+
$client->disableReboot();
52+
53+
/** @var ArrayUserProvider $userProvider */
54+
$userProvider = static::$kernel->getContainer()->get('security.user.provider.array');
55+
$userProvider->addUser(new User('user1', 'test', [$adminRole]));
56+
57+
$client->request('POST', '/login', [
58+
'_username' => 'user1',
59+
'_password' => 'test',
60+
]);
61+
62+
// user1 has ROLE_ADMIN and can visit secure page
63+
$client->request('GET', '/admin');
64+
$this->assertEquals(200, $client->getResponse()->getStatusCode());
65+
66+
// revoking ROLE_ADMIN from user1
67+
$userProvider->setUser('user1', new User('user1', 'test', [$userRole]));
68+
69+
// user1 has lost ROLE_ADMIN and MUST be redirected away from secure page
70+
$client->request('GET', '/admin');
71+
$this->assertEquals(302, $client->getResponse()->getStatusCode());
72+
}
3473
}
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
13+
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
15+
return [
16+
new FrameworkBundle(),
17+
new SecurityBundle(),
18+
new \Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\SecuredPageBundle(),
19+
];
+33Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
imports:
2+
- { resource: ./../config/framework.yml }
3+
4+
services:
5+
_defaults: { public: true }
6+
7+
security.user.provider.array:
8+
class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User\ArrayUserProvider
9+
10+
security:
11+
12+
encoders:
13+
Symfony\Component\Security\Core\User\User: plaintext
14+
15+
providers:
16+
array:
17+
id: security.user.provider.array
18+
19+
firewalls:
20+
default:
21+
form_login:
22+
check_path: login
23+
remember_me: true
24+
require_previous_session: false
25+
logout: ~
26+
anonymous: ~
27+
logout_on_user_change: true
28+
stateless: false
29+
30+
access_control:
31+
- { path: ^/admin$, roles: ROLE_ADMIN }
32+
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
33+
- { path: .*, roles: IS_AUTHENTICATED_FULLY }
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
login:
2+
path: /login
3+
4+
logout:
5+
path: /logout
6+
7+
admin_bundle:
8+
resource: '@SecuredPageBundle/Resources/config/routing.yml'
9+

‎src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,35 @@ private function hasUserChanged(UserInterface $user)
275275
return true;
276276
}
277277

278+
$rolesChanged = \count(
279+
array_diff(
280+
array_map([$this, 'castRole'], (array) $this->user->getRoles()),
281+
array_map([$this, 'castRole'], (array) $user->getRoles())
282+
)
283+
);
284+
285+
if ($rolesChanged) {
286+
return true;
287+
}
288+
278289
if ($this->user->getUsername() !== $user->getUsername()) {
279290
return true;
280291
}
281292

282293
return false;
283294
}
295+
296+
/**
297+
* @param string|Role $role
298+
*
299+
* @return string
300+
*/
301+
private function castRole($role)
302+
{
303+
if ($role instanceof Role) {
304+
return $role->getRole();
305+
}
306+
307+
return (string) $role;
308+
}
284309
}

0 commit comments

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