Skip to content

Commit ad04e86

Browse files
[Security] Allow in memory user to have extra fields
1 parent 6ae59a9 commit ad04e86

File tree

9 files changed

+107
-6
lines changed

9 files changed

+107
-6
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
use `security.password_hasher_factory` and `Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface` instead
1111
* Deprecate the `security.user_password_encoder.generic` service, the `security.password_encoder` and the `Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface` aliases,
1212
use `security.user_password_hasher`, `security.password_hasher` and `Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface` instead
13+
* Add `extra_fields` for `memory` provider to allow extra fields for users
1314

1415
5.2.0
1516
-----

src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ private function addProvidersSection(ArrayNodeDefinition $rootNode)
319319
'memory' => [
320320
'users' => [
321321
'foo' => ['password' => 'foo', 'roles' => 'ROLE_USER'],
322-
'bar' => ['password' => 'bar', 'roles' => '[ROLE_USER, ROLE_ADMIN]'],
322+
'bar' => ['password' => 'bar', 'roles' => ['ROLE_USER', 'ROLE_ADMIN'], 'extra_fields' => ['name' => 'John', 'age' => 77]],
323323
],
324324
],
325325
],

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/UserProvider/InMemoryFactory.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function create(ContainerBuilder $container, string $id, array $config)
3131
$users = [];
3232

3333
foreach ($config['users'] as $username => $user) {
34-
$users[$username] = ['password' => null !== $user['password'] ? (string) $user['password'] : $defaultPassword, 'roles' => $user['roles']];
34+
$users[$username] = ['password' => null !== $user['password'] ? (string) $user['password'] : $defaultPassword, 'roles' => $user['roles'], 'extra_fields' => $user['extra_fields']];
3535
}
3636

3737
$definition->addArgument($users);
@@ -57,6 +57,9 @@ public function addConfiguration(NodeDefinition $node)
5757
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
5858
->prototype('scalar')->end()
5959
->end()
60+
->arrayNode('extra_fields')
61+
->prototype('scalar')->end()
62+
->end()
6063
->end()
6164
->end()
6265
->end()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\Bundle\SecurityBundle\Tests\Functional;
13+
14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\Security\Core\User\User;
16+
use Symfony\Component\Security\Core\User\UserInterface;
17+
18+
class MemoryUserExtraFieldsTest extends AbstractWebTestCase
19+
{
20+
public function testMemoryUserHasExtraFields()
21+
{
22+
$client = $this->createClient(['test_case' => 'MemoryUserExtraFields', 'root_config' => 'config.yml']);
23+
24+
$client->request('POST', '/login', [
25+
'_username' => 'foo',
26+
'_password' => 'bar',
27+
]);
28+
$client->request('GET', '/memory-user-extra-fields');
29+
30+
$response = $client->getResponse();
31+
32+
$this->assertSame(200, $response->getStatusCode());
33+
$this->assertStringContainsString('username:foo, age:77', $response->getContent());
34+
}
35+
}
36+
37+
class MemoryUserExtraFieldsController
38+
{
39+
public function __invoke(UserInterface $user): Response
40+
{
41+
$username = $user->getUsername();
42+
$age = $user->getExtraFields()['age'] ?? '-';
43+
44+
return new Response(
45+
\sprintf('username:%s, age:%s', $username, $age)
46+
);
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
imports:
2+
- { resource: ./../config/framework.yml }
3+
4+
security:
5+
password_hashers:
6+
Symfony\Component\Security\Core\User\User: plaintext
7+
8+
providers:
9+
in_memory:
10+
memory:
11+
users:
12+
foo: { password: bar, roles: [ROLE_USER], extra_fields: {'age': 77} }
13+
14+
firewalls:
15+
default:
16+
form_login:
17+
check_path: login
18+
19+
access_control:
20+
- { path: ^/memory-user-extra-fields, roles: ROLE_USER }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
login:
2+
path: /login
3+
4+
memory-user-extra-fields:
5+
path: /memory-user-extra-fields
6+
defaults:
7+
_controller: Symfony\Bundle\SecurityBundle\Tests\Functional\MemoryUserExtraFieldsController

src/Symfony/Component/Security/Core/Tests/User/InMemoryUserProviderTest.php

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function testConstructor()
2525
$user = $provider->loadUserByUsername('fabien');
2626
$this->assertEquals('foo', $user->getPassword());
2727
$this->assertEquals(['ROLE_USER'], $user->getRoles());
28+
$this->assertEquals(['name' => 'John', 'age' => 77], $user->getExtraFields());
2829
$this->assertFalse($user->isEnabled());
2930
}
3031

@@ -37,6 +38,7 @@ public function testRefresh()
3738
$refreshedUser = $provider->refreshUser($user);
3839
$this->assertEquals('foo', $refreshedUser->getPassword());
3940
$this->assertEquals(['ROLE_USER'], $refreshedUser->getRoles());
41+
$this->assertEquals(['name' => 'John', 'age' => 77], $refreshedUser->getExtraFields());
4042
$this->assertFalse($refreshedUser->isEnabled());
4143
$this->assertFalse($refreshedUser->isCredentialsNonExpired());
4244
}
@@ -48,6 +50,7 @@ protected function createProvider(): InMemoryUserProvider
4850
'password' => 'foo',
4951
'enabled' => false,
5052
'roles' => ['ROLE_USER'],
53+
'extra_fields' => ['name' => 'John', 'age' => 77],
5154
],
5255
]);
5356
}

