diff options
author | Ryan Weaver <ryan@thatsquality.com> | 2015-05-18 09:14:21 -0400 |
---|---|---|
committer | Ryan Weaver <ryan@thatsquality.com> | 2015-09-20 19:24:21 -0400 |
commit | 182111856105a1f080bcee931e7fe0af40e55fec (patch) | |
tree | a2008b53a5bbb81fd0115c46dfa64aefdeb19135 | |
parent | dd9cccbeed41777f2e0c30d990a47737e8701cc7 (diff) | |
download | symfony-security-182111856105a1f080bcee931e7fe0af40e55fec.zip symfony-security-182111856105a1f080bcee931e7fe0af40e55fec.tar.gz symfony-security-182111856105a1f080bcee931e7fe0af40e55fec.tar.bz2 |
Splitting the getting of the user and checking credentials into two steps
This looks like a subjective change (one more method, but the method implementations are
simpler), but it wasn't. The problem was that the UserChecker checkPreAuth should happen
*after* we get the user, but *before* the credentials are checked, and that wasn't possible
before this change. Now it is.
-rw-r--r-- | Guard/GuardAuthenticatorInterface.php | 24 | ||||
-rw-r--r-- | Guard/Provider/GuardAuthenticationProvider.php | 17 | ||||
-rw-r--r-- | Guard/Tests/Provider/GuardAuthenticationProviderTest.php | 12 |
3 files changed, 41 insertions, 12 deletions
diff --git a/Guard/GuardAuthenticatorInterface.php b/Guard/GuardAuthenticatorInterface.php index 4b1e407..a727371 100644 --- a/Guard/GuardAuthenticatorInterface.php +++ b/Guard/GuardAuthenticatorInterface.php @@ -27,7 +27,7 @@ interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface * as any type (e.g. an associate array). If you return null, authentication * will be skipped. * - * Whatever value you return here will be passed to authenticate() + * Whatever value you return here will be passed to getUser() and checkCredentials() * * For example, for a form login, you might: * @@ -47,19 +47,33 @@ interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface public function getCredentials(Request $request); /** - * Return a UserInterface object based on the credentials OR throw - * an AuthenticationException. + * Return a UserInterface object based on the credentials * * The *credentials* are the return value from getCredentials() * + * You may throw an AuthenticationException if you wish. If you return + * null, then a UsernameNotFoundException is thrown for you. + * * @param mixed $credentials * @param UserProviderInterface $userProvider * * @throws AuthenticationException * - * @return UserInterface + * @return UserInterface|null + */ + public function getUser($credentials, UserProviderInterface $userProvider); + + /** + * Throw an AuthenticationException if the credentials are invalid + * + * The *credentials* are the return value from getCredentials() + * + * @param mixed $credentials + * @param UserInterface $user + * @throws AuthenticationException + * @return void */ - public function authenticate($credentials, UserProviderInterface $userProvider); + public function checkCredentials($credentials, UserInterface $user); /** * Create an authenticated token for the given user. diff --git a/Guard/Provider/GuardAuthenticationProvider.php b/Guard/Provider/GuardAuthenticationProvider.php index 4fefee3..eb9ef31 100644 --- a/Guard/Provider/GuardAuthenticationProvider.php +++ b/Guard/Provider/GuardAuthenticationProvider.php @@ -4,6 +4,7 @@ namespace Symfony\Component\Security\Guard\Provider; use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Guard\GuardAuthenticatorInterface; use Symfony\Component\Security\Guard\Token\GuardTokenInterface; use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken; @@ -95,18 +96,28 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface private function authenticateViaGuard(GuardAuthenticatorInterface $guardAuthenticator, PreAuthenticationGuardToken $token) { // get the user from the GuardAuthenticator - $user = $guardAuthenticator->authenticate($token->getCredentials(), $this->userProvider); + $user = $guardAuthenticator->getUser($token->getCredentials(), $this->userProvider); + + if (null === $user) { + throw new UsernameNotFoundException(sprintf( + 'Null returned from %s::getUser()', + get_class($guardAuthenticator) + )); + } if (!$user instanceof UserInterface) { throw new \UnexpectedValueException(sprintf( - 'The %s::authenticate method must return a UserInterface. You returned %s.', + 'The %s::getUser method must return a UserInterface. You returned %s.', get_class($guardAuthenticator), is_object($user) ? get_class($user) : gettype($user) )); } - // check the AdvancedUserInterface methods! + // check the preAuth UserChecker $this->userChecker->checkPreAuth($user); + // check the credentials + $guardAuthenticator->checkCredentials($token->getCredentials(), $user); + // check the postAuth UserChecker $this->userChecker->checkPostAuth($user); // turn the UserInterface into a TokenInterface diff --git a/Guard/Tests/Provider/GuardAuthenticationProviderTest.php b/Guard/Tests/Provider/GuardAuthenticationProviderTest.php index 99e9b5d..24c946d 100644 --- a/Guard/Tests/Provider/GuardAuthenticationProviderTest.php +++ b/Guard/Tests/Provider/GuardAuthenticationProviderTest.php @@ -43,21 +43,25 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase 'username' => '_weaverryan_test_user', 'password' => 'guard_auth_ftw', ); - $this->preAuthenticationToken->expects($this->once()) + $this->preAuthenticationToken->expects($this->atLeastOnce()) ->method('getCredentials') ->will($this->returnValue($enteredCredentials)); // authenticators A and C are never called $authenticatorA->expects($this->never()) - ->method('authenticate'); + ->method('getUser'); $authenticatorC->expects($this->never()) - ->method('authenticate'); + ->method('getUser'); $mockedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); $authenticatorB->expects($this->once()) - ->method('authenticate') + ->method('getUser') ->with($enteredCredentials, $this->userProvider) ->will($this->returnValue($mockedUser)); + // checkCredentials is called + $authenticatorB->expects($this->once()) + ->method('checkCredentials') + ->with($enteredCredentials, $mockedUser); $authedToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); $authenticatorB->expects($this->once()) ->method('createAuthenticatedToken') |