Merge branch '4.4' into 5.0
* 4.4: [DI] auto-register singly implemented interfaces by default [DI] fix overriding existing services with aliases for singly-implemented interfaces remove service when base class is missing do not depend on the QueryBuilder from the ORM [Security/Http] call auth listeners/guards eagerly when they "support" the request [Messenger] add tests to FailedMessagesShowCommand Fix the translation commands when a template contains a syntax error [Security] Fix clearing remember-me cookie after deauthentication [Validator] Update Slovenian translations [HttpClient] remove conflict rule with HttpKernel that prevents using the component in Symfony 3.4 [Config][ReflectionClassResource] Handle parameters with undefined constant as their default values fix dumping number-like string parameters Fix CI [Console] Fix autocomplete multibyte input support [Config] don't break on virtual stack frames in ClassExistenceResource more robust initialization from request Changing the multipart form-data behavior to use the form name as an array, which makes it recognizable as an array by PHP on the $_POST globals once it is coming from the HttpClient component
This commit is contained in:
commit
bb11cac33e
@ -266,6 +266,11 @@ install:
|
||||
run_tests () {
|
||||
set -e
|
||||
export PHP=$1
|
||||
|
||||
if [[ !$deps && $PHP = 7.2 ]]; then
|
||||
tfold src/Symfony/Component/HttpClient.h2push "$COMPOSER_UP symfony/contracts && docker run -it --rm -v $(pwd):/app -v $(phpenv which composer):/usr/local/bin/composer -v /usr/local/bin/vulcain:/usr/local/bin/vulcain -w /app php:7.3-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push"
|
||||
fi
|
||||
|
||||
if [[ $PHP != 7.4* && $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then
|
||||
echo -e "\\n\\e[33;1mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"
|
||||
return
|
||||
@ -312,10 +317,6 @@ install:
|
||||
PHPUNIT_X="$PHPUNIT_X,legacy"
|
||||
fi
|
||||
|
||||
if [[ $PHP = ${MIN_PHP%.*} ]]; then
|
||||
tfold src/Symfony/Component/HttpClient.h2push docker run -it --rm -v $(pwd):/app -v /usr/local/bin/vulcain:/usr/local/bin/vulcain -w /app php:7.3-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push
|
||||
fi
|
||||
|
||||
echo "$COMPONENTS" | parallel --gnu "tfold {} $PHPUNIT_X {}"
|
||||
|
||||
tfold src/Symfony/Component/Console.tty $PHPUNIT --group tty
|
||||
|
@ -222,6 +222,7 @@ Security
|
||||
* The `LdapUserProvider` class has been deprecated, use `Symfony\Component\Ldap\Security\LdapUserProvider` instead.
|
||||
* Implementations of `PasswordEncoderInterface` and `UserPasswordEncoderInterface` should add a new `needsRehash()` method
|
||||
* Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`. Please explicitly return `false` to indicate invalid credentials.
|
||||
* The `ListenerInterface` is deprecated, extend `AbstractListener` instead.
|
||||
* Deprecated passing more than one attribute to `AccessDecisionManager::decide()` and `AuthorizationChecker::isGranted()` (and indirectly the `is_granted()` Twig and ExpressionLanguage function)
|
||||
|
||||
**Before**
|
||||
|
@ -437,7 +437,7 @@ Security
|
||||
* `SimpleAuthenticatorInterface`, `SimpleFormAuthenticatorInterface`, `SimplePreAuthenticatorInterface`,
|
||||
`SimpleAuthenticationProvider`, `SimpleAuthenticationHandler`, `SimpleFormAuthenticationListener` and
|
||||
`SimplePreAuthenticationListener` have been removed. Use Guard instead.
|
||||
* The `ListenerInterface` has been removed, turn your listeners into callables instead.
|
||||
* The `ListenerInterface` has been removed, extend `AbstractListener` instead.
|
||||
* The `Firewall::handleRequest()` method has been removed, use `Firewall::callListeners()` instead.
|
||||
* `\Serializable` interface has been removed from `AbstractToken` and `AuthenticationException`,
|
||||
thus `serialize()` and `unserialize()` aren't available.
|
||||
|
@ -14,7 +14,6 @@ namespace Symfony\Bridge\Doctrine\Form\Type;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader;
|
||||
use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface;
|
||||
use Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader;
|
||||
@ -82,13 +81,16 @@ abstract class DoctrineType extends AbstractType implements ResetInterface
|
||||
* For instance in ORM two query builders with an equal SQL string and
|
||||
* equal parameters are considered to be equal.
|
||||
*
|
||||
* @param object $queryBuilder A query builder, type declaration is not present here as there
|
||||
* is no common base class for the different implementations
|
||||
*
|
||||
* @return array|null Array with important QueryBuilder parts or null if
|
||||
* they can't be determined
|
||||
*
|
||||
* @internal This method is public to be usable as callback. It should not
|
||||
* be used in user code.
|
||||
*/
|
||||
public function getQueryBuilderPartsForCachingHash(QueryBuilder $queryBuilder): ?array
|
||||
public function getQueryBuilderPartsForCachingHash($queryBuilder): ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ class EntityType extends DoctrineType
|
||||
*/
|
||||
public function getLoader(ObjectManager $manager, QueryBuilder $queryBuilder, string $class)
|
||||
{
|
||||
if (!$queryBuilder instanceof QueryBuilder) {
|
||||
throw new \TypeError(sprintf('Expected an instance of %s, but got %s.', QueryBuilder::class, \is_object($queryBuilder) ? \get_class($queryBuilder) : \gettype($queryBuilder)));
|
||||
}
|
||||
|
||||
return new ORMQueryBuilderLoader($queryBuilder);
|
||||
}
|
||||
|
||||
@ -65,11 +69,17 @@ class EntityType extends DoctrineType
|
||||
* We consider two query builders with an equal SQL string and
|
||||
* equal parameters to be equal.
|
||||
*
|
||||
* @param QueryBuilder $queryBuilder
|
||||
*
|
||||
* @internal This method is public to be usable as callback. It should not
|
||||
* be used in user code.
|
||||
*/
|
||||
public function getQueryBuilderPartsForCachingHash(QueryBuilder $queryBuilder): ?array
|
||||
public function getQueryBuilderPartsForCachingHash($queryBuilder): ?array
|
||||
{
|
||||
if (!$queryBuilder instanceof QueryBuilder) {
|
||||
throw new \TypeError(sprintf('Expected an instance of %s, but got %s.', QueryBuilder::class, \is_object($queryBuilder) ? \get_class($queryBuilder) : \gettype($queryBuilder)));
|
||||
}
|
||||
|
||||
return [
|
||||
$queryBuilder->getQuery()->getSQL(),
|
||||
array_map([$this, 'parameterToArray'], $queryBuilder->getParameters()->toArray()),
|
||||
|
@ -17,7 +17,6 @@ use Symfony\Bridge\Twig\Translation\TwigExtractor;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\Error;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
|
||||
class TwigExtractorTest extends TestCase
|
||||
@ -74,31 +73,23 @@ class TwigExtractorTest extends TestCase
|
||||
/**
|
||||
* @dataProvider resourcesWithSyntaxErrorsProvider
|
||||
*/
|
||||
public function testExtractSyntaxError($resources)
|
||||
public function testExtractSyntaxError($resources, array $messages)
|
||||
{
|
||||
$this->expectException('Twig\Error\Error');
|
||||
$twig = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock());
|
||||
$twig->addExtension(new TranslationExtension($this->getMockBuilder(TranslatorInterface::class)->getMock()));
|
||||
|
||||
$extractor = new TwigExtractor($twig);
|
||||
|
||||
try {
|
||||
$extractor->extract($resources, new MessageCatalogue('en'));
|
||||
} catch (Error $e) {
|
||||
$this->assertSame(\dirname(__DIR__).strtr('/Fixtures/extractor/syntax_error.twig', '/', \DIRECTORY_SEPARATOR), $e->getFile());
|
||||
$this->assertSame(1, $e->getLine());
|
||||
$this->assertSame('Unclosed "block".', $e->getMessage());
|
||||
|
||||
throw $e;
|
||||
}
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$extractor->extract($resources, $catalogue);
|
||||
$this->assertSame($messages, $catalogue->all());
|
||||
}
|
||||
|
||||
public function resourcesWithSyntaxErrorsProvider(): array
|
||||
{
|
||||
return [
|
||||
[__DIR__.'/../Fixtures'],
|
||||
[__DIR__.'/../Fixtures/extractor/syntax_error.twig'],
|
||||
[new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig')],
|
||||
[__DIR__.'/../Fixtures', ['messages' => ['Hi!' => 'Hi!']]],
|
||||
[__DIR__.'/../Fixtures/extractor/syntax_error.twig', []],
|
||||
[new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig'), []],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace Symfony\Bridge\Twig\Translation;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
|
||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
@ -58,13 +57,7 @@ class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
try {
|
||||
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
|
||||
} catch (Error $e) {
|
||||
if ($file instanceof \SplFileInfo) {
|
||||
$path = $file->getRealPath() ?: $file->getPathname();
|
||||
$name = $file instanceof SplFileInfo ? $file->getRelativePathname() : $path;
|
||||
$e->setSourceContext(new Source('', $name, $path));
|
||||
}
|
||||
|
||||
throw $e;
|
||||
// ignore errors, these should be fixed by using the linter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,11 @@ class RememberMeFactory implements SecurityFactoryInterface
|
||||
throw new \RuntimeException('Each "security.remember_me_aware" tag must have a provider attribute.');
|
||||
}
|
||||
|
||||
// context listeners don't need a provider
|
||||
if ('none' !== $attribute['provider']) {
|
||||
$userProviders[] = new Reference($attribute['provider']);
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition($serviceId)
|
||||
->addMethodCall('setRememberMeServices', [new Reference($rememberMeServicesId)])
|
||||
|
@ -315,10 +315,11 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
$listeners[] = new Reference('security.channel_listener');
|
||||
|
||||
$contextKey = null;
|
||||
$contextListenerId = null;
|
||||
// Context serializer listener
|
||||
if (false === $firewall['stateless']) {
|
||||
$contextKey = $firewall['context'] ?? $id;
|
||||
$listeners[] = new Reference($this->createContextListener($container, $contextKey));
|
||||
$listeners[] = new Reference($contextListenerId = $this->createContextListener($container, $contextKey));
|
||||
$sessionStrategyId = 'security.authentication.session_strategy';
|
||||
} else {
|
||||
$this->statelessFirewallKeys[] = $id;
|
||||
@ -391,7 +392,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
$configuredEntryPoint = isset($firewall['entry_point']) ? $firewall['entry_point'] : null;
|
||||
|
||||
// Authentication listeners
|
||||
list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint);
|
||||
list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint, $contextListenerId);
|
||||
|
||||
$config->replaceArgument(7, $configuredEntryPoint ?: $defaultEntryPoint);
|
||||
|
||||
@ -404,9 +405,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
}
|
||||
|
||||
// Access listener
|
||||
if ($firewall['stateless'] || empty($firewall['anonymous']['lazy'])) {
|
||||
$listeners[] = new Reference('security.access_listener');
|
||||
}
|
||||
|
||||
// Exception listener
|
||||
$exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $configuredEntryPoint ?: $defaultEntryPoint, $firewall['stateless']));
|
||||
@ -444,7 +443,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
return $this->contextListeners[$contextKey] = $listenerId;
|
||||
}
|
||||
|
||||
private function createAuthenticationListeners(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, ?string $defaultProvider, array $providerIds, ?string $defaultEntryPoint)
|
||||
private function createAuthenticationListeners(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, ?string $defaultProvider, array $providerIds, ?string $defaultEntryPoint, string $contextListenerId = null)
|
||||
{
|
||||
$listeners = [];
|
||||
$hasListeners = false;
|
||||
@ -462,6 +461,10 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
} elseif ('remember_me' === $key || 'anonymous' === $key) {
|
||||
// RememberMeFactory will use the firewall secret when created, AnonymousAuthenticationListener does not load users.
|
||||
$userProvider = null;
|
||||
|
||||
if ('remember_me' === $key && $contextListenerId) {
|
||||
$container->getDefinition($contextListenerId)->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none']);
|
||||
}
|
||||
} elseif ($defaultProvider) {
|
||||
$userProvider = $defaultProvider;
|
||||
} elseif (empty($providerIds)) {
|
||||
|
@ -151,9 +151,7 @@
|
||||
<argument type="service" id="security.exception_listener" />
|
||||
<argument /> <!-- LogoutListener -->
|
||||
<argument /> <!-- FirewallConfig -->
|
||||
<argument type="service" id="security.access_listener" />
|
||||
<argument type="service" id="security.untracked_token_storage" />
|
||||
<argument type="service" id="security.access_map" />
|
||||
</service>
|
||||
|
||||
<service id="security.firewall.config" class="Symfony\Bundle\SecurityBundle\Security\FirewallConfig" abstract="true">
|
||||
|
@ -13,11 +13,8 @@ namespace Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
|
||||
use Symfony\Component\Security\Core\Exception\LazyResponseException;
|
||||
use Symfony\Component\Security\Http\AccessMapInterface;
|
||||
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
|
||||
use Symfony\Component\Security\Http\Firewall\AccessListener;
|
||||
use Symfony\Component\Security\Http\Firewall\AbstractListener;
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
@ -28,17 +25,13 @@ use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
*/
|
||||
class LazyFirewallContext extends FirewallContext
|
||||
{
|
||||
private $accessListener;
|
||||
private $tokenStorage;
|
||||
private $map;
|
||||
|
||||
public function __construct(iterable $listeners, ?ExceptionListener $exceptionListener, ?LogoutListener $logoutListener, ?FirewallConfig $config, AccessListener $accessListener, TokenStorage $tokenStorage, AccessMapInterface $map)
|
||||
public function __construct(iterable $listeners, ?ExceptionListener $exceptionListener, ?LogoutListener $logoutListener, ?FirewallConfig $config, TokenStorage $tokenStorage)
|
||||
{
|
||||
parent::__construct($listeners, $exceptionListener, $logoutListener, $config);
|
||||
|
||||
$this->accessListener = $accessListener;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->map = $map;
|
||||
}
|
||||
|
||||
public function getListeners(): iterable
|
||||
@ -48,21 +41,37 @@ class LazyFirewallContext extends FirewallContext
|
||||
|
||||
public function __invoke(RequestEvent $event)
|
||||
{
|
||||
$this->tokenStorage->setInitializer(function () use ($event) {
|
||||
$event = new LazyResponseEvent($event);
|
||||
$listeners = [];
|
||||
$request = $event->getRequest();
|
||||
$lazy = $request->isMethodCacheable();
|
||||
|
||||
foreach (parent::getListeners() as $listener) {
|
||||
if (!$lazy || !$listener instanceof AbstractListener) {
|
||||
$listeners[] = $listener;
|
||||
$lazy = $lazy && $listener instanceof AbstractListener;
|
||||
} elseif (false !== $supports = $listener->supports($request)) {
|
||||
$listeners[] = [$listener, 'authenticate'];
|
||||
$lazy = null === $supports;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$lazy) {
|
||||
foreach ($listeners as $listener) {
|
||||
$listener($event);
|
||||
|
||||
if ($event->hasResponse()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->tokenStorage->setInitializer(function () use ($event, $listeners) {
|
||||
$event = new LazyResponseEvent($event);
|
||||
foreach ($listeners as $listener) {
|
||||
$listener($event);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
[$attributes] = $this->map->getPatterns($event->getRequest());
|
||||
|
||||
if ($attributes && [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] !== $attributes) {
|
||||
($this->accessListener)($event);
|
||||
}
|
||||
} catch (LazyResponseException $e) {
|
||||
$event->setResponse($e->getResponse());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
|
||||
|
||||
class AppCustomAuthenticator extends AbstractGuardAuthenticator
|
||||
{
|
||||
public function supports(Request $request)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCredentials(Request $request)
|
||||
{
|
||||
throw new AuthenticationException('This should be hit');
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user)
|
||||
{
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
|
||||
{
|
||||
return new Response('', 418);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
|
||||
{
|
||||
}
|
||||
|
||||
public function start(Request $request, AuthenticationException $authException = null)
|
||||
{
|
||||
return new Response($authException->getMessage(), Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
public function supportsRememberMe()
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\User\InMemoryUserProvider;
|
||||
use Symfony\Component\Security\Core\User\User;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
|
||||
class ClearRememberMeTest extends AbstractWebTestCase
|
||||
{
|
||||
public function testUserChangeClearsCookie()
|
||||
{
|
||||
$client = $this->createClient(['test_case' => 'ClearRememberMe', 'root_config' => 'config.yml']);
|
||||
|
||||
$client->request('POST', '/login', [
|
||||
'_username' => 'johannes',
|
||||
'_password' => 'test',
|
||||
]);
|
||||
|
||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||
$cookieJar = $client->getCookieJar();
|
||||
$this->assertNotNull($cookieJar->get('REMEMBERME'));
|
||||
|
||||
$client->request('GET', '/foo');
|
||||
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertNull($cookieJar->get('REMEMBERME'));
|
||||
}
|
||||
}
|
||||
|
||||
class RememberMeFooController
|
||||
{
|
||||
public function __invoke(UserInterface $user)
|
||||
{
|
||||
return new Response($user->getUsername());
|
||||
}
|
||||
}
|
||||
|
||||
class RememberMeUserProvider implements UserProviderInterface
|
||||
{
|
||||
private $inner;
|
||||
|
||||
public function __construct(InMemoryUserProvider $inner)
|
||||
{
|
||||
$this->inner = $inner;
|
||||
}
|
||||
|
||||
public function loadUserByUsername($username)
|
||||
{
|
||||
return $this->inner->loadUserByUsername($username);
|
||||
}
|
||||
|
||||
public function refreshUser(UserInterface $user)
|
||||
{
|
||||
$user = $this->inner->refreshUser($user);
|
||||
|
||||
$alterUser = \Closure::bind(function (User $user) { $user->password = 'foo'; }, null, User::class);
|
||||
$alterUser($user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return $this->inner->supportsClass($class);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
|
||||
|
||||
class GuardedTest extends AbstractWebTestCase
|
||||
{
|
||||
public function testGuarded()
|
||||
{
|
||||
$client = $this->createClient(['test_case' => 'Guarded', 'root_config' => 'config.yml']);
|
||||
|
||||
$client->request('GET', '/');
|
||||
|
||||
$this->assertSame(418, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||
|
||||
return [
|
||||
new FrameworkBundle(),
|
||||
new SecurityBundle(),
|
||||
];
|
@ -0,0 +1,31 @@
|
||||
imports:
|
||||
- { resource: ./../config/framework.yml }
|
||||
|
||||
security:
|
||||
encoders:
|
||||
Symfony\Component\Security\Core\User\User: plaintext
|
||||
|
||||
providers:
|
||||
in_memory:
|
||||
memory:
|
||||
users:
|
||||
johannes: { password: test, roles: [ROLE_USER] }
|
||||
|
||||
firewalls:
|
||||
default:
|
||||
form_login:
|
||||
check_path: login
|
||||
remember_me: true
|
||||
remember_me:
|
||||
always_remember_me: true
|
||||
secret: key
|
||||
anonymous: ~
|
||||
|
||||
access_control:
|
||||
- { path: ^/foo, roles: ROLE_USER }
|
||||
|
||||
services:
|
||||
Symfony\Bundle\SecurityBundle\Tests\Functional\RememberMeUserProvider:
|
||||
public: true
|
||||
decorates: security.user.provider.concrete.in_memory
|
||||
arguments: ['@Symfony\Bundle\SecurityBundle\Tests\Functional\RememberMeUserProvider.inner']
|
@ -0,0 +1,7 @@
|
||||
login:
|
||||
path: /login
|
||||
|
||||
foo:
|
||||
path: /foo
|
||||
defaults:
|
||||
_controller: Symfony\Bundle\SecurityBundle\Tests\Functional\RememberMeFooController
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return [
|
||||
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
||||
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
|
||||
];
|
@ -0,0 +1,22 @@
|
||||
framework:
|
||||
secret: test
|
||||
router: { resource: "%kernel.project_dir%/%kernel.test_case%/routing.yml" }
|
||||
test: ~
|
||||
default_locale: en
|
||||
profiler: false
|
||||
session:
|
||||
storage_id: session.storage.mock_file
|
||||
|
||||
services:
|
||||
logger: { class: Psr\Log\NullLogger }
|
||||
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AppCustomAuthenticator: ~
|
||||
|
||||
security:
|
||||
firewalls:
|
||||
secure:
|
||||
pattern: ^/
|
||||
anonymous: lazy
|
||||
stateless: false
|
||||
guard:
|
||||
authenticators:
|
||||
- Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AppCustomAuthenticator
|
@ -0,0 +1,5 @@
|
||||
main:
|
||||
path: /
|
||||
defaults:
|
||||
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction
|
||||
path: /app
|
@ -24,7 +24,7 @@
|
||||
"symfony/security-core": "^4.4|^5.0",
|
||||
"symfony/security-csrf": "^4.4|^5.0",
|
||||
"symfony/security-guard": "^4.4|^5.0",
|
||||
"symfony/security-http": "^4.4|^5.0"
|
||||
"symfony/security-http": "^4.4.1|^5.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-bundle": "^1.5|^2.0",
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Bridge\Twig\Extension\AssetExtension;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
@ -183,17 +183,19 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
|
||||
}
|
||||
|
||||
$props = [
|
||||
'file' => $trace[$i]['file'],
|
||||
'line' => $trace[$i]['line'],
|
||||
'file' => isset($trace[$i]['file']) ? $trace[$i]['file'] : null,
|
||||
'line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : null,
|
||||
'trace' => \array_slice($trace, 1 + $i),
|
||||
];
|
||||
|
||||
foreach ($props as $p => $v) {
|
||||
if (null !== $v) {
|
||||
$r = new \ReflectionProperty('Exception', $p);
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($e, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
@ -143,12 +143,56 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
|
||||
}
|
||||
|
||||
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
|
||||
yield preg_replace('/^ @@.*/m', '', $m);
|
||||
|
||||
$defaults = [];
|
||||
$parametersWithUndefinedConstants = [];
|
||||
foreach ($m->getParameters() as $p) {
|
||||
$defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null;
|
||||
if (!$p->isDefaultValueAvailable()) {
|
||||
$defaults[$p->name] = null;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$p->isDefaultValueConstant() || \defined($p->getDefaultValueConstantName())) {
|
||||
$defaults[$p->name] = $p->getDefaultValue();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaults[$p->name] = $p->getDefaultValueConstantName();
|
||||
$parametersWithUndefinedConstants[$p->name] = true;
|
||||
}
|
||||
|
||||
if (!$parametersWithUndefinedConstants) {
|
||||
yield preg_replace('/^ @@.*/m', '', $m);
|
||||
} else {
|
||||
$stack = [
|
||||
$m->getDocComment(),
|
||||
$m->getName(),
|
||||
$m->isAbstract(),
|
||||
$m->isFinal(),
|
||||
$m->isStatic(),
|
||||
$m->isPublic(),
|
||||
$m->isPrivate(),
|
||||
$m->isProtected(),
|
||||
$m->returnsReference(),
|
||||
$m->hasReturnType() ? $m->getReturnType()->getName() : '',
|
||||
];
|
||||
|
||||
foreach ($m->getParameters() as $p) {
|
||||
if (!isset($parametersWithUndefinedConstants[$p->name])) {
|
||||
$stack[] = (string) $p;
|
||||
} else {
|
||||
$stack[] = $p->isOptional();
|
||||
$stack[] = $p->hasType() ? $p->getType()->getName() : '';
|
||||
$stack[] = $p->isPassedByReference();
|
||||
$stack[] = $p->isVariadic();
|
||||
$stack[] = $p->getName();
|
||||
}
|
||||
}
|
||||
|
||||
yield implode(',', $stack);
|
||||
}
|
||||
|
||||
yield print_r($defaults, true);
|
||||
}
|
||||
|
||||
|
@ -64,8 +64,12 @@ class ReflectionClassResourceTest extends TestCase
|
||||
/**
|
||||
* @dataProvider provideHashedSignature
|
||||
*/
|
||||
public function testHashedSignature($changeExpected, $changedLine, $changedCode)
|
||||
public function testHashedSignature($changeExpected, $changedLine, $changedCode, $setContext = null)
|
||||
{
|
||||
if ($setContext) {
|
||||
$setContext();
|
||||
}
|
||||
|
||||
$code = <<<'EOPHP'
|
||||
/* 0*/
|
||||
/* 1*/ class %s extends ErrorException
|
||||
@ -83,7 +87,9 @@ class ReflectionClassResourceTest extends TestCase
|
||||
/*13*/ protected function prot($a = []) {}
|
||||
/*14*/
|
||||
/*15*/ private function priv() {}
|
||||
/*16*/ }
|
||||
/*16*/
|
||||
/*17*/ public function ccc($bar = A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC) {}
|
||||
/*18*/ }
|
||||
EOPHP;
|
||||
|
||||
static $expectedSignature, $generateSignature;
|
||||
@ -98,7 +104,9 @@ EOPHP;
|
||||
}
|
||||
|
||||
$code = explode("\n", $code);
|
||||
if (null !== $changedCode) {
|
||||
$code[$changedLine] = $changedCode;
|
||||
}
|
||||
eval(sprintf(implode("\n", $code), $class = 'Foo'.str_replace('.', '_', uniqid('', true))));
|
||||
$signature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class))));
|
||||
|
||||
@ -142,6 +150,10 @@ EOPHP;
|
||||
yield [0, 7, 'protected int $prot;'];
|
||||
yield [0, 9, 'private string $priv;'];
|
||||
}
|
||||
|
||||
yield [1, 17, 'public function ccc($bar = 187) {}'];
|
||||
yield [1, 17, 'public function ccc($bar = ANOTHER_ONE_THAT_WILL_NEVER_BE_DEFINED_CCCCCCCCC) {}'];
|
||||
yield [1, 17, null, static function () { \define('A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC', 'foo'); }];
|
||||
}
|
||||
|
||||
public function testEventSubscriber()
|
||||
|
@ -230,7 +230,7 @@ class QuestionHelper extends Helper
|
||||
} elseif ("\177" === $c) { // Backspace Character
|
||||
if (0 === $numMatches && 0 !== $i) {
|
||||
--$i;
|
||||
$fullChoice = substr($fullChoice, 0, -1);
|
||||
$fullChoice = self::substr($fullChoice, 0, -1);
|
||||
// Move cursor backwards
|
||||
$output->write("\033[1D");
|
||||
}
|
||||
@ -244,7 +244,7 @@ class QuestionHelper extends Helper
|
||||
}
|
||||
|
||||
// Pop the last character off the end of our string
|
||||
$ret = substr($ret, 0, $i);
|
||||
$ret = self::substr($ret, 0, $i);
|
||||
} elseif ("\033" === $c) {
|
||||
// Did we read an escape sequence?
|
||||
$c .= fread($inputStream, 2);
|
||||
@ -270,7 +270,7 @@ class QuestionHelper extends Helper
|
||||
$remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
|
||||
$output->write($remainingCharacters);
|
||||
$fullChoice .= $remainingCharacters;
|
||||
$i = \strlen($fullChoice);
|
||||
$i = self::strlen($fullChoice);
|
||||
|
||||
$matches = array_filter(
|
||||
$autocomplete($ret),
|
||||
|
@ -189,19 +189,20 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
||||
// Acm<NEWLINE>
|
||||
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
|
||||
// <NEWLINE>
|
||||
// <UP ARROW><UP ARROW><NEWLINE>
|
||||
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
|
||||
// <UP ARROW><UP ARROW><UP ARROW><NEWLINE>
|
||||
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
|
||||
// <DOWN ARROW><NEWLINE>
|
||||
// S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
|
||||
// F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
|
||||
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");
|
||||
// F⭐<TAB><BACKSPACE><BACKSPACE>⭐<TAB><NEWLINE>
|
||||
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\nF⭐\t\177\177⭐\t\n");
|
||||
|
||||
$dialog = new QuestionHelper();
|
||||
$helperSet = new HelperSet([new FormatterHelper()]);
|
||||
$dialog->setHelperSet($helperSet);
|
||||
|
||||
$question = new Question('Please select a bundle', 'FrameworkBundle');
|
||||
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle']);
|
||||
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle', 'F⭐Y']);
|
||||
|
||||
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
@ -211,6 +212,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
||||
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
$this->assertEquals('F⭐Y', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
}
|
||||
|
||||
public function testAskWithAutocompleteTrimmable()
|
||||
|
@ -316,6 +316,11 @@ class XmlDumper extends Dumper
|
||||
if (\in_array($value, ['null', 'true', 'false'], true)) {
|
||||
$element->setAttribute('type', 'string');
|
||||
}
|
||||
|
||||
if (\is_string($value) && (is_numeric($value) || preg_match('/^0b[01]*$/', $value) || preg_match('/^0x[0-9a-f]++$/i', $value))) {
|
||||
$element->setAttribute('type', 'string');
|
||||
}
|
||||
|
||||
$text = $this->document->createTextNode(self::phpToXml($value));
|
||||
$element->appendChild($text);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ abstract class FileLoader extends BaseFileLoader
|
||||
protected $instanceof = [];
|
||||
protected $interfaces = [];
|
||||
protected $singlyImplemented = [];
|
||||
protected $autoRegisterAliasesForSinglyImplementedInterfaces = true;
|
||||
|
||||
public function __construct(ContainerBuilder $container, FileLocatorInterface $locator)
|
||||
{
|
||||
@ -114,12 +115,16 @@ abstract class FileLoader extends BaseFileLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->autoRegisterAliasesForSinglyImplementedInterfaces) {
|
||||
$this->registerAliasesForSinglyImplementedInterfaces();
|
||||
}
|
||||
}
|
||||
|
||||
public function registerAliasesForSinglyImplementedInterfaces()
|
||||
{
|
||||
foreach ($this->interfaces as $interface) {
|
||||
if (!empty($this->singlyImplemented[$interface]) && !$this->container->hasAlias($interface)) {
|
||||
if (!empty($this->singlyImplemented[$interface]) && !$this->container->has($interface)) {
|
||||
$this->container->setAlias($interface, $this->singlyImplemented[$interface])->setPublic(false);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
|
||||
*/
|
||||
class PhpFileLoader extends FileLoader
|
||||
{
|
||||
protected $autoRegisterAliasesForSinglyImplementedInterfaces = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -36,6 +36,8 @@ class XmlFileLoader extends FileLoader
|
||||
{
|
||||
const NS = 'http://symfony.com/schema/dic/services';
|
||||
|
||||
protected $autoRegisterAliasesForSinglyImplementedInterfaces = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -110,6 +110,8 @@ class YamlFileLoader extends FileLoader
|
||||
private $anonymousServicesCount;
|
||||
private $anonymousServicesSuffix;
|
||||
|
||||
protected $autoRegisterAliasesForSinglyImplementedInterfaces = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -11,6 +11,17 @@ $container = new ContainerBuilder(new ParameterBag([
|
||||
'values' => [true, false, null, 0, 1000.3, 'true', 'false', 'null'],
|
||||
'binary' => "\xf0\xf0\xf0\xf0",
|
||||
'binary-control-char' => "This is a Bell char \x07",
|
||||
'null string' => 'null',
|
||||
'string of digits' => '123',
|
||||
'string of digits prefixed with minus character' => '-123',
|
||||
'true string' => 'true',
|
||||
'false string' => 'false',
|
||||
'binary number string' => '0b0110',
|
||||
'numeric string' => '-1.2E2',
|
||||
'hexadecimal number string' => '0xFF',
|
||||
'float string' => '10100.1',
|
||||
'positive float string' => '+10100.1',
|
||||
'negative float string' => '-10100.1',
|
||||
]));
|
||||
|
||||
return $container;
|
||||
|
@ -108,6 +108,17 @@ class ProjectServiceContainer extends Container
|
||||
],
|
||||
'binary' => 'ðððð',
|
||||
'binary-control-char' => 'This is a Bell char ',
|
||||
'null string' => 'null',
|
||||
'string of digits' => '123',
|
||||
'string of digits prefixed with minus character' => '-123',
|
||||
'true string' => 'true',
|
||||
'false string' => 'false',
|
||||
'binary number string' => '0b0110',
|
||||
'numeric string' => '-1.2E2',
|
||||
'hexadecimal number string' => '0xFF',
|
||||
'float string' => '10100.1',
|
||||
'positive float string' => '+10100.1',
|
||||
'negative float string' => '-10100.1',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,17 @@
|
||||
</parameter>
|
||||
<parameter key="binary" type="binary">8PDw8A==</parameter>
|
||||
<parameter key="binary-control-char" type="binary">VGhpcyBpcyBhIEJlbGwgY2hhciAH</parameter>
|
||||
<parameter key="null string" type="string">null</parameter>
|
||||
<parameter key="string of digits" type="string">123</parameter>
|
||||
<parameter key="string of digits prefixed with minus character" type="string">-123</parameter>
|
||||
<parameter key="true string" type="string">true</parameter>
|
||||
<parameter key="false string" type="string">false</parameter>
|
||||
<parameter key="binary number string" type="string">0b0110</parameter>
|
||||
<parameter key="numeric string" type="string">-1.2E2</parameter>
|
||||
<parameter key="hexadecimal number string" type="string">0xFF</parameter>
|
||||
<parameter key="float string" type="string">10100.1</parameter>
|
||||
<parameter key="positive float string" type="string">+10100.1</parameter>
|
||||
<parameter key="negative float string" type="string">-10100.1</parameter>
|
||||
</parameters>
|
||||
<services>
|
||||
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
|
||||
|
@ -6,6 +6,17 @@ parameters:
|
||||
values: [true, false, null, 0, 1000.3, 'true', 'false', 'null']
|
||||
binary: !!binary 8PDw8A==
|
||||
binary-control-char: !!binary VGhpcyBpcyBhIEJlbGwgY2hhciAH
|
||||
null string: 'null'
|
||||
string of digits: '123'
|
||||
string of digits prefixed with minus character: '-123'
|
||||
true string: 'true'
|
||||
false string: 'false'
|
||||
binary number string: '0b0110'
|
||||
numeric string: '-1.2E2'
|
||||
hexadecimal number string: '0xFF'
|
||||
float string: '10100.1'
|
||||
positive float string: '+10100.1'
|
||||
negative float string: '-10100.1'
|
||||
|
||||
services:
|
||||
service_container:
|
||||
|
@ -89,6 +89,7 @@ class FileLoaderTest extends TestCase
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('sub_dir', 'Sub');
|
||||
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));
|
||||
$loader->autoRegisterAliasesForSinglyImplementedInterfaces = false;
|
||||
|
||||
$loader->registerClasses(new Definition(), 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\\', 'Prototype/%sub_dir%/*');
|
||||
$loader->registerClasses(new Definition(), 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\\', 'Prototype/%sub_dir%/*'); // loading twice should not be an issue
|
||||
@ -121,7 +122,6 @@ class FileLoaderTest extends TestCase
|
||||
// load everything, except OtherDir/AnotherSub & Foo.php
|
||||
'Prototype/{%other_dir%/AnotherSub,Foo.php}'
|
||||
);
|
||||
$loader->registerAliasesForSinglyImplementedInterfaces();
|
||||
|
||||
$this->assertTrue($container->has(Bar::class));
|
||||
$this->assertTrue($container->has(Baz::class));
|
||||
@ -151,7 +151,6 @@ class FileLoaderTest extends TestCase
|
||||
'Prototype/OtherDir/AnotherSub/DeeperBaz.php',
|
||||
]
|
||||
);
|
||||
$loader->registerAliasesForSinglyImplementedInterfaces();
|
||||
|
||||
$this->assertTrue($container->has(Foo::class));
|
||||
$this->assertTrue($container->has(Baz::class));
|
||||
@ -167,7 +166,6 @@ class FileLoaderTest extends TestCase
|
||||
$prototype = new Definition();
|
||||
$prototype->setPublic(true)->setPrivate(true);
|
||||
$loader->registerClasses($prototype, 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/*');
|
||||
$loader->registerAliasesForSinglyImplementedInterfaces();
|
||||
|
||||
$this->assertTrue($container->has(Bar::class));
|
||||
$this->assertTrue($container->has(Baz::class));
|
||||
@ -199,7 +197,6 @@ class FileLoaderTest extends TestCase
|
||||
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\\',
|
||||
'Prototype/%bad_classes_dir%/*'
|
||||
);
|
||||
$loader->registerAliasesForSinglyImplementedInterfaces();
|
||||
|
||||
$this->assertTrue($container->has(MissingParent::class));
|
||||
|
||||
@ -218,7 +215,6 @@ class FileLoaderTest extends TestCase
|
||||
|
||||
// the Sub is missing from namespace prefix
|
||||
$loader->registerClasses(new Definition(), 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/Sub/*');
|
||||
$loader->registerAliasesForSinglyImplementedInterfaces();
|
||||
}
|
||||
|
||||
public function testRegisterClassesWithIncompatibleExclude()
|
||||
@ -234,12 +230,13 @@ class FileLoaderTest extends TestCase
|
||||
'Prototype/*',
|
||||
'yaml/*'
|
||||
);
|
||||
$loader->registerAliasesForSinglyImplementedInterfaces();
|
||||
}
|
||||
}
|
||||
|
||||
class TestFileLoader extends FileLoader
|
||||
{
|
||||
public $autoRegisterAliasesForSinglyImplementedInterfaces = true;
|
||||
|
||||
public function load($resource, string $type = null)
|
||||
{
|
||||
return $resource;
|
||||
|
@ -37,9 +37,6 @@
|
||||
"symfony/service-contracts": "^1.0|^2",
|
||||
"symfony/var-dumper": "^4.4|^5.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-kernel": "<4.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\HttpClient\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
|
||||
use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp;
|
||||
use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp;
|
||||
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
|
||||
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
|
||||
|
||||
/**
|
||||
* @group time-sensitive
|
||||
@ -94,4 +95,101 @@ EOF
|
||||
$redeliveryStamp2->getRedeliveredAt()->format('Y-m-d H:i:s')),
|
||||
$tester->getDisplay(true));
|
||||
}
|
||||
|
||||
public function testReceiverShouldBeListable()
|
||||
{
|
||||
$receiver = $this->createMock(ReceiverInterface::class);
|
||||
$command = new FailedMessagesShowCommand(
|
||||
'failure_receiver',
|
||||
$receiver
|
||||
);
|
||||
|
||||
$this->expectExceptionMessage('The "failure_receiver" receiver does not support listing or showing specific messages.');
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(['id' => 15]);
|
||||
}
|
||||
|
||||
public function testListMessages()
|
||||
{
|
||||
$sentToFailureStamp = new SentToFailureTransportStamp('async');
|
||||
$redeliveryStamp = new RedeliveryStamp(0, 'failure_receiver', 'Things are bad!');
|
||||
$envelope = new Envelope(new \stdClass(), [
|
||||
new TransportMessageIdStamp(15),
|
||||
$sentToFailureStamp,
|
||||
$redeliveryStamp,
|
||||
]);
|
||||
$receiver = $this->createMock(ListableReceiverInterface::class);
|
||||
$receiver->expects($this->once())->method('all')->with()->willReturn([$envelope]);
|
||||
|
||||
$command = new FailedMessagesShowCommand(
|
||||
'failure_receiver',
|
||||
$receiver
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute([]);
|
||||
$this->assertStringContainsString(sprintf(<<<EOF
|
||||
15 stdClass %s Things are bad!
|
||||
EOF
|
||||
,
|
||||
$redeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s')),
|
||||
$tester->getDisplay(true));
|
||||
}
|
||||
|
||||
public function testListMessagesReturnsNoMessagesFound()
|
||||
{
|
||||
$receiver = $this->createMock(ListableReceiverInterface::class);
|
||||
$receiver->expects($this->once())->method('all')->with()->willReturn([]);
|
||||
|
||||
$command = new FailedMessagesShowCommand(
|
||||
'failure_receiver',
|
||||
$receiver
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute([]);
|
||||
$this->assertStringContainsString('[OK] No failed messages were found.', $tester->getDisplay(true));
|
||||
}
|
||||
|
||||
public function testListMessagesReturnsPaginatedMessages()
|
||||
{
|
||||
$sentToFailureStamp = new SentToFailureTransportStamp('async');
|
||||
$envelope = new Envelope(new \stdClass(), [
|
||||
new TransportMessageIdStamp(15),
|
||||
$sentToFailureStamp,
|
||||
new RedeliveryStamp(0, 'failure_receiver', 'Things are bad!'),
|
||||
]);
|
||||
$receiver = $this->createMock(ListableReceiverInterface::class);
|
||||
$receiver->expects($this->once())->method('all')->with()->willReturn([$envelope]);
|
||||
|
||||
$command = new FailedMessagesShowCommand(
|
||||
'failure_receiver',
|
||||
$receiver
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(['--max' => 1]);
|
||||
$this->assertStringContainsString('Showing first 1 messages.', $tester->getDisplay(true));
|
||||
}
|
||||
|
||||
public function testInvalidMessagesThrowsException()
|
||||
{
|
||||
$sentToFailureStamp = new SentToFailureTransportStamp('async');
|
||||
$envelope = new Envelope(new \stdClass(), [
|
||||
new TransportMessageIdStamp(15),
|
||||
$sentToFailureStamp,
|
||||
]);
|
||||
$receiver = $this->createMock(ListableReceiverInterface::class);
|
||||
|
||||
$command = new FailedMessagesShowCommand(
|
||||
'failure_receiver',
|
||||
$receiver
|
||||
);
|
||||
|
||||
$this->expectExceptionMessage('The message "15" was not found.');
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(['id' => 15]);
|
||||
}
|
||||
}
|
||||
|
@ -56,11 +56,20 @@ final class FormDataPart extends AbstractMultipartPart
|
||||
private function prepareFields(array $fields): array
|
||||
{
|
||||
$values = [];
|
||||
array_walk_recursive($fields, function ($item, $key) use (&$values) {
|
||||
if (!\is_array($item)) {
|
||||
$values[] = $this->preparePart($key, $item);
|
||||
|
||||
$prepare = function ($item, $key, $root = null) use (&$values, &$prepare) {
|
||||
$fieldName = $root ? sprintf('%s[%s]', $root, $key) : $key;
|
||||
|
||||
if (\is_array($item)) {
|
||||
array_walk($item, $prepare, $fieldName);
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
$values[] = $this->preparePart($fieldName, $item);
|
||||
};
|
||||
|
||||
array_walk($fields, $prepare);
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
@ -47,6 +47,34 @@ class FormDataPartTest extends TestCase
|
||||
$this->assertEquals([$t, $b, $c], $f->getParts());
|
||||
}
|
||||
|
||||
public function testNestedArrayParts()
|
||||
{
|
||||
$p1 = new TextPart('content', 'utf-8', 'plain', '8bit');
|
||||
$f = new FormDataPart([
|
||||
'foo' => clone $p1,
|
||||
'bar' => [
|
||||
'baz' => [
|
||||
clone $p1,
|
||||
'qux' => clone $p1,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals('multipart', $f->getMediaType());
|
||||
$this->assertEquals('form-data', $f->getMediaSubtype());
|
||||
|
||||
$p1->setName('foo');
|
||||
$p1->setDisposition('form-data');
|
||||
|
||||
$p2 = clone $p1;
|
||||
$p2->setName('bar[baz][0]');
|
||||
|
||||
$p3 = clone $p1;
|
||||
$p3->setName('bar[baz][qux]');
|
||||
|
||||
$this->assertEquals([$p1, $p2, $p3], $f->getParts());
|
||||
}
|
||||
|
||||
public function testToString()
|
||||
{
|
||||
$p = DataPart::fromPath($file = __DIR__.'/../../Fixtures/mimetypes/test.gif');
|
||||
|
@ -57,8 +57,8 @@ class RequestContext
|
||||
$this->setMethod($request->getMethod());
|
||||
$this->setHost($request->getHost());
|
||||
$this->setScheme($request->getScheme());
|
||||
$this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort());
|
||||
$this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort);
|
||||
$this->setHttpPort($request->isSecure() || null === $request->getPort() ? $this->httpPort : $request->getPort());
|
||||
$this->setHttpsPort($request->isSecure() && null !== $request->getPort() ? $request->getPort() : $this->httpsPort);
|
||||
$this->setQueryString($request->server->get('QUERY_STRING', ''));
|
||||
|
||||
return $this;
|
||||
|
@ -62,6 +62,7 @@ CHANGELOG
|
||||
* Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`.
|
||||
* Deprecated passing more than one attribute to `AccessDecisionManager::decide()` and `AuthorizationChecker::isGranted()`
|
||||
* Added new `argon2id` encoder, undeprecated the `bcrypt` and `argon2i` ones (using `auto` is still recommended by default.)
|
||||
* Added `AbstractListener` which replaces the deprecated `ListenerInterface`
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
|
||||
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
||||
use Symfony\Component\Security\Http\Firewall\AbstractListener;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
|
||||
/**
|
||||
@ -31,7 +32,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class GuardAuthenticationListener
|
||||
class GuardAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $guardHandler;
|
||||
private $authenticationManager;
|
||||
@ -58,9 +59,9 @@ class GuardAuthenticationListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over each authenticator to see if each wants to authenticate the request.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$context = ['firewall_key' => $this->providerKey];
|
||||
@ -72,7 +73,39 @@ class GuardAuthenticationListener
|
||||
$this->logger->debug('Checking for guard authentication credentials.', $context);
|
||||
}
|
||||
|
||||
$guardAuthenticators = [];
|
||||
|
||||
foreach ($this->guardAuthenticators as $key => $guardAuthenticator) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Checking support on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
|
||||
}
|
||||
|
||||
if ($guardAuthenticator->supports($request)) {
|
||||
$guardAuthenticators[$key] = $guardAuthenticator;
|
||||
} elseif (null !== $this->logger) {
|
||||
$this->logger->debug('Guard authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$guardAuthenticators) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request->attributes->set('_guard_authenticators', $guardAuthenticators);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over each authenticator to see if each wants to authenticate the request.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$guardAuthenticators = $request->attributes->get('_guard_authenticators');
|
||||
$request->attributes->remove('_guard_authenticators');
|
||||
|
||||
foreach ($guardAuthenticators as $key => $guardAuthenticator) {
|
||||
// get a key that's unique to *this* guard authenticator
|
||||
// this MUST be the same as GuardAuthenticationProvider
|
||||
$uniqueGuardKey = $this->providerKey.'_'.$key;
|
||||
@ -93,19 +126,6 @@ class GuardAuthenticationListener
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
try {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Checking support on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
|
||||
}
|
||||
|
||||
// abort the execution of the authenticator if it doesn't support the request
|
||||
if (!$guardAuthenticator->supports($request)) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Guard authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Calling getCredentials() on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
"require": {
|
||||
"php": "^7.2.5",
|
||||
"symfony/security-core": "^5.0",
|
||||
"symfony/security-http": "^4.4|^5.0"
|
||||
"symfony/security-http": "^4.4.1|^5.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0"
|
||||
|
@ -48,7 +48,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class AbstractAuthenticationListener
|
||||
abstract class AbstractAuthenticationListener extends AbstractListener
|
||||
{
|
||||
protected $options;
|
||||
protected $logger;
|
||||
@ -102,20 +102,24 @@ abstract class AbstractAuthenticationListener
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $this->requiresAuthentication($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles form based authentication.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @throws SessionUnavailableException
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$this->requiresAuthentication($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$request->hasSession()) {
|
||||
throw new \RuntimeException('This authentication method requires a session.');
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
|
||||
/**
|
||||
* A base class for listeners that can tell whether they should authenticate incoming requests.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
abstract class AbstractListener
|
||||
{
|
||||
final public function __invoke(RequestEvent $event)
|
||||
{
|
||||
if (false !== $this->supports($event->getRequest())) {
|
||||
$this->authenticate($event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the authenticate() method should be called or not depending on the incoming request.
|
||||
*
|
||||
* Returning null means authenticate() can be called lazily when accessing the token storage.
|
||||
*/
|
||||
abstract public function supports(Request $request): ?bool;
|
||||
|
||||
/**
|
||||
* Does whatever is required to authenticate the request, typically calling $event->setResponse() internally.
|
||||
*/
|
||||
abstract public function authenticate(RequestEvent $event);
|
||||
}
|
@ -34,8 +34,8 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractPreAuthenticatedListener
|
||||
{
|
||||
abstract class AbstractPreAuthenticatedListener extends AbstractListener
|
||||
|
||||
protected $logger;
|
||||
private $tokenStorage;
|
||||
private $authenticationManager;
|
||||
@ -53,20 +53,31 @@ abstract class AbstractPreAuthenticatedListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pre-authentication.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
try {
|
||||
list($user, $credentials) = $this->getPreAuthenticatedData($request);
|
||||
$request->attributes->set('_pre_authenticated_data', $this->getPreAuthenticatedData($request));
|
||||
} catch (BadCredentialsException $e) {
|
||||
$this->clearToken($e);
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pre-authentication.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
[$user, $credentials] = $request->attributes->get('_pre_authenticated_data');
|
||||
$request->attributes->remove('_pre_authenticated_data');
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Checking current security token.', ['token' => (string) $this->tokenStorage->getToken()]);
|
||||
}
|
||||
|
@ -11,10 +11,12 @@
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
|
||||
use Symfony\Component\Security\Http\AccessMapInterface;
|
||||
@ -27,7 +29,7 @@ use Symfony\Component\Security\Http\Event\LazyResponseEvent;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AccessListener
|
||||
class AccessListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $accessDecisionManager;
|
||||
@ -42,13 +44,24 @@ class AccessListener
|
||||
$this->authManager = $authManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
[$attributes] = $this->map->getPatterns($request);
|
||||
$request->attributes->set('_access_control_attributes', $attributes);
|
||||
|
||||
return $attributes && [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] !== $attributes ? true : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles access authorization.
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* @throws AuthenticationCredentialsNotFoundException
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (!$event instanceof LazyResponseEvent && null === $token = $this->tokenStorage->getToken()) {
|
||||
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
|
||||
@ -56,9 +69,10 @@ class AccessListener
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
list($attributes) = $this->map->getPatterns($request);
|
||||
$attributes = $request->attributes->get('_access_control_attributes');
|
||||
$request->attributes->remove('_access_control_attributes');
|
||||
|
||||
if (!$attributes) {
|
||||
if (!$attributes || ([AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes && $event instanceof LazyResponseEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
|
||||
@ -26,7 +27,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AnonymousAuthenticationListener
|
||||
class AnonymousAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $secret;
|
||||
@ -41,10 +42,18 @@ class AnonymousAuthenticationListener
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null; // always run authenticate() lazily with lazy firewalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles anonymous authentication.
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (null !== $this->tokenStorage->getToken()) {
|
||||
return;
|
||||
|
@ -29,7 +29,7 @@ use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterfa
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class BasicAuthenticationListener
|
||||
class BasicAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $authenticationManager;
|
||||
@ -53,10 +53,18 @@ class BasicAuthenticationListener
|
||||
$this->ignoreFailure = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null !== $request->headers->get('PHP_AUTH_USER');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles basic authentication.
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Http\AccessMapInterface;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
@ -24,7 +25,7 @@ use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ChannelListener
|
||||
class ChannelListener extends AbstractListener
|
||||
{
|
||||
private $map;
|
||||
private $authenticationEntryPoint;
|
||||
@ -40,10 +41,8 @@ class ChannelListener
|
||||
/**
|
||||
* Handles channel management.
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
list(, $channel) = $this->map->getPatterns($request);
|
||||
|
||||
if ('https' === $channel && !$request->isSecure()) {
|
||||
@ -57,11 +56,7 @@ class ChannelListener
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->authenticationEntryPoint->start($request);
|
||||
|
||||
$event->setResponse($response);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ('http' === $channel && $request->isSecure()) {
|
||||
@ -69,9 +64,18 @@ class ChannelListener
|
||||
$this->logger->info('Redirecting to HTTP.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$response = $this->authenticationEntryPoint->start($request);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Event\DeauthenticatedEvent;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
@ -39,7 +40,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ContextListener
|
||||
class ContextListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $sessionKey;
|
||||
@ -48,6 +49,7 @@ class ContextListener
|
||||
private $dispatcher;
|
||||
private $registered;
|
||||
private $trustResolver;
|
||||
private $rememberMeServices;
|
||||
private $sessionTrackerEnabler;
|
||||
|
||||
/**
|
||||
@ -68,10 +70,18 @@ class ContextListener
|
||||
$this->sessionTrackerEnabler = $sessionTrackerEnabler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null; // always run authenticate() lazily with lazy firewalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Security Token from the session.
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (!$this->registered && null !== $this->dispatcher && $event->isMasterRequest()) {
|
||||
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
|
||||
@ -112,6 +122,10 @@ class ContextListener
|
||||
|
||||
if ($token instanceof TokenInterface) {
|
||||
$token = $this->refreshUser($token);
|
||||
|
||||
if (!$token && $this->rememberMeServices) {
|
||||
$this->rememberMeServices->loginFail($request);
|
||||
}
|
||||
} elseif (null !== $token) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning('Expected a security token from the session, got something else.', ['key' => $this->sessionKey, 'received' => $token]);
|
||||
@ -282,4 +296,9 @@ class ContextListener
|
||||
{
|
||||
throw new \ErrorException('Class not found: '.$class, 0x37313bc);
|
||||
}
|
||||
|
||||
public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices)
|
||||
{
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ use Symfony\Component\Security\Http\ParameterBagUtils;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LogoutListener
|
||||
class LogoutListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $options;
|
||||
@ -61,6 +61,14 @@ class LogoutListener
|
||||
$this->handlers[] = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $this->requiresLogout($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logout if requested.
|
||||
*
|
||||
@ -70,14 +78,10 @@ class LogoutListener
|
||||
* @throws LogoutException if the CSRF token is invalid
|
||||
* @throws \RuntimeException if the LogoutSuccessHandlerInterface instance does not return a response
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$this->requiresLogout($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $this->csrfTokenManager) {
|
||||
$csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
@ -30,7 +31,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RememberMeListener
|
||||
class RememberMeListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $rememberMeServices;
|
||||
@ -51,10 +52,18 @@ class RememberMeListener
|
||||
$this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null; // always run authenticate() lazily with lazy firewalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles remember-me cookie based authentication.
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (null !== $this->tokenStorage->getToken()) {
|
||||
return;
|
||||
|
@ -37,7 +37,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class SwitchUserListener
|
||||
class SwitchUserListener extends AbstractListener
|
||||
{
|
||||
const EXIT_VALUE = '_exit';
|
||||
|
||||
@ -71,14 +71,10 @@ class SwitchUserListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the switch to another user.
|
||||
*
|
||||
* @throws \LogicException if switching to a user failed
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
// usernames can be falsy
|
||||
$username = $request->get($this->usernameParameter);
|
||||
|
||||
@ -88,9 +84,26 @@ class SwitchUserListener
|
||||
|
||||
// if it's still "empty", nothing to do.
|
||||
if (null === $username || '' === $username) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$request->attributes->set('_switch_user_username', $username);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the switch to another user.
|
||||
*
|
||||
* @throws \LogicException if switching to a user failed
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$username = $request->attributes->get('_switch_user_username');
|
||||
$request->attributes->remove('_switch_user_username');
|
||||
|
||||
if (null === $this->tokenStorage->getToken()) {
|
||||
throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.');
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class UsernamePasswordJsonAuthenticationListener
|
||||
class UsernamePasswordJsonAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $authenticationManager;
|
||||
@ -71,19 +71,27 @@ class UsernamePasswordJsonAuthenticationListener
|
||||
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
|
||||
}
|
||||
|
||||
public function __invoke(RequestEvent $event)
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
if (false === strpos($request->getRequestFormat(), 'json')
|
||||
&& false === strpos($request->getContentType(), 'json')
|
||||
) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->options['check_path']) && !$this->httpUtils->checkRequestPath($request, $this->options['check_path'])) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$data = json_decode($request->getContent());
|
||||
|
||||
try {
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Http\Tests\Firewall;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
@ -26,7 +27,7 @@ class AccessListenerTest extends TestCase
|
||||
public function testHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
|
||||
{
|
||||
$this->expectException('Symfony\Component\Security\Core\Exception\AccessDeniedException');
|
||||
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
|
||||
$request = new Request();
|
||||
|
||||
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
|
||||
$accessMap
|
||||
@ -65,19 +66,12 @@ class AccessListenerTest extends TestCase
|
||||
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock()
|
||||
);
|
||||
|
||||
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
|
||||
public function testHandleWhenTheTokenIsNotAuthenticated()
|
||||
{
|
||||
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
|
||||
$request = new Request();
|
||||
|
||||
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
|
||||
$accessMap
|
||||
@ -136,19 +130,12 @@ class AccessListenerTest extends TestCase
|
||||
$authManager
|
||||
);
|
||||
|
||||
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
|
||||
public function testHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
|
||||
{
|
||||
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock();
|
||||
$request = new Request();
|
||||
|
||||
$accessMap = $this->getMockBuilder('Symfony\Component\Security\Http\AccessMapInterface')->getMock();
|
||||
$accessMap
|
||||
@ -178,19 +165,12 @@ class AccessListenerTest extends TestCase
|
||||
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock()
|
||||
);
|
||||
|
||||
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
|
||||
public function testHandleWhenAccessMapReturnsEmptyAttributes()
|
||||
{
|
||||
$request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->disableOriginalClone()->getMock();
|
||||
$request = new Request();
|
||||
|
||||
$accessMap = $this->getMockBuilder(AccessMapInterface::class)->getMock();
|
||||
$accessMap
|
||||
@ -213,12 +193,7 @@ class AccessListenerTest extends TestCase
|
||||
$this->getMockBuilder(AuthenticationManagerInterface::class)->getMock()
|
||||
);
|
||||
|
||||
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
$event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST);
|
||||
|
||||
$listener(new LazyResponseEvent($event));
|
||||
}
|
||||
@ -233,7 +208,7 @@ class AccessListenerTest extends TestCase
|
||||
->willReturn(null)
|
||||
;
|
||||
|
||||
$request = $this->getMockBuilder(Request::class)->disableOriginalConstructor()->disableOriginalClone()->getMock();
|
||||
$request = new Request();
|
||||
|
||||
$accessMap = $this->getMockBuilder(AccessMapInterface::class)->getMock();
|
||||
$accessMap
|
||||
@ -250,13 +225,6 @@ class AccessListenerTest extends TestCase
|
||||
$this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock()
|
||||
);
|
||||
|
||||
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
namespace Symfony\Component\Security\Http\Tests\Firewall;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
|
||||
use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener;
|
||||
|
||||
@ -38,7 +40,7 @@ class AnonymousAuthenticationListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$listener = new AnonymousAuthenticationListener($tokenStorage, 'TheSecret', null, $authenticationManager);
|
||||
$listener($this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock());
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), new Request(), HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
|
||||
public function testHandleWithTokenStorageHavingNoToken()
|
||||
@ -69,7 +71,7 @@ class AnonymousAuthenticationListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$listener = new AnonymousAuthenticationListener($tokenStorage, 'TheSecret', null, $authenticationManager);
|
||||
$listener($this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock());
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), new Request(), HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
|
||||
public function testHandledEventIsLogged()
|
||||
@ -84,6 +86,6 @@ class AnonymousAuthenticationListenerTest extends TestCase
|
||||
$authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock();
|
||||
|
||||
$listener = new AnonymousAuthenticationListener($tokenStorage, 'TheSecret', $logger, $authenticationManager);
|
||||
$listener($this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock());
|
||||
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), new Request(), HttpKernelInterface::MASTER_REQUEST));
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Event\DeauthenticatedEvent;
|
||||
use Symfony\Component\Security\Http\Firewall\ContextListener;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
use Symfony\Contracts\Service\ServiceLocatorTrait;
|
||||
|
||||
class ContextListenerTest extends TestCase
|
||||
@ -262,10 +263,23 @@ class ContextListenerTest extends TestCase
|
||||
$tokenStorage = new TokenStorage();
|
||||
$badRefreshedUser = new User('foobar', 'baz');
|
||||
$goodRefreshedUser = new User('foobar', 'bar');
|
||||
$tokenStorage = $this->handleEventWithPreviousSession([new SupportingUserProvider($badRefreshedUser), new SupportingUserProvider($goodRefreshedUser)], $goodRefreshedUser, true);
|
||||
$tokenStorage = $this->handleEventWithPreviousSession([new SupportingUserProvider($badRefreshedUser), new SupportingUserProvider($goodRefreshedUser)], $goodRefreshedUser);
|
||||
$this->assertSame($goodRefreshedUser, $tokenStorage->getToken()->getUser());
|
||||
}
|
||||
|
||||
public function testRememberMeGetsCanceledIfTokenIsDeauthenticated()
|
||||
{
|
||||
$tokenStorage = new TokenStorage();
|
||||
$refreshedUser = new User('foobar', 'baz');
|
||||
|
||||
$rememberMeServices = $this->createMock(RememberMeServicesInterface::class);
|
||||
$rememberMeServices->expects($this->once())->method('loginFail');
|
||||
|
||||
$tokenStorage = $this->handleEventWithPreviousSession([new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], null, $rememberMeServices);
|
||||
|
||||
$this->assertNull($tokenStorage->getToken());
|
||||
}
|
||||
|
||||
public function testTryAllUserProvidersUntilASupportingUserProviderIsFound()
|
||||
{
|
||||
$refreshedUser = new User('foobar', 'baz');
|
||||
@ -372,7 +386,7 @@ class ContextListenerTest extends TestCase
|
||||
return $session;
|
||||
}
|
||||
|
||||
private function handleEventWithPreviousSession($userProviders, UserInterface $user = null)
|
||||
private function handleEventWithPreviousSession($userProviders, UserInterface $user = null, RememberMeServicesInterface $rememberMeServices = null)
|
||||
{
|
||||
$user = $user ?: new User('foo', 'bar');
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
@ -392,6 +406,10 @@ class ContextListenerTest extends TestCase
|
||||
$sessionTrackerEnabler = [$tokenStorage, 'enableUsageTracking'];
|
||||
|
||||
$listener = new ContextListener($tokenStorage, $userProviders, 'context_key', null, null, null, $sessionTrackerEnabler);
|
||||
|
||||
if ($rememberMeServices) {
|
||||
$listener->setRememberMeServices($rememberMeServices);
|
||||
}
|
||||
$listener(new RequestEvent($this->getMockBuilder(HttpKernelInterface::class)->getMock(), $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
|
||||
$this->assertSame($usageIndex, $session->getUsageIndex());
|
||||
|
@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\Firewall\RememberMeListener;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
@ -27,7 +28,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage) = $this->getListener();
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn($this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock())
|
||||
;
|
||||
@ -45,7 +46,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service) = $this->getListener();
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -57,11 +58,6 @@ class RememberMeListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn(new Request())
|
||||
;
|
||||
|
||||
$this->assertNull($listener($event));
|
||||
}
|
||||
@ -73,7 +69,7 @@ class RememberMeListenerTest extends TestCase
|
||||
$exception = new AuthenticationException('Authentication failed.');
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -96,12 +92,7 @@ class RememberMeListenerTest extends TestCase
|
||||
->willThrowException($exception)
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
$event = $this->getGetResponseEvent($request);
|
||||
|
||||
$listener($event);
|
||||
}
|
||||
@ -113,7 +104,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, false);
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -137,11 +128,6 @@ class RememberMeListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn(new Request())
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
}
|
||||
@ -151,7 +137,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service, $manager) = $this->getListener();
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -174,11 +160,6 @@ class RememberMeListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn(new Request())
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
}
|
||||
@ -188,7 +169,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service, $manager) = $this->getListener();
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -213,11 +194,6 @@ class RememberMeListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn(new Request())
|
||||
;
|
||||
|
||||
$listener($event);
|
||||
}
|
||||
@ -227,7 +203,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service, $manager, , , $sessionStrategy) = $this->getListener(false, true, true);
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -258,25 +234,10 @@ class RememberMeListenerTest extends TestCase
|
||||
->willReturn(true)
|
||||
;
|
||||
|
||||
$request = $this->getMockBuilder('\Symfony\Component\HttpFoundation\Request')->getMock();
|
||||
$request
|
||||
->expects($this->once())
|
||||
->method('hasSession')
|
||||
->willReturn(true)
|
||||
;
|
||||
$request = new Request();
|
||||
$request->setSession($session);
|
||||
|
||||
$request
|
||||
->expects($this->once())
|
||||
->method('getSession')
|
||||
->willReturn($session)
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
$event = $this->getGetResponseEvent($request);
|
||||
|
||||
$sessionStrategy
|
||||
->expects($this->once())
|
||||
@ -292,7 +253,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, true, false);
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -327,25 +288,10 @@ class RememberMeListenerTest extends TestCase
|
||||
->method('migrate')
|
||||
;
|
||||
|
||||
$request = $this->getMockBuilder('\Symfony\Component\HttpFoundation\Request')->getMock();
|
||||
$request
|
||||
->expects($this->any())
|
||||
->method('hasSession')
|
||||
->willReturn(true)
|
||||
;
|
||||
$request = new Request();
|
||||
$request->setSession($session);
|
||||
|
||||
$request
|
||||
->expects($this->any())
|
||||
->method('getSession')
|
||||
->willReturn($session)
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
$event = $this->getGetResponseEvent($request);
|
||||
|
||||
$listener($event);
|
||||
}
|
||||
@ -355,7 +301,7 @@ class RememberMeListenerTest extends TestCase
|
||||
list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true);
|
||||
|
||||
$tokenStorage
|
||||
->expects($this->once())
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn(null)
|
||||
;
|
||||
@ -380,12 +326,6 @@ class RememberMeListenerTest extends TestCase
|
||||
;
|
||||
|
||||
$event = $this->getGetResponseEvent();
|
||||
$request = new Request();
|
||||
$event
|
||||
->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
|
||||
$dispatcher
|
||||
->expects($this->once())
|
||||
@ -399,9 +339,20 @@ class RememberMeListenerTest extends TestCase
|
||||
$listener($event);
|
||||
}
|
||||
|
||||
protected function getGetResponseEvent()
|
||||
protected function getGetResponseEvent(Request $request = null): RequestEvent
|
||||
{
|
||||
return $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
|
||||
$request = $request ?? new Request();
|
||||
|
||||
$event = $this->getMockBuilder(RequestEvent::class)
|
||||
->setConstructorArgs([$this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST])
|
||||
->getMock();
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->willReturn($request)
|
||||
;
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
protected function getResponseEvent(): ResponseEvent
|
||||
|
@ -318,6 +318,54 @@
|
||||
<source>Error</source>
|
||||
<target>Napaka</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="83">
|
||||
<source>This is not a valid UUID.</source>
|
||||
<target>To ni veljaven UUID.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="84">
|
||||
<source>This value should be a multiple of {{ compared_value }}.</source>
|
||||
<target>Ta vrednost bi morala biti večkratnik od {{ compared_value }}.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="85">
|
||||
<source>This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.</source>
|
||||
<target>Ta poslovna identifikacijska koda (BIC) ni povezana z IBAN {{ iban }}.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="86">
|
||||
<source>This value should be valid JSON.</source>
|
||||
<target>Ta vrednost bi morala biti veljaven JSON.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="87">
|
||||
<source>This collection should contain only unique elements.</source>
|
||||
<target>Ta zbirka bi morala vsebovati samo edinstvene elemente.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="88">
|
||||
<source>This value should be positive.</source>
|
||||
<target>Ta vrednost bi morala biti pozitivna.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="89">
|
||||
<source>This value should be either positive or zero.</source>
|
||||
<target>Ta vrednost bi morala biti pozitivna ali enaka nič.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="90">
|
||||
<source>This value should be negative.</source>
|
||||
<target>Ta vrednost bi morala biti negativna.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="91">
|
||||
<source>This value should be either negative or zero.</source>
|
||||
<target>Ta vrednost bi morala biti negativna ali enaka nič.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="92">
|
||||
<source>This value is not a valid timezone.</source>
|
||||
<target>Ta vrednost ni veljaven časovni pas.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="93">
|
||||
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
|
||||
<target>To geslo je ušlo pri kršitvi varnosti podatkov in ga ne smete uporabljati. Prosimo, uporabite drugo geslo.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="94">
|
||||
<source>This value should be between {{ min }} and {{ max }}.</source>
|
||||
<target>Ta vrednost bi morala biti med {{ min }} in {{ max }}.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
Reference in New Issue
Block a user