src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class InMemoryUserProvider implements UserProviderInterface
2828

2929
/**
3030
* The user array is a hash where the keys are usernames and the values are
31-
* an array of attributes: 'password', 'enabled', and 'roles'.
31+
* an array of attributes: 'password', 'enabled', 'roles' and 'extra_fields'.
3232
*
3333
* @param array $users An array of users
3434
*/
@@ -38,7 +38,8 @@ public function __construct(array $users = [])
3838
$password = $attributes['password'] ?? null;
3939
$enabled = $attributes['enabled'] ?? true;
4040
$roles = $attributes['roles'] ?? [];
41-
$user = new User($username, $password, $roles, $enabled, true, true, true);
41+
$extraFields = $attributes['extra_fields'] ?? [];
42+
$user = new User($username, $password, $roles, $enabled, true, true, true, $extraFields);
4243

4344
$this->createUser($user);
4445
}
@@ -65,7 +66,7 @@ public function loadUserByUsername(string $username)
6566
{
6667
$user = $this->getUser($username);
6768

68-
return new User($user->getUsername(), $user->getPassword(), $user->getRoles(), $user->isEnabled(), $user->isAccountNonExpired(), $user->isCredentialsNonExpired(), $user->isAccountNonLocked());
69+
return new User($user->getUsername(), $user->getPassword(), $user->getRoles(), $user->isEnabled(), $user->isAccountNonExpired(), $user->isCredentialsNonExpired(), $user->isAccountNonLocked(), $user->getExtraFields());
6970
}
7071

7172
/**
@@ -79,7 +80,7 @@ public function refreshUser(UserInterface $user)
7980

8081
$storedUser = $this->getUser($user->getUsername());
8182

82-
return new User($storedUser->getUsername(), $storedUser->getPassword(), $storedUser->getRoles(), $storedUser->isEnabled(), $storedUser->isAccountNonExpired(), $storedUser->isCredentialsNonExpired() && $storedUser->getPassword() === $user->getPassword(), $storedUser->isAccountNonLocked());
83+
return new User($storedUser->getUsername(), $storedUser->getPassword(), $storedUser->getRoles(), $storedUser->isEnabled(), $storedUser->isAccountNonExpired(), $storedUser->isCredentialsNonExpired() && $storedUser->getPassword() === $user->getPassword(), $storedUser->isAccountNonLocked(), $storedUser->getExtraFields());
8384
}
8485

8586
/**

0 commit comments

Comments
 (0)