diff --git a/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php b/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php index 4b1e4073b9..a727371409 100644 --- a/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/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 authenticate($credentials, UserProviderInterface $userProvider); + 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 checkCredentials($credentials, UserInterface $user); /** * Create an authenticated token for the given user. diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index 4fefee3b89..eb9ef31e43 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/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/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php b/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php index 99e9b5d206..24c946d0e1 100644 --- a/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/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')