Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

[DX] New service to simplify password encoding #11306

Merged
merged 1 commit into from

7 participants

@aferrandini
Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #11299
License MIT
Doc PR symfony/symfony-docs#3995

This new service siplifies the way to encode a password. Just get the security.password_encoder service and encode the User password.

$encoded = $this->container->get('security.password_encoder')
    ->encodePassword($user, $plainPassword);

$user->setPassword($encoded);
...nent/Security/Core/Encoder/PasswordEncoderService.php
((33 lines not shown))
+ */
+ public function __construct (EncoderFactoryInterface $encoderFactory)
+ {
+ $this->encoderFactory = $encoderFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword (UserInterface $user, $plainPassword)
+ {
+ $encoder = $this->encoderFactory->getEncoder($user);
+
+ $encoded = $encoder->encodePassword($plainPassword, $user->getSalt());
+
+ return $encoded;
@jakzal Collaborator
jakzal added a note

You could make it more consistent and avoid assignment, just like in the isPasswordValid().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...nent/Security/Core/Encoder/PasswordEncoderService.php
((27 lines not shown))
+ private $encoderFactory;
+
+ /**
+ * Constructor
+ *
+ * @param EncoderFactoryInterface $encoderFactory The encoder factory
+ */
+ public function __construct (EncoderFactoryInterface $encoderFactory)
+ {
+ $this->encoderFactory = $encoderFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword (UserInterface $user, $plainPassword)
@jakzal Collaborator
jakzal added a note

Remove the space before ( (also the case in few other places, run php-cs-fixer).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ity/Core/Tests/Encoder/PasswordEncoderServiceTest.php
((7 lines not shown))
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Encoder;
+
+
+use Symfony\Component\Security\Core\Encoder\PasswordEncoderService;
+
+class PasswordEncoderServiceTest extends \PHPUnit_Framework_TestCase
+{
+ public function testEncodePassword ()
+ {
+ $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $userMock->expects($this->once())
@jakzal Collaborator
jakzal added a note

All the $this->once() should actually be $this->any(). We don't really care if these methods were called, since we're stubbing here (as opposed to mocking).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Nek-

So you don't think that this comment #11299 (comment) is a great idea ? (just not repeat "password")

@aferrandini

@jakzal I've update your comments. Please review it and tell me if I have to change anything else.

@aferrandini

@javiereguiluz we could have both methods, one for validate user password as you mention before and another to validate a password, due to could be a password not stored in the user object.

public function isPasswordValid(UserInterface $user, $encoded, $raw);

public function isUserPasswordValid(UserInterface $user, $raw);
@jakzal
Collaborator

:+1: for @javiereguiluz comment, password is redundant.

@Nek- I think security.password_encoder is a name that reflects the serivce's purpose bettern than security.encoder (what kind of an encoder?). Then, the method names (encodePassword, isPasswordValid) are inline with the encoder factory, so probably what most users would expect.

...nent/Security/Core/Encoder/PasswordEncoderService.php
((7 lines not shown))
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Encoder;
+
+
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * A generic password encoder
+ *
+ * @author Ariel Ferrandini <arielferrandini@gmail.com>
+ */
+class PasswordEncoderService
@jakzal Collaborator
jakzal added a note

PasswordEncoder would be better. We don't use the Service suffix (it doesn't bring much value).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...nent/Security/Core/Encoder/PasswordEncoderService.php
((15 lines not shown))
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * A generic password encoder
+ *
+ * @author Ariel Ferrandini <arielferrandini@gmail.com>
+ */
+class PasswordEncoderService
+{
+ /**
+ * @var EncoderFactoryInterface
+ */
+ private $encoderFactory;
+
+ /**
+ * Constructor
@jakzal Collaborator
jakzal added a note

Remove this please. It's clear the method is a constructor ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@aferrandini

I forgot to implements the PasswordEncoderServiceInterface.

@jakzal I added the Service prefix in order to prevent collision with PasswordEncoderInterface in the same namespace.

@jakzal
Collaborator

Do we need an interface here? It's a helper class and is unlikely to be overriden.

How about calling the class UserPasswordEncoder?

@javiereguiluz javiereguiluz added the DX label
@aferrandini

@jakzal :+1: to the class name UserPasswordEncoder

@aferrandini aferrandini New service to simplify password encoding
7bc190a
@aferrandini

@jakzal changes made, and also passed the php-cs-fixer hope everything it's ok now

@weaverryan
Collaborator

I like this implementation. @aferrandini we should also get a PR (or at least an issue) on symfony/symfony-docs for the changes (which will shorten things!). Can you create one of those?

@aferrandini

@waverryan of course :+1:

@aferrandini

@weaverryan I added a PR to the symfony/symfony-docs repo with documentation.

@weaverryan
Collaborator

@aferrandini you're on fire!

@ggam

@aferrandini docs link point to the current repository (symfony/symfony). I think you should enter the full url https://github.com/symfony/symfony-docs/pull/3995

@aferrandini aferrandini referenced this pull request in symfony/symfony-docs
Merged

[DX] New service to simplify password encoding #3995

@aferrandini

@ggam updated

@fabpot
Owner

:+1:

@fabpot
Owner

Thank you @aferrandini.

@fabpot fabpot merged commit 7bc190a into symfony:master

2 checks passed

Details continuous-integration/travis-ci The Travis CI build passed
Details default Success: Travis, fabbot
@fabpot fabpot referenced this pull request from a commit
@fabpot fabpot feature #11306 [DX] New service to simplify password encoding (aferra…
…ndini)

This PR was merged into the 2.6-dev branch.

Discussion
----------

[DX] New service to simplify password encoding

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #11299
| License       | MIT
| Doc PR | symfony/symfony-docs#3995

This new service siplifies the way to encode a password. Just get the `security.password_encoder` service and encode the `User` password.

```php
$encoded = $this->container->get('security.password_encoder')
    ->encodePassword($user, $plainPassword);

$user->setPassword($encoded);
```

Commits
-------

7bc190a New service to simplify password encoding
eb48706
@weaverryan weaverryan referenced this pull request from a commit in symfony/symfony-docs
@weaverryan weaverryan feature #3995 [DX] New service to simplify password encoding (aferran…
…dini)

This PR was merged into the master branch.

Discussion
----------

[DX] New service to simplify password encoding

| Q             | A
| ------------- | ---
| Doc fix?      | no
| New docs?     | [#11306](symfony/symfony#11306)
| Applies to    | 2.6

Add documentation for symfony/symfony PR [#11306](symfony/symfony#11306)

New service to simplify password encoding.

Commits
-------

785827f New service to simplify password encoding
9de96e6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 5, 2014
  1. @aferrandini

    New service to simplify password encoding

    aferrandini authored
This page is out of date. Refresh to see the latest.
View
7 src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
@@ -10,6 +10,7 @@
<parameter key="security.user_checker.class">Symfony\Component\Security\Core\User\UserChecker</parameter>
<parameter key="security.encoder_factory.generic.class">Symfony\Component\Security\Core\Encoder\EncoderFactory</parameter>
+ <parameter key="security.user_password_encoder.generic.class">Symfony\Component\Security\Core\Encoder\UserPasswordEncoder</parameter>
<parameter key="security.encoder.digest.class">Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder</parameter>
<parameter key="security.encoder.plain.class">Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder</parameter>
<parameter key="security.encoder.pbkdf2.class">Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder</parameter>
@@ -80,6 +81,12 @@
<service id="security.encoder_factory" alias="security.encoder_factory.generic"></service>
+ <service id="security.user_password_encoder.generic" class="%security.user_password_encoder.generic.class%" public="false">
+ <argument type="service" id="security.encoder_factory"></argument>
+ </service>
+
+ <service id="security.password_encoder" alias="security.user_password_encoder.generic"></service>
+
<service id="security.user_checker" class="%security.user_checker.class%" public="false" />
<service id="security.expression_language" class="%security.expression_language.class%" public="false" />
View
55 src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Encoder;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * A generic password encoder
+ *
+ * @author Ariel Ferrandini <arielferrandini@gmail.com>
+ */
+class UserPasswordEncoder implements UserPasswordEncoderInterface
+{
+ /**
+ * @var EncoderFactoryInterface
+ */
+ private $encoderFactory;
+
+ /**
+ * @param EncoderFactoryInterface $encoderFactory The encoder factory
+ */
+ public function __construct(EncoderFactoryInterface $encoderFactory)
+ {
+ $this->encoderFactory = $encoderFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword(UserInterface $user, $plainPassword)
+ {
+ $encoder = $this->encoderFactory->getEncoder($user);
+
+ return $encoder->encodePassword($plainPassword, $user->getSalt());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPasswordValid(UserInterface $user, $raw)
+ {
+ $encoder = $this->encoderFactory->getEncoder($user);
+
+ return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt());
+ }
+}
View
41 src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoderInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Encoder;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * UserPasswordEncoderInterface is the interface for the password encoder service.
+ *
+ * @author Ariel Ferrandini <arielferrandini@gmail.com>
+ */
+interface UserPasswordEncoderInterface
+{
+ /**
+ *
+ * Encodes the plain password.
+ *
+ * @param UserInterface $user The user
+ * @param string $plainPassword The password to encode
+ *
+ * @return string The encoded password
+ */
+ public function encodePassword(UserInterface $user, $plainPassword);
+
+ /**
+ * @param UserInterface $user The user
+ * @param string $raw A raw password
+ *
+ * @return bool true if the password is valid, false otherwise
+ */
+ public function isPasswordValid(UserInterface $user, $raw);
+}
View
70 src/Symfony/Component/Security/Core/Tests/Encoder/UserPasswordEncoderTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Encoder;
+
+use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder;
+
+class UserPasswordEncoderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testEncodePassword()
+ {
+ $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $userMock->expects($this->any())
+ ->method('getSalt')
+ ->will($this->returnValue('userSalt'));
+
+ $mockEncoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface');
+ $mockEncoder->expects($this->any())
+ ->method('encodePassword')
+ ->with($this->equalTo('plainPassword'), $this->equalTo('userSalt'))
+ ->will($this->returnValue('encodedPassword'));
+
+ $mockEncoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface');
+ $mockEncoderFactory->expects($this->any())
+ ->method('getEncoder')
+ ->with($this->equalTo($userMock))
+ ->will($this->returnValue($mockEncoder));
+
+ $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory);
+
+ $encoded = $passwordEncoder->encodePassword($userMock, 'plainPassword');
+ $this->assertEquals('encodedPassword', $encoded);
+ }
+
+ public function testIsPasswordValid()
+ {
+ $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $userMock->expects($this->any())
+ ->method('getSalt')
+ ->will($this->returnValue('userSalt'));
+ $userMock->expects($this->any())
+ ->method('getPassword')
+ ->will($this->returnValue('encodedPassword'));
+
+ $mockEncoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface');
+ $mockEncoder->expects($this->any())
+ ->method('isPasswordValid')
+ ->with($this->equalTo('encodedPassword'), $this->equalTo('plainPassword'), $this->equalTo('userSalt'))
+ ->will($this->returnValue(true));
+
+ $mockEncoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface');
+ $mockEncoderFactory->expects($this->any())
+ ->method('getEncoder')
+ ->with($this->equalTo($userMock))
+ ->will($this->returnValue($mockEncoder));
+
+ $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory);
+
+ $isValid = $passwordEncoder->isPasswordValid($userMock, 'plainPassword');
+ $this->assertTrue($isValid);
+ }
+}
Something went wrong with that request. Please try again.