summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Weaver <ryan@thatsquality.com>2015-05-18 09:14:21 -0400
committerRyan Weaver <ryan@thatsquality.com>2015-09-20 19:24:21 -0400
commit182111856105a1f080bcee931e7fe0af40e55fec (patch)
treea2008b53a5bbb81fd0115c46dfa64aefdeb19135
parentdd9cccbeed41777f2e0c30d990a47737e8701cc7 (diff)
downloadsymfony-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.php24
-rw-r--r--Guard/Provider/GuardAuthenticationProvider.php17
-rw-r--r--Guard/Tests/Provider/GuardAuthenticationProviderTest.php12
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')