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

Skip to content

Commit 4ad343b

Browse files
committed
feature #10005 [Security] Added named encoders to EncoderFactory (tamirvs)
This PR was squashed before being merged into the 2.5-dev branch (closes #10005). Discussion ---------- [Security] Added named encoders to EncoderFactory | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9743 | License | MIT | Doc PR | - This PR is basically merging FOSAdvancedEncoder. I think it's better than having a separate bundle that most of it's code is a copy of the core. A use case is: having a different encoders or bcrypt cost based on the user's roles. Commits ------- c69e2ca [Security] Added named encoders to EncoderFactory
2 parents a207006 + c69e2ca commit 4ad343b

File tree

3 files changed

+112
-7
lines changed

3 files changed

+112
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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\Encoder;
13+
14+
/**
15+
* @author Christophe Coevoet <[email protected]>
16+
*/
17+
interface EncoderAwareInterface
18+
{
19+
/**
20+
* Gets the name of the encoder used to encode the password.
21+
*
22+
* If the method returns null, the standard way to retrieve the encoder
23+
* will be used instead.
24+
*
25+
* @return string
26+
*/
27+
public function getEncoderName();
28+
}

src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php

+20-7
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,32 @@ public function __construct(array $encoders)
3030
*/
3131
public function getEncoder($user)
3232
{
33-
foreach ($this->encoders as $class => $encoder) {
34-
if ((is_object($user) && !$user instanceof $class) || (!is_object($user) && !is_subclass_of($user, $class) && $user != $class)) {
35-
continue;
33+
$encoderKey = null;
34+
35+
if ($user instanceof EncoderAwareInterface && (null !== $encoderName = $user->getEncoderName())) {
36+
if (!array_key_exists($encoderName, $this->encoders)) {
37+
throw new \RuntimeException(sprintf('The encoder "%s" was not configured.', $encoderName));
3638
}
3739

38-
if (!$encoder instanceof PasswordEncoderInterface) {
39-
return $this->encoders[$class] = $this->createEncoder($encoder);
40+
$encoderKey = $encoderName;
41+
} else {
42+
foreach ($this->encoders as $class => $encoder) {
43+
if ((is_object($user) && $user instanceof $class) || (!is_object($user) && (is_subclass_of($user, $class) || $user == $class))) {
44+
$encoderKey = $class;
45+
break;
46+
}
4047
}
48+
}
49+
50+
if (null === $encoderKey) {
51+
throw new \RuntimeException(sprintf('No encoder has been configured for account "%s".', is_object($user) ? get_class($user) : $user));
52+
}
4153

42-
return $this->encoders[$class];
54+
if (!$this->encoders[$encoderKey] instanceof PasswordEncoderInterface) {
55+
$this->encoders[$encoderKey] = $this->createEncoder($this->encoders[$encoderKey]);
4356
}
4457

45-
throw new \RuntimeException(sprintf('No encoder has been configured for account "%s".', is_object($user) ? get_class($user) : $user));
58+
return $this->encoders[$encoderKey];
4659
}
4760

4861
/**

src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php

+64
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
1515
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
16+
use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface;
1617
use Symfony\Component\Security\Core\User\User;
1718
use Symfony\Component\Security\Core\User\UserInterface;
1819

@@ -78,6 +79,59 @@ public function testGetEncoderConfiguredForConcreteClassWithClassName()
7879
$expectedEncoder = new MessageDigestPasswordEncoder('sha1');
7980
$this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', ''));
8081
}
82+
83+
public function testGetNamedEncoderForEncoderAware()
84+
{
85+
$factory = new EncoderFactory(array(
86+
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha256'),
87+
'encoder_name' => new MessageDigestPasswordEncoder('sha1')
88+
));
89+
90+
$encoder = $factory->getEncoder(new EncAwareUser('user', 'pass'));
91+
$expectedEncoder = new MessageDigestPasswordEncoder('sha1');
92+
$this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', ''));
93+
}
94+
95+
public function testGetNullNamedEncoderForEncoderAware()
96+
{
97+
$factory = new EncoderFactory(array(
98+
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'),
99+
'encoder_name' => new MessageDigestPasswordEncoder('sha256')
100+
));
101+
102+
$user = new EncAwareUser('user', 'pass');
103+
$user->encoderName = null;
104+
$encoder = $factory->getEncoder($user);
105+
$expectedEncoder = new MessageDigestPasswordEncoder('sha1');
106+
$this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', ''));
107+
}
108+
109+
/**
110+
* @expectedException RuntimeException
111+
*/
112+
public function testGetInvalidNamedEncoderForEncoderAware()
113+
{
114+
$factory = new EncoderFactory(array(
115+
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'),
116+
'encoder_name' => new MessageDigestPasswordEncoder('sha256')
117+
));
118+
119+
$user = new EncAwareUser('user', 'pass');
120+
$user->encoderName = 'invalid_encoder_name';
121+
$encoder = $factory->getEncoder($user);
122+
}
123+
124+
public function testGetEncoderForEncoderAwareWithClassName()
125+
{
126+
$factory = new EncoderFactory(array(
127+
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'),
128+
'encoder_name' => new MessageDigestPasswordEncoder('sha256')
129+
));
130+
131+
$encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser');
132+
$expectedEncoder = new MessageDigestPasswordEncoder('sha1');
133+
$this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', ''));
134+
}
81135
}
82136

83137
class SomeUser implements UserInterface
@@ -92,3 +146,13 @@ public function eraseCredentials() {}
92146
class SomeChildUser extends SomeUser
93147
{
94148
}
149+
150+
class EncAwareUser extends SomeUser implements EncoderAwareInterface
151+
{
152+
public $encoderName = 'encoder_name';
153+
154+
public function getEncoderName()
155+
{
156+
return $this->encoderName;
157+
}
158+
}

0 commit comments

Comments
 (0)