[Security] Lazy load user providers
This commit is contained in:
parent
d43355c6d8
commit
d7914a6a7d
@ -245,7 +245,7 @@ class SecurityExtension extends Extension
|
||||
foreach ($providerIds as $userProviderId) {
|
||||
$userProviders[] = new Reference($userProviderId);
|
||||
}
|
||||
$arguments[1] = $userProviders;
|
||||
$arguments[1] = new IteratorArgument($userProviders);
|
||||
$definition->setArguments($arguments);
|
||||
|
||||
$customUserChecker = false;
|
||||
@ -613,7 +613,7 @@ class SecurityExtension extends Extension
|
||||
|
||||
$container
|
||||
->setDefinition($name, new ChildDefinition('security.user.provider.chain'))
|
||||
->addArgument($providers);
|
||||
->addArgument(new IteratorArgument($providers));
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
|
||||
@ -57,10 +58,10 @@ abstract class CompleteConfigurationTest extends TestCase
|
||||
$this->assertEquals(array(), array_diff($providers, $expectedProviders));
|
||||
|
||||
// chain provider
|
||||
$this->assertEquals(array(array(
|
||||
$this->assertEquals(array(new IteratorArgument(array(
|
||||
new Reference('security.user.provider.concrete.service'),
|
||||
new Reference('security.user.provider.concrete.basic'),
|
||||
)), $container->getDefinition('security.user.provider.concrete.chain')->getArguments());
|
||||
))), $container->getDefinition('security.user.provider.concrete.chain')->getArguments());
|
||||
}
|
||||
|
||||
public function testFirewalls()
|
||||
|
@ -172,6 +172,26 @@ class ChainUserProviderTest extends TestCase
|
||||
$this->assertFalse($provider->supportsClass('foo'));
|
||||
}
|
||||
|
||||
public function testAcceptsTraversable()
|
||||
{
|
||||
$provider1 = $this->getProvider();
|
||||
$provider1
|
||||
->expects($this->once())
|
||||
->method('refreshUser')
|
||||
->will($this->throwException(new UnsupportedUserException('unsupported')))
|
||||
;
|
||||
|
||||
$provider2 = $this->getProvider();
|
||||
$provider2
|
||||
->expects($this->once())
|
||||
->method('refreshUser')
|
||||
->will($this->returnValue($account = $this->getAccount()))
|
||||
;
|
||||
|
||||
$provider = new ChainUserProvider(new \ArrayObject(array($provider1, $provider2)));
|
||||
$this->assertSame($account, $provider->refreshUser($this->getAccount()));
|
||||
}
|
||||
|
||||
protected function getAccount()
|
||||
{
|
||||
return $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
|
||||
|
@ -26,7 +26,10 @@ class ChainUserProvider implements UserProviderInterface
|
||||
{
|
||||
private $providers;
|
||||
|
||||
public function __construct(array $providers)
|
||||
/**
|
||||
* @param iterable|UserProviderInterface[] $providers
|
||||
*/
|
||||
public function __construct($providers)
|
||||
{
|
||||
$this->providers = $providers;
|
||||
}
|
||||
@ -36,6 +39,10 @@ class ChainUserProvider implements UserProviderInterface
|
||||
*/
|
||||
public function getProviders()
|
||||
{
|
||||
if ($this->providers instanceof \Traversable) {
|
||||
return iterator_to_array($this->providers);
|
||||
}
|
||||
|
||||
return $this->providers;
|
||||
}
|
||||
|
||||
|
@ -44,18 +44,20 @@ class ContextListener implements ListenerInterface
|
||||
private $registered;
|
||||
private $trustResolver;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, array $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, AuthenticationTrustResolverInterface $trustResolver = null)
|
||||
/**
|
||||
* @param TokenStorageInterface $tokenStorage
|
||||
* @param iterable|UserProviderInterface[] $userProviders
|
||||
* @param string $contextKey
|
||||
* @param LoggerInterface|null $logger
|
||||
* @param EventDispatcherInterface|null $dispatcher
|
||||
* @param AuthenticationTrustResolverInterface|null $trustResolver
|
||||
*/
|
||||
public function __construct(TokenStorageInterface $tokenStorage, $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, AuthenticationTrustResolverInterface $trustResolver = null)
|
||||
{
|
||||
if (empty($contextKey)) {
|
||||
throw new \InvalidArgumentException('$contextKey must not be empty.');
|
||||
}
|
||||
|
||||
foreach ($userProviders as $userProvider) {
|
||||
if (!$userProvider instanceof UserProviderInterface) {
|
||||
throw new \InvalidArgumentException(sprintf('User provider "%s" must implement "Symfony\Component\Security\Core\User\UserProviderInterface".', get_class($userProvider)));
|
||||
}
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->userProviders = $userProviders;
|
||||
$this->contextKey = $contextKey;
|
||||
@ -158,6 +160,10 @@ class ContextListener implements ListenerInterface
|
||||
$userNotFoundByProvider = false;
|
||||
|
||||
foreach ($this->userProviders as $provider) {
|
||||
if (!$provider instanceof UserProviderInterface) {
|
||||
throw new \InvalidArgumentException(sprintf('User provider "%s" must implement "%s".', get_class($provider), UserProviderInterface::class));
|
||||
}
|
||||
|
||||
try {
|
||||
$refreshedUser = $provider->refreshUser($user);
|
||||
$token->setUser($refreshedUser);
|
||||
|
@ -53,11 +53,7 @@ class ContextListenerTest extends TestCase
|
||||
*/
|
||||
public function testUserProvidersNeedToImplementAnInterface()
|
||||
{
|
||||
new ContextListener(
|
||||
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock(),
|
||||
array(new \stdClass()),
|
||||
'key123'
|
||||
);
|
||||
$this->handleEventWithPreviousSession(new TokenStorage(), array(new \stdClass()));
|
||||
}
|
||||
|
||||
public function testOnKernelResponseWillAddSession()
|
||||
@ -287,6 +283,15 @@ class ContextListenerTest extends TestCase
|
||||
$this->handleEventWithPreviousSession(new TokenStorage(), array(new NotSupportingUserProvider(), new NotSupportingUserProvider()));
|
||||
}
|
||||
|
||||
public function testAcceptsProvidersAsTraversable()
|
||||
{
|
||||
$tokenStorage = new TokenStorage();
|
||||
$refreshedUser = new User('foobar', 'baz');
|
||||
$this->handleEventWithPreviousSession($tokenStorage, new \ArrayObject(array(new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser))));
|
||||
|
||||
$this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser());
|
||||
}
|
||||
|
||||
protected function runSessionOnKernelResponse($newToken, $original = null)
|
||||
{
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
@ -315,7 +320,7 @@ class ContextListenerTest extends TestCase
|
||||
return $session;
|
||||
}
|
||||
|
||||
private function handleEventWithPreviousSession(TokenStorageInterface $tokenStorage, array $userProviders)
|
||||
private function handleEventWithPreviousSession(TokenStorageInterface $tokenStorage, $userProviders)
|
||||
{
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
$session->set('_security_context_key', serialize(new UsernamePasswordToken(new User('foo', 'bar'), '', 'context_key')));
|
||||
|
Reference in New Issue
Block a user