Renaming the tokens to be clear they are "post" and "pre" auth - also adding an interface

The reason is that the GuardAuthenticationProvider *must* respond to *all* tokens
created by the system - both "pre auth" and "post auth" tokens. The reason is that
if a "post auth" token becomes not authenticated (e.g. because the user changes between
requests), then it may be passed to the provider system. If no providers respond (which
was the case before this commit), then AuthenticationProviderManager throws an exception.

The next commit will properly handle these "post auth" + "no-longer-authenticated" tokens,
which should cause a log out.
This commit is contained in:
Ryan Weaver 2015-05-17 17:27:01 -04:00
parent a0bceb43c9
commit 873ed284d2
8 changed files with 45 additions and 30 deletions

View File

@ -3,26 +3,26 @@
namespace Symfony\Component\Security\Guard;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\Token\GenericGuardToken;
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
/**
* An optional base class that creates a GenericGuardToken for you
* An optional base class that creates a PostAuthenticationGuardToken for you
*
* @author Ryan Weaver <weaverryan@gmail.com>
*/
abstract class AbstractGuardAuthenticator implements GuardAuthenticatorInterface
{
/**
* Shortcut to create a GenericGuardToken for you, if you don't really
* Shortcut to create a PostAuthenticationGuardToken for you, if you don't really
* care about which authenticated token you're using
*
* @param UserInterface $user
* @param string $providerKey
* @return GenericGuardToken
* @return PostAuthenticationGuardToken
*/
public function createAuthenticatedToken(UserInterface $user, $providerKey)
{
return new GenericGuardToken(
return new PostAuthenticationGuardToken(
$user,
$providerKey,
$user->getRoles()

View File

@ -6,7 +6,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Component\Security\Guard\Token\NonAuthenticatedGuardToken;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
use Psr\Log\LoggerInterface;
@ -86,7 +86,7 @@ class GuardAuthenticationListener implements ListenerInterface
}
// create a token with the unique key, so that the provider knows which authenticator to use
$token = new NonAuthenticatedGuardToken($credentials, $uniqueGuardKey);
$token = new PreAuthenticationGuardToken($credentials, $uniqueGuardKey);
if (null !== $this->logger) {
$this->logger->info('Passing guard token information to the GuardAuthenticationProvider', array('firewall_key' => $this->providerKey, 'authenticator' => get_class($guardAuthenticator)));

View File

@ -3,15 +3,18 @@
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\AuthenticationException;
use Symfony\Component\Security\Guard\GuardAuthenticatorInterface;
use Symfony\Component\Security\Guard\Token\NonAuthenticatedGuardToken;
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* Responsible for accepting the NonAuthenticatedGuardToken and calling
* Responsible for accepting the PreAuthenticationGuardToken and calling
* the correct authenticator to retrieve the authenticated token
*
* @author Ryan Weaver <weaverryan@gmail.com>
@ -43,12 +46,12 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
/**
* Finds the correct authenticator for the token and calls it
*
* @param NonAuthenticatedGuardToken $token
* @param GuardTokenInterface $token
* @return TokenInterface
*/
public function authenticate(TokenInterface $token)
{
if (!$token instanceof NonAuthenticatedGuardToken) {
if (!$this->supports($token)) {
throw new \InvalidArgumentException('GuardAuthenticationProvider only supports NonAuthenticatedGuardToken');
}
@ -69,7 +72,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
));
}
private function authenticateViaGuard(GuardAuthenticatorInterface $guardAuthenticator, NonAuthenticatedGuardToken $token)
private function authenticateViaGuard(GuardAuthenticatorInterface $guardAuthenticator, PreAuthenticationGuardToken $token)
{
// get the user from the GuardAuthenticator
$user = $guardAuthenticator->authenticate($token->getCredentials(), $this->userProvider);
@ -101,6 +104,6 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
public function supports(TokenInterface $token)
{
return $token instanceof NonAuthenticatedGuardToken;
return $token instanceof GuardTokenInterface;
}
}

View File

@ -14,7 +14,7 @@ namespace Symfony\Component\Security\Guard\Tests\Firewall;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Guard\Firewall\GuardAuthenticationListener;
use Symfony\Component\Security\Guard\Token\NonAuthenticatedGuardToken;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
/**
@ -44,7 +44,7 @@ class GuardAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
// a clone of the token that should be created internally
$uniqueGuardKey = 'my_firewall_0';
$nonAuthedToken = new NonAuthenticatedGuardToken($credentials, $uniqueGuardKey);
$nonAuthedToken = new PreAuthenticationGuardToken($credentials, $uniqueGuardKey);
$this->authenticationManager
->expects($this->once())

View File

@ -20,7 +20,7 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
{
private $userProvider;
private $userChecker;
private $nonAuthedToken;
private $preAuthenticationToken;
public function testAuthenticate()
{
@ -32,7 +32,7 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
$authenticators = array($authenticatorA, $authenticatorB, $authenticatorC);
// called 2 times - for authenticator A and B (stops on B because of match)
$this->nonAuthedToken->expects($this->exactly(2))
$this->preAuthenticationToken->expects($this->exactly(2))
->method('getGuardProviderKey')
// it will return the "1" index, which will match authenticatorB
->will($this->returnValue('my_cool_firewall_1'));
@ -41,7 +41,7 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
'username' => '_weaverryan_test_user',
'password' => 'guard_auth_ftw',
);
$this->nonAuthedToken->expects($this->once())
$this->preAuthenticationToken->expects($this->once())
->method('getCredentials')
->will($this->returnValue($enteredCredentials));
@ -71,7 +71,7 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
->with($mockedUser);
$provider = new GuardAuthenticationProvider($authenticators, $this->userProvider, $providerKey, $this->userChecker);
$actualAuthedToken = $provider->authenticate($this->nonAuthedToken);
$actualAuthedToken = $provider->authenticate($this->preAuthenticationToken);
$this->assertSame($authedToken, $actualAuthedToken);
}
@ -79,7 +79,7 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
{
$this->userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
$this->userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
$this->nonAuthedToken = $this->getMockBuilder('Symfony\Component\Security\Guard\Token\NonAuthenticatedGuardToken')
$this->preAuthenticationToken = $this->getMockBuilder('Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken')
->disableOriginalConstructor()
->getMock();
}
@ -88,6 +88,6 @@ class GuardAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
{
$this->userProvider = null;
$this->userChecker = null;
$this->nonAuthedToken = null;
$this->preAuthenticationToken = null;
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Symfony\Component\Security\Guard\Token;
/**
* An empty interface that both guard tokens implement
*
* This interface is used by the GuardAuthenticationProvider to know
* that a token belongs to its system.
*
* @author Ryan Weaver <weaverryan@gmail.com>
*/
interface GuardTokenInterface
{
}

View File

@ -7,17 +7,14 @@ use Symfony\Component\Security\Core\Role\RoleInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* A generic token used by the AbstractGuardAuthenticator
* Used as an "authenticated" token, though it could be set to not-authenticated later.
*
* This is meant to be used as an "authenticated" token, though it
* could be set to not-authenticated later.
*
* You're free to use this (it's simple) or use any other token for
* your authenticated token
* If you're using Guard authentication, you *must* use a class that implements
* GuardTokenInterface as your authenticated token (like this class).
*
* @author Ryan Weaver <weaverryan@gmail.com>
*/
class GenericGuardToken extends AbstractToken
class PostAuthenticationGuardToken extends AbstractToken implements GuardTokenInterface
{
private $providerKey;

View File

@ -13,7 +13,7 @@ use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
*
* @author Ryan Weaver <weaverryan@gmail.com>
*/
class NonAuthenticatedGuardToken extends AbstractToken
class PreAuthenticationGuardToken extends AbstractToken implements GuardTokenInterface
{
private $credentials;
private $guardProviderKey;
@ -51,6 +51,6 @@ class NonAuthenticatedGuardToken extends AbstractToken
public function setAuthenticated($authenticated)
{
throw new \Exception('The NonAuthenticatedGuardToken is *always* not authenticated');
throw new \Exception('The PreAuthenticationGuardToken is *always* not authenticated');
}
}