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.
This commit is contained in:
parent
6edb9e1b06
commit
ffdbc66534
@ -27,7 +27,7 @@ interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface
|
|||||||
* as any type (e.g. an associate array). If you return null, authentication
|
* as any type (e.g. an associate array). If you return null, authentication
|
||||||
* will be skipped.
|
* 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:
|
* For example, for a form login, you might:
|
||||||
*
|
*
|
||||||
@ -47,19 +47,33 @@ interface GuardAuthenticatorInterface extends AuthenticationEntryPointInterface
|
|||||||
public function getCredentials(Request $request);
|
public function getCredentials(Request $request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a UserInterface object based on the credentials OR throw
|
* Return a UserInterface object based on the credentials
|
||||||
* an AuthenticationException.
|
|
||||||
*
|
*
|
||||||
* The *credentials* are the return value from getCredentials()
|
* 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 mixed $credentials
|
||||||
* @param UserProviderInterface $userProvider
|
* @param UserProviderInterface $userProvider
|
||||||
*
|
*
|
||||||
* @throws AuthenticationException
|
* @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.
|
* Create an authenticated token for the given user.
|
||||||
|
@ -4,6 +4,7 @@ namespace Symfony\Component\Security\Guard\Provider;
|
|||||||
|
|
||||||
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
|
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\GuardAuthenticatorInterface;
|
||||||
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
|
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
|
||||||
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
||||||
@ -95,18 +96,28 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
|||||||
private function authenticateViaGuard(GuardAuthenticatorInterface $guardAuthenticator, PreAuthenticationGuardToken $token)
|
private function authenticateViaGuard(GuardAuthenticatorInterface $guardAuthenticator, PreAuthenticationGuardToken $token)
|
||||||
{
|
{
|
||||||
// get the user from the GuardAuthenticator
|
// 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) {
|
if (!$user instanceof UserInterface) {
|
||||||
throw new \UnexpectedValueException(sprintf(
|
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),
|
get_class($guardAuthenticator),
|
||||||
is_object($user) ? get_class($user) : gettype($user)
|
is_object($user) ? get_class($user) : gettype($user)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the AdvancedUserInterface methods!
|
// check the preAuth UserChecker
|
||||||
$this->userChecker->checkPreAuth($user);
|
$this->userChecker->checkPreAuth($user);
|
||||||
|
// check the credentials
|
||||||
|
$guardAuthenticator->checkCredentials($token->getCredentials(), $user);
|
||||||
|
// check the postAuth UserChecker
|
||||||
$this->userChecker->checkPostAuth($user);
|
$this->userChecker->checkPostAuth($user);
|
||||||
|
|
||||||
// turn the UserInterface into a TokenInterface
|
// turn the UserInterface into a TokenInterface
|
||||||
|
@ -43,21 +43,25 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
|
|||||||
'username' => '_weaverryan_test_user',
|
'username' => '_weaverryan_test_user',
|
||||||
'password' => 'guard_auth_ftw',
|
'password' => 'guard_auth_ftw',
|
||||||
);
|
);
|
||||||
$this->preAuthenticationToken->expects($this->once())
|
$this->preAuthenticationToken->expects($this->atLeastOnce())
|
||||||
->method('getCredentials')
|
->method('getCredentials')
|
||||||
->will($this->returnValue($enteredCredentials));
|
->will($this->returnValue($enteredCredentials));
|
||||||
|
|
||||||
// authenticators A and C are never called
|
// authenticators A and C are never called
|
||||||
$authenticatorA->expects($this->never())
|
$authenticatorA->expects($this->never())
|
||||||
->method('authenticate');
|
->method('getUser');
|
||||||
$authenticatorC->expects($this->never())
|
$authenticatorC->expects($this->never())
|
||||||
->method('authenticate');
|
->method('getUser');
|
||||||
|
|
||||||
$mockedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
|
$mockedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
|
||||||
$authenticatorB->expects($this->once())
|
$authenticatorB->expects($this->once())
|
||||||
->method('authenticate')
|
->method('getUser')
|
||||||
->with($enteredCredentials, $this->userProvider)
|
->with($enteredCredentials, $this->userProvider)
|
||||||
->will($this->returnValue($mockedUser));
|
->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');
|
$authedToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
|
||||||
$authenticatorB->expects($this->once())
|
$authenticatorB->expects($this->once())
|
||||||
->method('createAuthenticatedToken')
|
->method('createAuthenticatedToken')
|
||||||
|
Reference in New Issue
Block a user