context listener: hardening user provider handling
This commit is contained in:
parent
5898ec2c5e
commit
0fb09293fd
|
@ -150,6 +150,8 @@ class ContextListener implements ListenerInterface
|
|||
return $token;
|
||||
}
|
||||
|
||||
$userNotFoundByProvider = false;
|
||||
|
||||
foreach ($this->userProviders as $provider) {
|
||||
try {
|
||||
$refreshedUser = $provider->refreshUser($user);
|
||||
|
@ -167,10 +169,14 @@ class ContextListener implements ListenerInterface
|
|||
$this->logger->warning('Username could not be found in the selected user provider.', array('username' => $e->getUsername(), 'provider' => get_class($provider)));
|
||||
}
|
||||
|
||||
return;
|
||||
$userNotFoundByProvider = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($userNotFoundByProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('There is no user provider for user "%s".', get_class($user)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,17 @@ use Symfony\Component\HttpFoundation\Response;
|
|||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\User;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Firewall\ContextListener;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
|
||||
|
@ -238,6 +245,40 @@ class ContextListenerTest extends TestCase
|
|||
$listener->handle($event);
|
||||
}
|
||||
|
||||
public function testTryAllUserProvidersUntilASupportingUserProviderIsFound()
|
||||
{
|
||||
$tokenStorage = new TokenStorage();
|
||||
$refreshedUser = new User('foobar', 'baz');
|
||||
$this->handleEventWithPreviousSession($tokenStorage, array(new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)));
|
||||
|
||||
$this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser());
|
||||
}
|
||||
|
||||
public function testNextSupportingUserProviderIsTriedIfPreviousSupportingUserProviderDidNotLoadTheUser()
|
||||
{
|
||||
$tokenStorage = new TokenStorage();
|
||||
$refreshedUser = new User('foobar', 'baz');
|
||||
$this->handleEventWithPreviousSession($tokenStorage, array(new SupportingUserProvider(), new SupportingUserProvider($refreshedUser)));
|
||||
|
||||
$this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser());
|
||||
}
|
||||
|
||||
public function testTokenIsSetToNullIfNoUserWasLoadedByTheRegisteredUserProviders()
|
||||
{
|
||||
$tokenStorage = new TokenStorage();
|
||||
$this->handleEventWithPreviousSession($tokenStorage, array(new NotSupportingUserProvider(), new SupportingUserProvider()));
|
||||
|
||||
$this->assertNull($tokenStorage->getToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testRuntimeExceptionIsThrownIfNoSupportingUserProviderWasRegistered()
|
||||
{
|
||||
$this->handleEventWithPreviousSession(new TokenStorage(), array(new NotSupportingUserProvider(), new NotSupportingUserProvider()));
|
||||
}
|
||||
|
||||
protected function runSessionOnKernelResponse($newToken, $original = null)
|
||||
{
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
|
@ -265,4 +306,67 @@ class ContextListenerTest extends TestCase
|
|||
|
||||
return $session;
|
||||
}
|
||||
|
||||
private function handleEventWithPreviousSession(TokenStorageInterface $tokenStorage, array $userProviders)
|
||||
{
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
$session->set('_security_context_key', serialize(new UsernamePasswordToken(new User('foo', 'bar'), '', 'context_key')));
|
||||
|
||||
$request = new Request();
|
||||
$request->setSession($session);
|
||||
$request->cookies->set('MOCKSESSID', true);
|
||||
|
||||
$listener = new ContextListener($tokenStorage, $userProviders, 'context_key');
|
||||
$listener->handle(new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
}
|
||||
|
||||
class NotSupportingUserProvider implements UserProviderInterface
|
||||
{
|
||||
public function loadUserByUsername($username)
|
||||
{
|
||||
throw new UsernameNotFoundException();
|
||||
}
|
||||
|
||||
public function refreshUser(UserInterface $user)
|
||||
{
|
||||
throw new UnsupportedUserException();
|
||||
}
|
||||
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class SupportingUserProvider implements UserProviderInterface
|
||||
{
|
||||
private $refreshedUser;
|
||||
|
||||
public function __construct(User $refreshedUser = null)
|
||||
{
|
||||
$this->refreshedUser = $refreshedUser;
|
||||
}
|
||||
|
||||
public function loadUserByUsername($username)
|
||||
{
|
||||
}
|
||||
|
||||
public function refreshUser(UserInterface $user)
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
throw new UnsupportedUserException();
|
||||
}
|
||||
|
||||
if (null === $this->refreshedUser) {
|
||||
throw new UsernameNotFoundException();
|
||||
}
|
||||
|
||||
return $this->refreshedUser;
|
||||
}
|
||||
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return 'Symfony\Component\Security\Core\User\User' === $class;
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue