Merge branch '4.4'
* 4.4: [OptionsResolve] Revert change in tests for a not-merged change in code [HttpClient] fix handling of 3xx with no Location header - ignore Content-Length when no body is expected [Workflow] Made the configuration more robust for the 'property' key [Security/Core] make NativePasswordEncoder use sodium to validate passwords when possible [FrameworkBundle] make SodiumVault report bad decryption key accurately cs fix [Security] Allow to set a fixed algorithm [Security/Core] make encodedLength computation more generic [Security/Core] add fast path when encoded password cannot match anything #30432 fix an error message fix paths to detect code owners [HttpClient] ignore the body of responses to HEAD requests [Validator] Ensure numeric subpaths do not cause errors on PHP 7.4 [SecurityBundle] Fix wrong assertion Remove unused local variables in tests [Yaml][Parser] Remove the getLastLineNumberBeforeDeprecation() internal unused method Make sure to collect child forms created on *_SET_DATA events [WebProfilerBundle] Improve display in Email panel for dark theme do not render errors for checkboxes twice
This commit is contained in:
commit
5a855408e1
26
.github/CODEOWNERS
vendored
26
.github/CODEOWNERS
vendored
@ -6,7 +6,7 @@
|
|||||||
/src/Symfony/Component/ErrorRenderer/* @yceruto
|
/src/Symfony/Component/ErrorRenderer/* @yceruto
|
||||||
# Form
|
# Form
|
||||||
/src/Symfony/Bridge/Twig/Extension/FormExtension.php @xabbuh
|
/src/Symfony/Bridge/Twig/Extension/FormExtension.php @xabbuh
|
||||||
/src/Symfony/Bridge/Twig/Form/* @xabbuh
|
/src/Symfony/Bridge/Twig/Form/ @xabbuh
|
||||||
/src/Symfony/Bridge/Twig/Node/FormThemeNode.php @xabbuh
|
/src/Symfony/Bridge/Twig/Node/FormThemeNode.php @xabbuh
|
||||||
/src/Symfony/Bridge/Twig/Node/RenderBlockNode.php @xabbuh
|
/src/Symfony/Bridge/Twig/Node/RenderBlockNode.php @xabbuh
|
||||||
/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php @xabbuh
|
/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php @xabbuh
|
||||||
@ -15,36 +15,36 @@
|
|||||||
/src/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php @xabbuh
|
/src/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php @xabbuh
|
||||||
/src/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php @xabbuh
|
/src/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php @xabbuh
|
||||||
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php @xabbuh
|
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php @xabbuh
|
||||||
/src/Symfony/Bundle/FrameworkBundle/Resources/views/* @xabbuh
|
/src/Symfony/Bundle/FrameworkBundle/Resources/views/ @xabbuh
|
||||||
/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @xabbuh
|
/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @xabbuh
|
||||||
/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/FormPassTest.php @xabbuh
|
/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/FormPassTest.php @xabbuh
|
||||||
/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @xabbuh
|
/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @xabbuh
|
||||||
/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @xabbuh
|
/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @xabbuh
|
||||||
/src/Symfony/Component/Form/* @xabbuh
|
/src/Symfony/Component/Form/ @xabbuh
|
||||||
# HttpKernel
|
# HttpKernel
|
||||||
/src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas
|
/src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas
|
||||||
# LDAP
|
# LDAP
|
||||||
/src/Symfony/Component/Ldap/* @csarrazi
|
/src/Symfony/Component/Ldap/ @csarrazi
|
||||||
# Lock
|
# Lock
|
||||||
/src/Symfony/Component/Lock/* @jderusse
|
/src/Symfony/Component/Lock/ @jderusse
|
||||||
# Messenger
|
# Messenger
|
||||||
/src/Symfony/Bridge/Doctrine/Messenger/* @sroze
|
/src/Symfony/Bridge/Doctrine/Messenger/ @sroze
|
||||||
/src/Symfony/Component/Messenger/* @sroze
|
/src/Symfony/Component/Messenger/ @sroze
|
||||||
# PropertyInfo
|
# PropertyInfo
|
||||||
/src/Symfony/Component/PropertyInfo/* @dunglas
|
/src/Symfony/Component/PropertyInfo/ @dunglas
|
||||||
/src/Symfony/Bridge/Doctrine/PropertyInfo/* @dunglas
|
/src/Symfony/Bridge/Doctrine/PropertyInfo/ @dunglas
|
||||||
# Serializer
|
# Serializer
|
||||||
/src/Symfony/Component/Serializer/* @dunglas
|
/src/Symfony/Component/Serializer/ @dunglas
|
||||||
# TwigBundle
|
# TwigBundle
|
||||||
/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php @yceruto
|
/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php @yceruto
|
||||||
# WebLink
|
# WebLink
|
||||||
/src/Symfony/Component/WebLink/* @dunglas
|
/src/Symfony/Component/WebLink/ @dunglas
|
||||||
# Workflow
|
# Workflow
|
||||||
/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @lyrixx
|
/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @lyrixx
|
||||||
/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @lyrixx
|
/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @lyrixx
|
||||||
/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @lyrixx
|
/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @lyrixx
|
||||||
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @lyrixx
|
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @lyrixx
|
||||||
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/WorkflowGuardListenerPass.php @lyrixx
|
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/WorkflowGuardListenerPass.php @lyrixx
|
||||||
/src/Symfony/Component/Workflow/* @lyrixx
|
/src/Symfony/Component/Workflow/ @lyrixx
|
||||||
# Yaml
|
# Yaml
|
||||||
/src/Symfony/Component/Yaml/* @xabbuh
|
/src/Symfony/Component/Yaml/ @xabbuh
|
||||||
|
@ -209,11 +209,6 @@ Security
|
|||||||
* Not implementing the methods `__serialize` and `__unserialize` in classes implementing
|
* Not implementing the methods `__serialize` and `__unserialize` in classes implementing
|
||||||
the `TokenInterface` is deprecated
|
the `TokenInterface` is deprecated
|
||||||
|
|
||||||
SecurityBundle
|
|
||||||
--------------
|
|
||||||
|
|
||||||
* Configuring encoders using `argon2i` or `bcrypt` as algorithm has been deprecated, use `auto` instead.
|
|
||||||
|
|
||||||
TwigBridge
|
TwigBridge
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -509,7 +509,6 @@ SecurityBundle
|
|||||||
changed to underscores.
|
changed to underscores.
|
||||||
Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore).
|
Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore).
|
||||||
After: `my-cookie` deletes the `my-cookie` cookie (with a dash).
|
After: `my-cookie` deletes the `my-cookie` cookie (with a dash).
|
||||||
* Configuring encoders using `argon2i` or `bcrypt` as algorithm is not supported anymore, use `auto` instead.
|
|
||||||
|
|
||||||
Serializer
|
Serializer
|
||||||
----------
|
----------
|
||||||
|
@ -187,7 +187,7 @@ class EntityTypeTest extends BaseTypeTest
|
|||||||
public function testConfigureQueryBuilderWithNonQueryBuilderAndNonClosure()
|
public function testConfigureQueryBuilderWithNonQueryBuilderAndNonClosure()
|
||||||
{
|
{
|
||||||
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
|
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
|
||||||
$field = $this->factory->createNamed('name', static::TESTED_TYPE, null, [
|
$this->factory->createNamed('name', static::TESTED_TYPE, null, [
|
||||||
'em' => 'default',
|
'em' => 'default',
|
||||||
'class' => self::SINGLE_IDENT_CLASS,
|
'class' => self::SINGLE_IDENT_CLASS,
|
||||||
'query_builder' => new \stdClass(),
|
'query_builder' => new \stdClass(),
|
||||||
|
@ -28,7 +28,6 @@ final class SearchAndRenderBlockNode extends FunctionExpression
|
|||||||
|
|
||||||
preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches);
|
preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches);
|
||||||
|
|
||||||
$label = null;
|
|
||||||
$arguments = iterator_to_array($this->getNode('arguments'));
|
$arguments = iterator_to_array($this->getNode('arguments'));
|
||||||
$blockNameSuffix = $matches[1];
|
$blockNameSuffix = $matches[1];
|
||||||
|
|
||||||
|
@ -82,7 +82,6 @@ col-sm-10
|
|||||||
<div class="{{ block('form_group_class') }}">
|
<div class="{{ block('form_group_class') }}">
|
||||||
{{- form_widget(form) -}}
|
{{- form_widget(form) -}}
|
||||||
{{- form_help(form) -}}
|
{{- form_help(form) -}}
|
||||||
{{- form_errors(form) -}}
|
|
||||||
</div>{#--#}
|
</div>{#--#}
|
||||||
</div>
|
</div>
|
||||||
{%- endblock checkbox_row %}
|
{%- endblock checkbox_row %}
|
||||||
|
@ -180,10 +180,10 @@ class AppVariableTest extends TestCase
|
|||||||
$flashMessages = $this->setFlashMessages();
|
$flashMessages = $this->setFlashMessages();
|
||||||
$this->assertEquals($flashMessages, $this->appVariable->getFlashes([]));
|
$this->assertEquals($flashMessages, $this->appVariable->getFlashes([]));
|
||||||
|
|
||||||
$flashMessages = $this->setFlashMessages();
|
$this->setFlashMessages();
|
||||||
$this->assertEquals([], $this->appVariable->getFlashes('this-does-not-exist'));
|
$this->assertEquals([], $this->appVariable->getFlashes('this-does-not-exist'));
|
||||||
|
|
||||||
$flashMessages = $this->setFlashMessages();
|
$this->setFlashMessages();
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['this-does-not-exist' => []],
|
['this-does-not-exist' => []],
|
||||||
$this->appVariable->getFlashes(['this-does-not-exist'])
|
$this->appVariable->getFlashes(['this-does-not-exist'])
|
||||||
|
@ -52,7 +52,7 @@ class LintCommandTest extends TestCase
|
|||||||
$filename = $this->createFile('');
|
$filename = $this->createFile('');
|
||||||
unlink($filename);
|
unlink($filename);
|
||||||
|
|
||||||
$ret = $tester->execute(['filename' => [$filename]], ['decorated' => false]);
|
$tester->execute(['filename' => [$filename]], ['decorated' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLintFileCompileTimeException()
|
public function testLintFileCompileTimeException()
|
||||||
|
@ -34,7 +34,7 @@ class StopwatchExtensionTest extends TestCase
|
|||||||
$twig->addExtension(new StopwatchExtension($this->getStopwatch($events)));
|
$twig->addExtension(new StopwatchExtension($this->getStopwatch($events)));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$nodes = $twig->render('template');
|
$twig->render('template');
|
||||||
} catch (RuntimeError $e) {
|
} catch (RuntimeError $e) {
|
||||||
throw $e->getPrevious();
|
throw $e->getPrevious();
|
||||||
}
|
}
|
||||||
|
@ -51,14 +51,14 @@ class TranslationExtensionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('Twig\Error\SyntaxError');
|
$this->expectException('Twig\Error\SyntaxError');
|
||||||
$this->expectExceptionMessage('Unexpected token. Twig was looking for the "with", "from", or "into" keyword in "index" at line 3.');
|
$this->expectExceptionMessage('Unexpected token. Twig was looking for the "with", "from", or "into" keyword in "index" at line 3.');
|
||||||
$output = $this->getTemplate("{% trans \n\nfoo %}{% endtrans %}")->render();
|
$this->getTemplate("{% trans \n\nfoo %}{% endtrans %}")->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTransComplexBody()
|
public function testTransComplexBody()
|
||||||
{
|
{
|
||||||
$this->expectException('Twig\Error\SyntaxError');
|
$this->expectException('Twig\Error\SyntaxError');
|
||||||
$this->expectExceptionMessage('A message inside a trans tag must be a simple text in "index" at line 2.');
|
$this->expectExceptionMessage('A message inside a trans tag must be a simple text in "index" at line 2.');
|
||||||
$output = $this->getTemplate("{% trans %}\n{{ 1 + 2 }}{% endtrans %}")->render();
|
$this->getTemplate("{% trans %}\n{{ 1 + 2 }}{% endtrans %}")->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTransTests()
|
public function getTransTests()
|
||||||
|
@ -510,7 +510,6 @@ class TextDescriptor extends Descriptor
|
|||||||
$tableHeaders = ['Order', 'Callable', 'Priority'];
|
$tableHeaders = ['Order', 'Callable', 'Priority'];
|
||||||
$tableRows = [];
|
$tableRows = [];
|
||||||
|
|
||||||
$order = 1;
|
|
||||||
foreach ($eventListeners as $order => $listener) {
|
foreach ($eventListeners as $order => $listener) {
|
||||||
$tableRows[] = [sprintf('#%d', $order + 1), $this->formatCallable($listener), $eventDispatcher->getListenerPriority($event, $listener)];
|
$tableRows[] = [sprintf('#%d', $order + 1), $this->formatCallable($listener), $eventDispatcher->getListenerPriority($event, $listener)];
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,13 @@ class SodiumVault extends AbstractVault
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sodium_crypto_box_seal_open(include $file, $this->decryptionKey);
|
if (false === $value = sodium_crypto_box_seal_open(include $file, $this->decryptionKey)) {
|
||||||
|
$this->lastMessage = sprintf('Secrets cannot be revealed as the wrong decryption key was provided for "%s".', $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remove(string $name): bool
|
public function remove(string $name): bool
|
||||||
|
@ -336,8 +336,7 @@ class AbstractControllerTest extends TestCase
|
|||||||
|
|
||||||
$controller = $this->createController();
|
$controller = $this->createController();
|
||||||
|
|
||||||
/* @var BinaryFileResponse $response */
|
$controller->file('some-file.txt', 'test.php');
|
||||||
$response = $controller->file('some-file.txt', 'test.php');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsGranted()
|
public function testIsGranted()
|
||||||
|
@ -27,7 +27,7 @@ class TestExtension extends Extension implements PrependExtensionInterface
|
|||||||
public function load(array $configs, ContainerBuilder $container)
|
public function load(array $configs, ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$configuration = $this->getConfiguration($configs, $container);
|
$configuration = $this->getConfiguration($configs, $container);
|
||||||
$config = $this->processConfiguration($configuration, $configs);
|
$this->processConfiguration($configuration, $configs);
|
||||||
|
|
||||||
$container->setAlias('test.annotation_reader', new Alias('annotation_reader', true));
|
$container->setAlias('test.annotation_reader', new Alias('annotation_reader', true));
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ class SessionTest extends AbstractWebTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set flash
|
// set flash
|
||||||
$crawler = $client->request('GET', '/session_setflash/Hello%20world.');
|
$client->request('GET', '/session_setflash/Hello%20world.');
|
||||||
|
|
||||||
// check flash displays on redirect
|
// check flash displays on redirect
|
||||||
$this->assertStringContainsString('Hello world.', $client->followRedirect()->text());
|
$this->assertStringContainsString('Hello world.', $client->followRedirect()->text());
|
||||||
|
@ -19,7 +19,8 @@ CHANGELOG
|
|||||||
4.4.0
|
4.4.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
* Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories.
|
* Added new `argon2id` encoder, undeprecated the `bcrypt` and `argon2i` ones (using `auto` is still recommended by default.)
|
||||||
|
* Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories.
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
@ -30,7 +31,6 @@ CHANGELOG
|
|||||||
option is deprecated and will be disabled in Symfony 5.0. This affects to cookies
|
option is deprecated and will be disabled in Symfony 5.0. This affects to cookies
|
||||||
with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie`
|
with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie`
|
||||||
name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore).
|
name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore).
|
||||||
* Deprecated configuring encoders using `argon2i` as algorithm, use `auto` instead
|
|
||||||
|
|
||||||
4.2.0
|
4.2.0
|
||||||
-----
|
-----
|
||||||
|
@ -530,6 +530,41 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bcrypt encoder
|
||||||
|
if ('bcrypt' === $config['algorithm']) {
|
||||||
|
$config['algorithm'] = 'native';
|
||||||
|
$config['native_algorithm'] = PASSWORD_BCRYPT;
|
||||||
|
|
||||||
|
return $this->createEncoder($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Argon2i encoder
|
||||||
|
if ('argon2i' === $config['algorithm']) {
|
||||||
|
if (SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||||
|
$config['algorithm'] = 'sodium';
|
||||||
|
} elseif (\defined('PASSWORD_ARGON2I')) {
|
||||||
|
$config['algorithm'] = 'native';
|
||||||
|
$config['native_algorithm'] = PASSWORD_ARGON2I;
|
||||||
|
} else {
|
||||||
|
throw new InvalidConfigurationException(sprintf('Algorithm "argon2i" is not available. Either use %s"auto" or upgrade to PHP 7.2+ instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? '"argon2id", ' : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createEncoder($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('argon2id' === $config['algorithm']) {
|
||||||
|
if (($hasSodium = SodiumPasswordEncoder::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||||
|
$config['algorithm'] = 'sodium';
|
||||||
|
} elseif (\defined('PASSWORD_ARGON2ID')) {
|
||||||
|
$config['algorithm'] = 'native';
|
||||||
|
$config['native_algorithm'] = PASSWORD_ARGON2ID;
|
||||||
|
} else {
|
||||||
|
throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available. Either use %s"auto", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? '"argon2i", ' : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createEncoder($config);
|
||||||
|
}
|
||||||
|
|
||||||
if ('native' === $config['algorithm']) {
|
if ('native' === $config['algorithm']) {
|
||||||
return [
|
return [
|
||||||
'class' => NativePasswordEncoder::class,
|
'class' => NativePasswordEncoder::class,
|
||||||
@ -537,7 +572,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
|||||||
$config['time_cost'],
|
$config['time_cost'],
|
||||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||||
$config['cost'],
|
$config['cost'],
|
||||||
],
|
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
|||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
|
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
|
||||||
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
|
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
|
||||||
|
|
||||||
abstract class CompleteConfigurationTest extends TestCase
|
abstract class CompleteConfigurationTest extends TestCase
|
||||||
@ -370,6 +371,107 @@ abstract class CompleteConfigurationTest extends TestCase
|
|||||||
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
|
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEncodersWithArgon2i()
|
||||||
|
{
|
||||||
|
if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
|
||||||
|
$this->markTestSkipped('Argon2i algorithm is not supported.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$container = $this->getContainer('argon2i_encoder');
|
||||||
|
|
||||||
|
$this->assertEquals([[
|
||||||
|
'JMS\FooBundle\Entity\User1' => [
|
||||||
|
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
|
||||||
|
'arguments' => [false],
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User2' => [
|
||||||
|
'algorithm' => 'sha1',
|
||||||
|
'encode_as_base64' => false,
|
||||||
|
'iterations' => 5,
|
||||||
|
'hash_algorithm' => 'sha512',
|
||||||
|
'key_length' => 40,
|
||||||
|
'ignore_case' => false,
|
||||||
|
'cost' => null,
|
||||||
|
'memory_cost' => null,
|
||||||
|
'time_cost' => null,
|
||||||
|
'threads' => null,
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User3' => [
|
||||||
|
'algorithm' => 'md5',
|
||||||
|
'hash_algorithm' => 'sha512',
|
||||||
|
'key_length' => 40,
|
||||||
|
'ignore_case' => false,
|
||||||
|
'encode_as_base64' => true,
|
||||||
|
'iterations' => 5000,
|
||||||
|
'cost' => null,
|
||||||
|
'memory_cost' => null,
|
||||||
|
'time_cost' => null,
|
||||||
|
'threads' => null,
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
|
||||||
|
'JMS\FooBundle\Entity\User5' => [
|
||||||
|
'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder',
|
||||||
|
'arguments' => ['sha1', false, 5, 30],
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User6' => [
|
||||||
|
'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder',
|
||||||
|
'arguments' => [8, 102400, 15],
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User7' => [
|
||||||
|
'class' => $sodium ? SodiumPasswordEncoder::class : NativePasswordEncoder::class,
|
||||||
|
'arguments' => $sodium ? [256, 1] : [1, 262144, null, \PASSWORD_ARGON2I],
|
||||||
|
],
|
||||||
|
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncodersWithBCrypt()
|
||||||
|
{
|
||||||
|
$container = $this->getContainer('bcrypt_encoder');
|
||||||
|
$this->assertEquals([[
|
||||||
|
'JMS\FooBundle\Entity\User1' => [
|
||||||
|
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
|
||||||
|
'arguments' => [false],
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User2' => [
|
||||||
|
'algorithm' => 'sha1',
|
||||||
|
'encode_as_base64' => false,
|
||||||
|
'iterations' => 5,
|
||||||
|
'hash_algorithm' => 'sha512',
|
||||||
|
'key_length' => 40,
|
||||||
|
'ignore_case' => false,
|
||||||
|
'cost' => null,
|
||||||
|
'memory_cost' => null,
|
||||||
|
'time_cost' => null,
|
||||||
|
'threads' => null,
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User3' => [
|
||||||
|
'algorithm' => 'md5',
|
||||||
|
'hash_algorithm' => 'sha512',
|
||||||
|
'key_length' => 40,
|
||||||
|
'ignore_case' => false,
|
||||||
|
'encode_as_base64' => true,
|
||||||
|
'iterations' => 5000,
|
||||||
|
'cost' => null,
|
||||||
|
'memory_cost' => null,
|
||||||
|
'time_cost' => null,
|
||||||
|
'threads' => null,
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
|
||||||
|
'JMS\FooBundle\Entity\User5' => [
|
||||||
|
'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder',
|
||||||
|
'arguments' => ['sha1', false, 5, 30],
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User6' => [
|
||||||
|
'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder',
|
||||||
|
'arguments' => [8, 102400, 15],
|
||||||
|
],
|
||||||
|
'JMS\FooBundle\Entity\User7' => [
|
||||||
|
'class' => NativePasswordEncoder::class,
|
||||||
|
'arguments' => [null, null, 15, \PASSWORD_BCRYPT],
|
||||||
|
],
|
||||||
|
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
|
||||||
|
}
|
||||||
|
|
||||||
public function testRememberMeThrowExceptionsDefault()
|
public function testRememberMeThrowExceptionsDefault()
|
||||||
{
|
{
|
||||||
$container = $this->getContainer('container1');
|
$container = $this->getContainer('container1');
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$this->load('container1.php', $container);
|
||||||
|
|
||||||
|
$container->loadFromExtension('security', [
|
||||||
|
'encoders' => [
|
||||||
|
'JMS\FooBundle\Entity\User7' => [
|
||||||
|
'algorithm' => 'argon2i',
|
||||||
|
'memory_cost' => 256,
|
||||||
|
'time_cost' => 1,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:sec="http://symfony.com/schema/dic/security"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||||
|
|
||||||
|
<imports>
|
||||||
|
<import resource="container1.xml"/>
|
||||||
|
</imports>
|
||||||
|
|
||||||
|
<sec:config>
|
||||||
|
<sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="argon2i" memory_cost="256" time_cost="1" />
|
||||||
|
</sec:config>
|
||||||
|
|
||||||
|
</container>
|
@ -0,0 +1,9 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: container1.yml }
|
||||||
|
|
||||||
|
security:
|
||||||
|
encoders:
|
||||||
|
JMS\FooBundle\Entity\User7:
|
||||||
|
algorithm: argon2i
|
||||||
|
memory_cost: 256
|
||||||
|
time_cost: 1
|
@ -61,7 +61,7 @@ class AbstractFactoryTest extends TestCase
|
|||||||
$options['failure_handler'] = $serviceId;
|
$options['failure_handler'] = $serviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
|
list($container) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
|
||||||
|
|
||||||
$definition = $container->getDefinition('abstract_listener.foo');
|
$definition = $container->getDefinition('abstract_listener.foo');
|
||||||
$arguments = $definition->getArguments();
|
$arguments = $definition->getArguments();
|
||||||
@ -99,7 +99,7 @@ class AbstractFactoryTest extends TestCase
|
|||||||
$options['success_handler'] = $serviceId;
|
$options['success_handler'] = $serviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
|
list($container) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
|
||||||
|
|
||||||
$definition = $container->getDefinition('abstract_listener.foo');
|
$definition = $container->getDefinition('abstract_listener.foo');
|
||||||
$arguments = $definition->getArguments();
|
$arguments = $definition->getArguments();
|
||||||
|
@ -159,7 +159,7 @@ class GuardAuthenticationFactoryTest extends TestCase
|
|||||||
'authenticators' => ['authenticator123', 'authenticatorABC'],
|
'authenticators' => ['authenticator123', 'authenticatorABC'],
|
||||||
'entry_point' => 'authenticatorABC',
|
'entry_point' => 'authenticatorABC',
|
||||||
];
|
];
|
||||||
list($container, $entryPointId) = $this->executeCreate($config, null);
|
list(, $entryPointId) = $this->executeCreate($config, null);
|
||||||
$this->assertEquals('authenticatorABC', $entryPointId);
|
$this->assertEquals('authenticatorABC', $entryPointId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ class GuardAuthenticationFactoryTest extends TestCase
|
|||||||
$userProviderId = 'my_user_provider';
|
$userProviderId = 'my_user_provider';
|
||||||
|
|
||||||
$factory = new GuardAuthenticationFactory();
|
$factory = new GuardAuthenticationFactory();
|
||||||
list($providerId, $listenerId, $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
|
list(, , $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
|
||||||
|
|
||||||
return [$container, $entryPointId];
|
return [$container, $entryPointId];
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class MissingUserProviderTest extends AbstractWebTestCase
|
|||||||
|
|
||||||
$response = $client->getResponse();
|
$response = $client->getResponse();
|
||||||
$this->assertSame(500, $response->getStatusCode());
|
$this->assertSame(500, $response->getStatusCode());
|
||||||
$this->stringContains('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', $response->getContent());
|
$this->assertStringContainsString('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', $response->getContent());
|
||||||
$this->stringContains('"default" firewall requires a user provider but none was defined.', $response->getContent());
|
$this->assertStringContainsString('"default" firewall requires a user provider but none was defined', html_entity_decode($response->getContent()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,66 @@ class UserPasswordEncoderCommandTest extends AbstractWebTestCase
|
|||||||
$this->assertEquals($statusCode, 1);
|
$this->assertEquals($statusCode, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEncodePasswordBcrypt()
|
||||||
|
{
|
||||||
|
$this->setupBcrypt();
|
||||||
|
$this->passwordEncoderCommandTester->execute([
|
||||||
|
'command' => 'security:encode-password',
|
||||||
|
'password' => 'password',
|
||||||
|
'user-class' => 'Custom\Class\Bcrypt\User',
|
||||||
|
], ['interactive' => false]);
|
||||||
|
|
||||||
|
$output = $this->passwordEncoderCommandTester->getDisplay();
|
||||||
|
$this->assertStringContainsString('Password encoding succeeded', $output);
|
||||||
|
|
||||||
|
$encoder = new NativePasswordEncoder(null, null, 17, PASSWORD_BCRYPT);
|
||||||
|
preg_match('# Encoded password\s{1,}([\w+\/$.]+={0,2})\s+#', $output, $matches);
|
||||||
|
$hash = $matches[1];
|
||||||
|
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncodePasswordArgon2i()
|
||||||
|
{
|
||||||
|
if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
|
||||||
|
$this->markTestSkipped('Argon2i algorithm not available.');
|
||||||
|
}
|
||||||
|
$this->setupArgon2i();
|
||||||
|
$this->passwordEncoderCommandTester->execute([
|
||||||
|
'command' => 'security:encode-password',
|
||||||
|
'password' => 'password',
|
||||||
|
'user-class' => 'Custom\Class\Argon2i\User',
|
||||||
|
], ['interactive' => false]);
|
||||||
|
|
||||||
|
$output = $this->passwordEncoderCommandTester->getDisplay();
|
||||||
|
$this->assertStringContainsString('Password encoding succeeded', $output);
|
||||||
|
|
||||||
|
$encoder = $sodium ? new SodiumPasswordEncoder() : new NativePasswordEncoder(null, null, null, PASSWORD_ARGON2I);
|
||||||
|
preg_match('# Encoded password\s+(\$argon2i?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches);
|
||||||
|
$hash = $matches[1];
|
||||||
|
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncodePasswordArgon2id()
|
||||||
|
{
|
||||||
|
if (!($sodium = (SodiumPasswordEncoder::isSupported() && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13'))) && !\defined('PASSWORD_ARGON2ID')) {
|
||||||
|
$this->markTestSkipped('Argon2id algorithm not available.');
|
||||||
|
}
|
||||||
|
$this->setupArgon2id();
|
||||||
|
$this->passwordEncoderCommandTester->execute([
|
||||||
|
'command' => 'security:encode-password',
|
||||||
|
'password' => 'password',
|
||||||
|
'user-class' => 'Custom\Class\Argon2id\User',
|
||||||
|
], ['interactive' => false]);
|
||||||
|
|
||||||
|
$output = $this->passwordEncoderCommandTester->getDisplay();
|
||||||
|
$this->assertStringContainsString('Password encoding succeeded', $output);
|
||||||
|
|
||||||
|
$encoder = $sodium ? new SodiumPasswordEncoder() : new NativePasswordEncoder(null, null, null, PASSWORD_ARGON2ID);
|
||||||
|
preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches);
|
||||||
|
$hash = $matches[1];
|
||||||
|
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
|
||||||
|
}
|
||||||
|
|
||||||
public function testEncodePasswordNative()
|
public function testEncodePasswordNative()
|
||||||
{
|
{
|
||||||
$this->passwordEncoderCommandTester->execute([
|
$this->passwordEncoderCommandTester->execute([
|
||||||
@ -148,6 +208,38 @@ class UserPasswordEncoderCommandTest extends AbstractWebTestCase
|
|||||||
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
|
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEncodePasswordArgon2iOutput()
|
||||||
|
{
|
||||||
|
if (!(SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
|
||||||
|
$this->markTestSkipped('Argon2i algorithm not available.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setupArgon2i();
|
||||||
|
$this->passwordEncoderCommandTester->execute([
|
||||||
|
'command' => 'security:encode-password',
|
||||||
|
'password' => 'p@ssw0rd',
|
||||||
|
'user-class' => 'Custom\Class\Argon2i\User',
|
||||||
|
], ['interactive' => false]);
|
||||||
|
|
||||||
|
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncodePasswordArgon2idOutput()
|
||||||
|
{
|
||||||
|
if (!(SodiumPasswordEncoder::isSupported() && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2ID')) {
|
||||||
|
$this->markTestSkipped('Argon2id algorithm not available.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setupArgon2id();
|
||||||
|
$this->passwordEncoderCommandTester->execute([
|
||||||
|
'command' => 'security:encode-password',
|
||||||
|
'password' => 'p@ssw0rd',
|
||||||
|
'user-class' => 'Custom\Class\Argon2id\User',
|
||||||
|
], ['interactive' => false]);
|
||||||
|
|
||||||
|
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
public function testEncodePasswordSodiumOutput()
|
public function testEncodePasswordSodiumOutput()
|
||||||
{
|
{
|
||||||
if (!SodiumPasswordEncoder::isSupported()) {
|
if (!SodiumPasswordEncoder::isSupported()) {
|
||||||
@ -238,6 +330,45 @@ EOTXT
|
|||||||
$this->passwordEncoderCommandTester = null;
|
$this->passwordEncoderCommandTester = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setupArgon2i()
|
||||||
|
{
|
||||||
|
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
|
||||||
|
$kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2i.yml']);
|
||||||
|
$kernel->boot();
|
||||||
|
|
||||||
|
$application = new Application($kernel);
|
||||||
|
|
||||||
|
$passwordEncoderCommand = $application->get('security:encode-password');
|
||||||
|
|
||||||
|
$this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setupArgon2id()
|
||||||
|
{
|
||||||
|
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
|
||||||
|
$kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2id.yml']);
|
||||||
|
$kernel->boot();
|
||||||
|
|
||||||
|
$application = new Application($kernel);
|
||||||
|
|
||||||
|
$passwordEncoderCommand = $application->get('security:encode-password');
|
||||||
|
|
||||||
|
$this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setupBcrypt()
|
||||||
|
{
|
||||||
|
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
|
||||||
|
$kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'bcrypt.yml']);
|
||||||
|
$kernel->boot();
|
||||||
|
|
||||||
|
$application = new Application($kernel);
|
||||||
|
|
||||||
|
$passwordEncoderCommand = $application->get('security:encode-password');
|
||||||
|
|
||||||
|
$this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand);
|
||||||
|
}
|
||||||
|
|
||||||
private function setupSodium()
|
private function setupSodium()
|
||||||
{
|
{
|
||||||
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
|
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: config.yml }
|
||||||
|
|
||||||
|
security:
|
||||||
|
encoders:
|
||||||
|
Custom\Class\Argon2id\User:
|
||||||
|
algorithm: argon2id
|
@ -46,6 +46,8 @@
|
|||||||
--base-4: #666;
|
--base-4: #666;
|
||||||
--base-5: #444;
|
--base-5: #444;
|
||||||
--base-6: #222;
|
--base-6: #222;
|
||||||
|
--card-label-background: #eee;
|
||||||
|
--card-label-color: var(--base-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-dark {
|
.theme-dark {
|
||||||
@ -85,6 +87,8 @@
|
|||||||
--base-4: #666;
|
--base-4: #666;
|
||||||
--base-5: #e0e0e0;
|
--base-5: #e0e0e0;
|
||||||
--base-6: #f5f5f5;
|
--base-6: #f5f5f5;
|
||||||
|
--card-label-background: var(--tab-active-background);
|
||||||
|
--card-label-color: var(--tab-active-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
{# Basic styles
|
{# Basic styles
|
||||||
@ -436,8 +440,8 @@ table tbody td.num-col {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
.card .label {
|
.card .label {
|
||||||
background-color: #EEE;
|
background-color: var(--card-label-background);
|
||||||
color: var(--base-6);
|
color: var(--card-label-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
{# Status
|
{# Status
|
||||||
|
@ -201,7 +201,7 @@ class CookieTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('UnexpectedValueException');
|
$this->expectException('UnexpectedValueException');
|
||||||
$this->expectExceptionMessage('The cookie expiration time "string" is not valid.');
|
$this->expectExceptionMessage('The cookie expiration time "string" is not valid.');
|
||||||
$cookie = new Cookie('foo', 'bar', 'string');
|
new Cookie('foo', 'bar', 'string');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSameSite()
|
public function testSameSite()
|
||||||
|
@ -70,7 +70,7 @@ class MaxIdLengthAdapterTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
||||||
$this->expectExceptionMessage('Namespace must be 26 chars max, 40 given ("----------------------------------------")');
|
$this->expectExceptionMessage('Namespace must be 26 chars max, 40 given ("----------------------------------------")');
|
||||||
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
|
$this->getMockBuilder(MaxIdLengthAdapter::class)
|
||||||
->setConstructorArgs([str_repeat('-', 40)])
|
->setConstructorArgs([str_repeat('-', 40)])
|
||||||
->getMock();
|
->getMock();
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class DelegatingLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function testConstructor()
|
public function testConstructor()
|
||||||
{
|
{
|
||||||
$loader = new DelegatingLoader($resolver = new LoaderResolver());
|
new DelegatingLoader($resolver = new LoaderResolver());
|
||||||
$this->assertTrue(true, '__construct() takes a loader resolver as its first argument');
|
$this->assertTrue(true, '__construct() takes a loader resolver as its first argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ EOF
|
|||||||
|
|
||||||
$loadedClass = 123;
|
$loadedClass = 123;
|
||||||
|
|
||||||
$res = new ClassExistenceResource('MissingFooClass', false);
|
new ClassExistenceResource('MissingFooClass', false);
|
||||||
|
|
||||||
$this->assertSame(123, $loadedClass);
|
$this->assertSame(123, $loadedClass);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -67,7 +67,7 @@ class DirectoryResourceTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$this->expectExceptionMessageRegExp('/The directory ".*" does not exist./');
|
$this->expectExceptionMessageRegExp('/The directory ".*" does not exist./');
|
||||||
$resource = new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
|
new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsFresh()
|
public function testIsFresh()
|
||||||
@ -165,7 +165,7 @@ class DirectoryResourceTest extends TestCase
|
|||||||
{
|
{
|
||||||
$resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
|
$resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
|
||||||
|
|
||||||
$unserialized = unserialize(serialize($resource));
|
unserialize(serialize($resource));
|
||||||
|
|
||||||
$this->assertSame(realpath($this->directory), $resource->getResource());
|
$this->assertSame(realpath($this->directory), $resource->getResource());
|
||||||
$this->assertSame('/\.(foo|xml)$/', $resource->getPattern());
|
$this->assertSame('/\.(foo|xml)$/', $resource->getPattern());
|
||||||
|
@ -57,7 +57,7 @@ class FileResourceTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$this->expectExceptionMessageRegExp('/The file ".*" does not exist./');
|
$this->expectExceptionMessageRegExp('/The file ".*" does not exist./');
|
||||||
$resource = new FileResource('/____foo/foobar'.mt_rand(1, 999999));
|
new FileResource('/____foo/foobar'.mt_rand(1, 999999));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsFresh()
|
public function testIsFresh()
|
||||||
@ -76,7 +76,7 @@ class FileResourceTest extends TestCase
|
|||||||
|
|
||||||
public function testSerializeUnserialize()
|
public function testSerializeUnserialize()
|
||||||
{
|
{
|
||||||
$unserialized = unserialize(serialize($this->resource));
|
unserialize(serialize($this->resource));
|
||||||
|
|
||||||
$this->assertSame(realpath($this->file), $this->resource->getResource());
|
$this->assertSame(realpath($this->file), $this->resource->getResource());
|
||||||
}
|
}
|
||||||
|
@ -579,7 +579,7 @@ class ApplicationTest extends TestCase
|
|||||||
|
|
||||||
// Subnamespace + plural
|
// Subnamespace + plural
|
||||||
try {
|
try {
|
||||||
$a = $application->find('foo3:');
|
$application->find('foo3:');
|
||||||
$this->fail('->find() should throw an Symfony\Component\Console\Exception\CommandNotFoundException if a command is ambiguous because of a subnamespace, with alternatives');
|
$this->fail('->find() should throw an Symfony\Component\Console\Exception\CommandNotFoundException if a command is ambiguous because of a subnamespace, with alternatives');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e);
|
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e);
|
||||||
|
@ -104,7 +104,7 @@ class ProgressIndicatorTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$this->expectExceptionMessage('Must have at least 2 indicator value characters.');
|
$this->expectExceptionMessage('Must have at least 2 indicator value characters.');
|
||||||
$bar = new ProgressIndicator($this->getOutputStream(), null, 100, ['1']);
|
new ProgressIndicator($this->getOutputStream(), null, 100, ['1']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCannotStartAlreadyStartedIndicator()
|
public function testCannotStartAlreadyStartedIndicator()
|
||||||
|
@ -269,7 +269,7 @@ EOF;
|
|||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
$c .= ' '.$this->doExport($id)." => true,\n";
|
$c .= ' '.$this->doExport($id)." => true,\n";
|
||||||
}
|
}
|
||||||
$files['removed-ids.php'] = $c .= "];\n";
|
$files['removed-ids.php'] = $c."];\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->inlineFactories) {
|
if (!$this->inlineFactories) {
|
||||||
|
@ -24,28 +24,28 @@ class AnalyzeServiceReferencesPassTest extends TestCase
|
|||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
$a = $container
|
$container
|
||||||
->register('a')
|
->register('a')
|
||||||
->addArgument($ref1 = new Reference('b'))
|
->addArgument($ref1 = new Reference('b'))
|
||||||
;
|
;
|
||||||
|
|
||||||
$b = $container
|
$container
|
||||||
->register('b')
|
->register('b')
|
||||||
->addMethodCall('setA', [$ref2 = new Reference('a')])
|
->addMethodCall('setA', [$ref2 = new Reference('a')])
|
||||||
;
|
;
|
||||||
|
|
||||||
$c = $container
|
$container
|
||||||
->register('c')
|
->register('c')
|
||||||
->addArgument($ref3 = new Reference('a'))
|
->addArgument($ref3 = new Reference('a'))
|
||||||
->addArgument($ref4 = new Reference('b'))
|
->addArgument($ref4 = new Reference('b'))
|
||||||
;
|
;
|
||||||
|
|
||||||
$d = $container
|
$container
|
||||||
->register('d')
|
->register('d')
|
||||||
->setProperty('foo', $ref5 = new Reference('b'))
|
->setProperty('foo', $ref5 = new Reference('b'))
|
||||||
;
|
;
|
||||||
|
|
||||||
$e = $container
|
$container
|
||||||
->register('e')
|
->register('e')
|
||||||
->setConfigurator([$ref6 = new Reference('b'), 'methodName'])
|
->setConfigurator([$ref6 = new Reference('b'), 'methodName'])
|
||||||
;
|
;
|
||||||
|
@ -51,7 +51,7 @@ class IntegrationTest extends TestCase
|
|||||||
->setPublic(true)
|
->setPublic(true)
|
||||||
;
|
;
|
||||||
|
|
||||||
$b = $container
|
$container
|
||||||
->register('b', '\stdClass')
|
->register('b', '\stdClass')
|
||||||
->addArgument(new Reference('c'))
|
->addArgument(new Reference('c'))
|
||||||
->setPublic(false)
|
->setPublic(false)
|
||||||
|
@ -363,7 +363,7 @@ class ResolveChildDefinitionsPassTest extends TestCase
|
|||||||
->setBindings(['a' => '1', 'b' => '2'])
|
->setBindings(['a' => '1', 'b' => '2'])
|
||||||
;
|
;
|
||||||
|
|
||||||
$child = $container->setDefinition('child', new ChildDefinition('parent'))
|
$container->setDefinition('child', new ChildDefinition('parent'))
|
||||||
->setBindings(['b' => 'B', 'c' => 'C'])
|
->setBindings(['b' => 'B', 'c' => 'C'])
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ class ResolveClassPassTest extends TestCase
|
|||||||
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
|
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
|
||||||
$this->expectExceptionMessage('Service definition "App\Foo\Child" has a parent but no class, and its name looks like a FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.');
|
$this->expectExceptionMessage('Service definition "App\Foo\Child" has a parent but no class, and its name looks like a FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.');
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
$parent = $container->register('App\Foo', null);
|
$container->register('App\Foo', null);
|
||||||
$child = $container->setDefinition('App\Foo\Child', new ChildDefinition('App\Foo'));
|
$container->setDefinition('App\Foo\Child', new ChildDefinition('App\Foo'));
|
||||||
|
|
||||||
(new ResolveClassPass())->process($container);
|
(new ResolveClassPass())->process($container);
|
||||||
}
|
}
|
||||||
|
@ -1272,7 +1272,7 @@ class ContainerBuilderTest extends TestCase
|
|||||||
$this->expectExceptionMessage('The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.');
|
$this->expectExceptionMessage('The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.');
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
$definition = $container->register(\DateTime::class);
|
$container->register(\DateTime::class);
|
||||||
$container->compile();
|
$container->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1302,7 +1302,7 @@ class ContainerBuilderTest extends TestCase
|
|||||||
$this->expectExceptionMessage('The definition for "123_abc" has no class.');
|
$this->expectExceptionMessage('The definition for "123_abc" has no class.');
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
$definition = $container->register('123_abc');
|
$container->register('123_abc');
|
||||||
$container->compile();
|
$container->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,7 +1312,7 @@ class ContainerBuilderTest extends TestCase
|
|||||||
$this->expectExceptionMessage('The definition for "\foo" has no class.');
|
$this->expectExceptionMessage('The definition for "\foo" has no class.');
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
$definition = $container->register('\\foo');
|
$container->register('\\foo');
|
||||||
$container->compile();
|
$container->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1091,7 +1091,7 @@ class PhpDumperTest extends TestCase
|
|||||||
->setPublic(true)
|
->setPublic(true)
|
||||||
->addArgument($baz);
|
->addArgument($baz);
|
||||||
|
|
||||||
$passConfig = $container->getCompiler()->getPassConfig();
|
$container->getCompiler()->getPassConfig();
|
||||||
$container->compile();
|
$container->compile();
|
||||||
|
|
||||||
$dumper = new PhpDumper($container);
|
$dumper = new PhpDumper($container);
|
||||||
@ -1183,7 +1183,6 @@ class PhpDumperTest extends TestCase
|
|||||||
$container->compile();
|
$container->compile();
|
||||||
|
|
||||||
$dumper = new PhpDumper($container);
|
$dumper = new PhpDumper($container);
|
||||||
$dump = $dumper->dump();
|
|
||||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_adawson.php', $dumper->dump());
|
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_adawson.php', $dumper->dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +884,6 @@ class XmlFileLoaderTest extends TestCase
|
|||||||
$container->compile();
|
$container->compile();
|
||||||
|
|
||||||
$dumper = new PhpDumper($container);
|
$dumper = new PhpDumper($container);
|
||||||
$dump = $dumper->dump();
|
|
||||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_tsantos.php', $dumper->dump());
|
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_tsantos.php', $dumper->dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class ChoiceFormFieldTest extends FormFieldTestCase
|
|||||||
{
|
{
|
||||||
$node = $this->createNode('textarea', '');
|
$node = $this->createNode('textarea', '');
|
||||||
try {
|
try {
|
||||||
$field = new ChoiceFormField($node);
|
new ChoiceFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is not an input or a select');
|
$this->fail('->initialize() throws a \LogicException if the node is not an input or a select');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input or a select');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input or a select');
|
||||||
@ -27,7 +27,7 @@ class ChoiceFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('input', '', ['type' => 'text']);
|
$node = $this->createNode('input', '', ['type' => 'text']);
|
||||||
try {
|
try {
|
||||||
$field = new ChoiceFormField($node);
|
new ChoiceFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
|
$this->fail('->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
|
||||||
|
@ -24,7 +24,7 @@ class FileFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('textarea', '');
|
$node = $this->createNode('textarea', '');
|
||||||
try {
|
try {
|
||||||
$field = new FileFormField($node);
|
new FileFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is not an input field');
|
$this->fail('->initialize() throws a \LogicException if the node is not an input field');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input field');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input field');
|
||||||
@ -32,7 +32,7 @@ class FileFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('input', '', ['type' => 'text']);
|
$node = $this->createNode('input', '', ['type' => 'text']);
|
||||||
try {
|
try {
|
||||||
$field = new FileFormField($node);
|
new FileFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is not a file input field');
|
$this->fail('->initialize() throws a \LogicException if the node is not a file input field');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a file input field');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a file input field');
|
||||||
|
@ -24,7 +24,7 @@ class InputFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('textarea', '');
|
$node = $this->createNode('textarea', '');
|
||||||
try {
|
try {
|
||||||
$field = new InputFormField($node);
|
new InputFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is not an input');
|
$this->fail('->initialize() throws a \LogicException if the node is not an input');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input');
|
||||||
@ -32,7 +32,7 @@ class InputFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('input', '', ['type' => 'checkbox']);
|
$node = $this->createNode('input', '', ['type' => 'checkbox']);
|
||||||
try {
|
try {
|
||||||
$field = new InputFormField($node);
|
new InputFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is a checkbox');
|
$this->fail('->initialize() throws a \LogicException if the node is a checkbox');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is a checkbox');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is a checkbox');
|
||||||
@ -40,7 +40,7 @@ class InputFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('input', '', ['type' => 'file']);
|
$node = $this->createNode('input', '', ['type' => 'file']);
|
||||||
try {
|
try {
|
||||||
$field = new InputFormField($node);
|
new InputFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is a file');
|
$this->fail('->initialize() throws a \LogicException if the node is a file');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is a file');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is a file');
|
||||||
|
@ -24,7 +24,7 @@ class TextareaFormFieldTest extends FormFieldTestCase
|
|||||||
|
|
||||||
$node = $this->createNode('input', '');
|
$node = $this->createNode('input', '');
|
||||||
try {
|
try {
|
||||||
$field = new TextareaFormField($node);
|
new TextareaFormField($node);
|
||||||
$this->fail('->initialize() throws a \LogicException if the node is not a textarea');
|
$this->fail('->initialize() throws a \LogicException if the node is not a textarea');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a textarea');
|
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a textarea');
|
||||||
|
@ -39,14 +39,14 @@ class FormTest extends TestCase
|
|||||||
$nodes = $dom->getElementsByTagName('input');
|
$nodes = $dom->getElementsByTagName('input');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$form = new Form($nodes->item(0), 'http://example.com');
|
new Form($nodes->item(0), 'http://example.com');
|
||||||
$this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
|
$this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
|
$this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$form = new Form($nodes->item(1), 'http://example.com');
|
new Form($nodes->item(1), 'http://example.com');
|
||||||
$this->fail('__construct() throws a \\LogicException if the input type is not submit, button, or image');
|
$this->fail('__construct() throws a \\LogicException if the input type is not submit, button, or image');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '__construct() throws a \\LogicException if the input type is not submit, button, or image');
|
$this->assertTrue(true, '__construct() throws a \\LogicException if the input type is not submit, button, or image');
|
||||||
@ -55,7 +55,7 @@ class FormTest extends TestCase
|
|||||||
$nodes = $dom->getElementsByTagName('button');
|
$nodes = $dom->getElementsByTagName('button');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$form = new Form($nodes->item(0), 'http://example.com');
|
new Form($nodes->item(0), 'http://example.com');
|
||||||
$this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
|
$this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
$this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
|
$this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
|
||||||
@ -63,11 +63,19 @@ class FormTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __construct() should throw \\LogicException if the form attribute is invalid.
|
* @dataProvider constructorThrowsExceptionIfNoRelatedFormProvider
|
||||||
|
*
|
||||||
|
* __construct() should throw a \LogicException if the form attribute is invalid.
|
||||||
*/
|
*/
|
||||||
public function testConstructorThrowsExceptionIfNoRelatedForm()
|
public function testConstructorThrowsExceptionIfNoRelatedForm(\DOMElement $node)
|
||||||
{
|
{
|
||||||
$this->expectException('LogicException');
|
$this->expectException('LogicException');
|
||||||
|
|
||||||
|
new Form($node, 'http://example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function constructorThrowsExceptionIfNoRelatedFormProvider()
|
||||||
|
{
|
||||||
$dom = new \DOMDocument();
|
$dom = new \DOMDocument();
|
||||||
$dom->loadHTML('
|
$dom->loadHTML('
|
||||||
<html>
|
<html>
|
||||||
@ -81,8 +89,10 @@ class FormTest extends TestCase
|
|||||||
|
|
||||||
$nodes = $dom->getElementsByTagName('input');
|
$nodes = $dom->getElementsByTagName('input');
|
||||||
|
|
||||||
$form = new Form($nodes->item(0), 'http://example.com');
|
return [
|
||||||
$form = new Form($nodes->item(1), 'http://example.com');
|
[$nodes->item(0)],
|
||||||
|
[$nodes->item(1)],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConstructorLoadsOnlyFieldsOfTheRightForm()
|
public function testConstructorLoadsOnlyFieldsOfTheRightForm()
|
||||||
|
@ -751,7 +751,7 @@ class DebugClassLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($dirFiles[$file])) {
|
if (isset($dirFiles[$file])) {
|
||||||
return $real .= $dirFiles[$file];
|
return $real.$dirFiles[$file];
|
||||||
}
|
}
|
||||||
|
|
||||||
$kFile = strtolower($file);
|
$kFile = strtolower($file);
|
||||||
@ -770,7 +770,7 @@ class DebugClassLoader
|
|||||||
self::$darwinCache[$kDir][1] = $dirFiles;
|
self::$darwinCache[$kDir][1] = $dirFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $real .= $dirFiles[$kFile];
|
return $real.$dirFiles[$kFile];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -294,7 +294,7 @@ class FlattenExceptionTest extends TestCase
|
|||||||
|
|
||||||
// assertEquals() does not like NAN values.
|
// assertEquals() does not like NAN values.
|
||||||
$this->assertEquals($array[$i][0], 'float');
|
$this->assertEquals($array[$i][0], 'float');
|
||||||
$this->assertNan($array[$i++][1]);
|
$this->assertNan($array[$i][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRecursionInArguments()
|
public function testRecursionInArguments()
|
||||||
|
@ -63,6 +63,14 @@ class ExpressionLanguageTest extends TestCase
|
|||||||
$this->assertSame($savedParsedExpression, $parsedExpression);
|
$this->assertSame($savedParsedExpression, $parsedExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testWrongCacheImplementation()
|
||||||
|
{
|
||||||
|
$this->expectException('InvalidArgumentException');
|
||||||
|
$this->expectExceptionMessage('Cache argument has to implement Psr\Cache\CacheItemPoolInterface.');
|
||||||
|
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemSpoolInterface')->getMock();
|
||||||
|
new ExpressionLanguage($cacheMock);
|
||||||
|
}
|
||||||
|
|
||||||
public function testConstantFunction()
|
public function testConstantFunction()
|
||||||
{
|
{
|
||||||
$expressionLanguage = new ExpressionLanguage();
|
$expressionLanguage = new ExpressionLanguage();
|
||||||
@ -158,7 +166,7 @@ class ExpressionLanguageTest extends TestCase
|
|||||||
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemPoolInterface')->getMock();
|
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemPoolInterface')->getMock();
|
||||||
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
|
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
|
||||||
$expressionLanguage = new ExpressionLanguage($cacheMock);
|
$expressionLanguage = new ExpressionLanguage($cacheMock);
|
||||||
$savedParsedExpressions = [];
|
$savedParsedExpression = null;
|
||||||
|
|
||||||
$cacheMock
|
$cacheMock
|
||||||
->expects($this->exactly(2))
|
->expects($this->exactly(2))
|
||||||
|
@ -131,7 +131,8 @@ class FormDataCollector extends DataCollector implements FormDataCollectorInterf
|
|||||||
$hash = spl_object_hash($form);
|
$hash = spl_object_hash($form);
|
||||||
|
|
||||||
if (!isset($this->dataByForm[$hash])) {
|
if (!isset($this->dataByForm[$hash])) {
|
||||||
$this->dataByForm[$hash] = [];
|
// field was created by form event
|
||||||
|
$this->collectConfiguration($form);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->dataByForm[$hash] = array_replace(
|
$this->dataByForm[$hash] = array_replace(
|
||||||
|
@ -181,10 +181,10 @@ class DateTimeToLocalizedStringTransformerTest extends TestCase
|
|||||||
|
|
||||||
public function testTransformWrapsIntlErrors()
|
public function testTransformWrapsIntlErrors()
|
||||||
{
|
{
|
||||||
$transformer = new DateTimeToLocalizedStringTransformer();
|
|
||||||
|
|
||||||
$this->markTestIncomplete('Checking for intl errors needs to be reimplemented');
|
$this->markTestIncomplete('Checking for intl errors needs to be reimplemented');
|
||||||
|
|
||||||
|
$transformer = new DateTimeToLocalizedStringTransformer();
|
||||||
|
|
||||||
// HOW TO REPRODUCE?
|
// HOW TO REPRODUCE?
|
||||||
|
|
||||||
//$this->expectException('Symfony\Component\Form\Extension\Core\DataTransformer\TransformationFailedException');
|
//$this->expectException('Symfony\Component\Form\Extension\Core\DataTransformer\TransformationFailedException');
|
||||||
|
@ -13,10 +13,20 @@ namespace Symfony\Component\Form\Tests\Extension\DataCollector;
|
|||||||
|
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||||
|
use Symfony\Component\Form\Extension\Core\CoreExtension;
|
||||||
|
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
|
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
|
||||||
use Symfony\Component\Form\Form;
|
use Symfony\Component\Form\Form;
|
||||||
use Symfony\Component\Form\FormBuilder;
|
use Symfony\Component\Form\FormBuilder;
|
||||||
|
use Symfony\Component\Form\FormFactory;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormRegistry;
|
||||||
use Symfony\Component\Form\FormView;
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\Form\ResolvedFormTypeFactory;
|
||||||
|
|
||||||
class FormDataCollectorTest extends TestCase
|
class FormDataCollectorTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -69,9 +79,9 @@ class FormDataCollectorTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->dataExtractor = $this->getMockBuilder('Symfony\Component\Form\Extension\DataCollector\FormDataExtractorInterface')->getMock();
|
$this->dataExtractor = $this->getMockBuilder('Symfony\Component\Form\Extension\DataCollector\FormDataExtractorInterface')->getMock();
|
||||||
$this->dataCollector = new FormDataCollector($this->dataExtractor);
|
$this->dataCollector = new FormDataCollector($this->dataExtractor);
|
||||||
$this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
|
$this->dispatcher = new EventDispatcher();
|
||||||
$this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock();
|
$this->factory = new FormFactory(new FormRegistry([new CoreExtension()], new ResolvedFormTypeFactory()));
|
||||||
$this->dataMapper = $this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock();
|
$this->dataMapper = new PropertyPathMapper();
|
||||||
$this->form = $this->createForm('name');
|
$this->form = $this->createForm('name');
|
||||||
$this->childForm = $this->createForm('child');
|
$this->childForm = $this->createForm('child');
|
||||||
$this->view = new FormView();
|
$this->view = new FormView();
|
||||||
@ -726,6 +736,56 @@ class FormDataCollectorTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCollectMissingDataFromChildFormAddedOnFormEvents()
|
||||||
|
{
|
||||||
|
$form = $this->factory->createNamedBuilder('root', FormType::class, ['items' => null])
|
||||||
|
->add('items', CollectionType::class, [
|
||||||
|
'entry_type' => TextType::class,
|
||||||
|
'allow_add' => true,
|
||||||
|
// data is locked and modelData (null) is different to the
|
||||||
|
// configured data, so modifications of the configured data
|
||||||
|
// won't be allowed at this point. It also means *_SET_DATA
|
||||||
|
// events won't dispatched either. Therefore, no child form
|
||||||
|
// is created during the mapping of data to the form.
|
||||||
|
'data' => ['foo'],
|
||||||
|
])
|
||||||
|
->getForm()
|
||||||
|
;
|
||||||
|
$this->dataExtractor->expects($extractConfiguration = $this->exactly(4))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->willReturn([])
|
||||||
|
;
|
||||||
|
$this->dataExtractor->expects($extractDefaultData = $this->exactly(4))
|
||||||
|
->method('extractDefaultData')
|
||||||
|
->willReturnCallback(static function (FormInterface $form) {
|
||||||
|
// this simulate the call in extractDefaultData() method
|
||||||
|
// where (if defaultDataSet is false) it fires *_SET_DATA
|
||||||
|
// events, adding the form related to the configured data
|
||||||
|
$form->getNormData();
|
||||||
|
|
||||||
|
return [];
|
||||||
|
})
|
||||||
|
;
|
||||||
|
$this->dataExtractor->expects($this->exactly(4))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->willReturn([])
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->dataCollector->collectConfiguration($form);
|
||||||
|
$this->assertSame(2, $extractConfiguration->getInvocationCount(), 'only "root" and "items" forms were collected, the "items" children do not exist yet.');
|
||||||
|
|
||||||
|
$this->dataCollector->collectDefaultData($form);
|
||||||
|
$this->assertSame(3, $extractConfiguration->getInvocationCount(), 'extracted missing configuration of the "items" children ["0" => foo].');
|
||||||
|
$this->assertSame(3, $extractDefaultData->getInvocationCount());
|
||||||
|
$this->assertSame(['foo'], $form->get('items')->getData());
|
||||||
|
|
||||||
|
$form->submit(['items' => ['foo', 'bar']]);
|
||||||
|
$this->dataCollector->collectSubmittedData($form);
|
||||||
|
$this->assertSame(4, $extractConfiguration->getInvocationCount(), 'extracted missing configuration of the "items" children ["1" => bar].');
|
||||||
|
$this->assertSame(4, $extractDefaultData->getInvocationCount(), 'extracted missing default data of the "items" children ["1" => bar].');
|
||||||
|
$this->assertSame(['foo', 'bar'], $form->get('items')->getData());
|
||||||
|
}
|
||||||
|
|
||||||
private function createForm($name)
|
private function createForm($name)
|
||||||
{
|
{
|
||||||
$builder = new FormBuilder($name, null, $this->dispatcher, $this->factory);
|
$builder = new FormBuilder($name, null, $this->dispatcher, $this->factory);
|
||||||
|
@ -219,6 +219,8 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
|
|||||||
if ('POST' === $method) {
|
if ('POST' === $method) {
|
||||||
// Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303
|
// Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303
|
||||||
$curlopts[CURLOPT_POST] = true;
|
$curlopts[CURLOPT_POST] = true;
|
||||||
|
} elseif ('HEAD' === $method) {
|
||||||
|
$curlopts[CURLOPT_NOBODY] = true;
|
||||||
} else {
|
} else {
|
||||||
$curlopts[CURLOPT_CUSTOMREQUEST] = $method;
|
$curlopts[CURLOPT_CUSTOMREQUEST] = $method;
|
||||||
}
|
}
|
||||||
|
@ -356,6 +356,7 @@ final class CurlResponse implements ResponseInterface
|
|||||||
|
|
||||||
if (200 > $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE)) {
|
if (200 > $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE)) {
|
||||||
$multi->handlesActivity[$id][] = new InformationalChunk($statusCode, $headers);
|
$multi->handlesActivity[$id][] = new InformationalChunk($statusCode, $headers);
|
||||||
|
$location = null;
|
||||||
|
|
||||||
return \strlen($data);
|
return \strlen($data);
|
||||||
}
|
}
|
||||||
@ -379,9 +380,7 @@ final class CurlResponse implements ResponseInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$location = null;
|
if ($statusCode < 300 || 400 <= $statusCode || null === $location || curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
|
||||||
|
|
||||||
if ($statusCode < 300 || 400 <= $statusCode || curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
|
|
||||||
// Headers and redirects completed, time to get the response's body
|
// Headers and redirects completed, time to get the response's body
|
||||||
$multi->handlesActivity[$id][] = new FirstChunk();
|
$multi->handlesActivity[$id][] = new FirstChunk();
|
||||||
|
|
||||||
@ -405,6 +404,8 @@ final class CurlResponse implements ResponseInterface
|
|||||||
$logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url']));
|
$logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$location = null;
|
||||||
|
|
||||||
return \strlen($data);
|
return \strlen($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ class MockResponse implements ResponseInterface
|
|||||||
try {
|
try {
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
$chunk[1]->getStatusCode();
|
$chunk[1]->getStatusCode();
|
||||||
$response->headers = $chunk[1]->getHeaders(false);
|
$chunk[1]->getHeaders(false);
|
||||||
self::readResponse($response, $chunk[0], $chunk[1], $offset);
|
self::readResponse($response, $chunk[0], $chunk[1], $offset);
|
||||||
$multi->handlesActivity[$id][] = new FirstChunk();
|
$multi->handlesActivity[$id][] = new FirstChunk();
|
||||||
$buffer = $response->requestOptions['buffer'] ?? null;
|
$buffer = $response->requestOptions['buffer'] ?? null;
|
||||||
@ -269,7 +269,7 @@ class MockResponse implements ResponseInterface
|
|||||||
$info = $mock->getInfo() ?: [];
|
$info = $mock->getInfo() ?: [];
|
||||||
$response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode() ?: 200;
|
$response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode() ?: 200;
|
||||||
$response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers);
|
$response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers);
|
||||||
$dlSize = isset($response->headers['content-encoding']) ? 0 : (int) ($response->headers['content-length'][0] ?? 0);
|
$dlSize = isset($response->headers['content-encoding']) || 'HEAD' === $response->info['http_method'] || \in_array($response->info['http_code'], [204, 304], true) ? 0 : (int) ($response->headers['content-length'][0] ?? 0);
|
||||||
|
|
||||||
$response->info = [
|
$response->info = [
|
||||||
'start_time' => $response->info['start_time'],
|
'start_time' => $response->info['start_time'],
|
||||||
|
@ -195,8 +195,16 @@ final class NativeResponse implements ResponseInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, $this->content, $this->onProgress, &$this->remaining, &$this->info];
|
|
||||||
$this->multi->handlesActivity[$this->id] = [new FirstChunk()];
|
$this->multi->handlesActivity[$this->id] = [new FirstChunk()];
|
||||||
|
|
||||||
|
if ('HEAD' === $context['http']['method'] || \in_array($this->info['http_code'], [204, 304], true)) {
|
||||||
|
$this->multi->handlesActivity[$this->id][] = null;
|
||||||
|
$this->multi->handlesActivity[$this->id][] = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, $this->content, $this->onProgress, &$this->remaining, &$this->info];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -152,7 +152,7 @@ class UploadedFileTest extends TestCase
|
|||||||
UPLOAD_ERR_OK
|
UPLOAD_ERR_OK
|
||||||
);
|
);
|
||||||
|
|
||||||
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
|
$file->move(__DIR__.'/Fixtures/directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function failedUploadedFile()
|
public function failedUploadedFile()
|
||||||
|
@ -59,7 +59,7 @@ class HeaderBagTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('RuntimeException');
|
$this->expectException('RuntimeException');
|
||||||
$bag = new HeaderBag(['foo' => 'Tue']);
|
$bag = new HeaderBag(['foo' => 'Tue']);
|
||||||
$headerDate = $bag->getDate('foo');
|
$bag->getDate('foo');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetCacheControlHeader()
|
public function testGetCacheControlHeader()
|
||||||
|
@ -30,13 +30,13 @@ class RedirectResponseTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$this->expectExceptionMessage('Cannot redirect to an empty URL.');
|
$this->expectExceptionMessage('Cannot redirect to an empty URL.');
|
||||||
$response = new RedirectResponse('');
|
new RedirectResponse('');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRedirectResponseConstructorWrongStatusCode()
|
public function testRedirectResponseConstructorWrongStatusCode()
|
||||||
{
|
{
|
||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$response = new RedirectResponse('foo.bar', 404);
|
new RedirectResponse('foo.bar', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGenerateLocationHeader()
|
public function testGenerateLocationHeader()
|
||||||
|
@ -40,7 +40,7 @@ class NativeFileSessionHandlerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testConstructSavePath($savePath, $expectedSavePath, $path)
|
public function testConstructSavePath($savePath, $expectedSavePath, $path)
|
||||||
{
|
{
|
||||||
$handler = new NativeFileSessionHandler($savePath);
|
new NativeFileSessionHandler($savePath);
|
||||||
$this->assertEquals($expectedSavePath, ini_get('session.save_path'));
|
$this->assertEquals($expectedSavePath, ini_get('session.save_path'));
|
||||||
$this->assertDirectoryExists(realpath($path));
|
$this->assertDirectoryExists(realpath($path));
|
||||||
|
|
||||||
@ -61,13 +61,13 @@ class NativeFileSessionHandlerTest extends TestCase
|
|||||||
public function testConstructException()
|
public function testConstructException()
|
||||||
{
|
{
|
||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$handler = new NativeFileSessionHandler('something;invalid;with;too-many-args');
|
new NativeFileSessionHandler('something;invalid;with;too-many-args');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConstructDefault()
|
public function testConstructDefault()
|
||||||
{
|
{
|
||||||
$path = ini_get('session.save_path');
|
$path = ini_get('session.save_path');
|
||||||
$storage = new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler());
|
new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler());
|
||||||
|
|
||||||
$this->assertEquals($path, ini_get('session.save_path'));
|
$this->assertEquals($path, ini_get('session.save_path'));
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class NullSessionHandlerTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function testSaveHandlers()
|
public function testSaveHandlers()
|
||||||
{
|
{
|
||||||
$storage = $this->getStorage();
|
$this->getStorage();
|
||||||
$this->assertEquals('user', ini_get('session.save_handler'));
|
$this->assertEquals('user', ini_get('session.save_handler'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class PdoSessionHandlerTest extends TestCase
|
|||||||
$pdo = $this->getMemorySqlitePdo();
|
$pdo = $this->getMemorySqlitePdo();
|
||||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
|
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
|
||||||
|
|
||||||
$storage = new PdoSessionHandler($pdo);
|
new PdoSessionHandler($pdo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInexistentTable()
|
public function testInexistentTable()
|
||||||
|
@ -142,7 +142,7 @@ class NativeSessionStorageTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->iniSet('session.cache_limiter', 'nocache');
|
$this->iniSet('session.cache_limiter', 'nocache');
|
||||||
|
|
||||||
$storage = new NativeSessionStorage();
|
new NativeSessionStorage();
|
||||||
$this->assertEquals('', ini_get('session.cache_limiter'));
|
$this->assertEquals('', ini_get('session.cache_limiter'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ class NativeSessionStorageTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->iniSet('session.cache_limiter', 'nocache');
|
$this->iniSet('session.cache_limiter', 'nocache');
|
||||||
|
|
||||||
$storage = new NativeSessionStorage(['cache_limiter' => 'public']);
|
new NativeSessionStorage(['cache_limiter' => 'public']);
|
||||||
$this->assertEquals('public', ini_get('session.cache_limiter'));
|
$this->assertEquals('public', ini_get('session.cache_limiter'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = null;
|
|
||||||
try {
|
try {
|
||||||
$content = $request->getContent();
|
$content = $request->getContent();
|
||||||
} catch (\LogicException $e) {
|
} catch (\LogicException $e) {
|
||||||
@ -59,7 +58,6 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
|
|||||||
|
|
||||||
$sessionMetadata = [];
|
$sessionMetadata = [];
|
||||||
$sessionAttributes = [];
|
$sessionAttributes = [];
|
||||||
$session = null;
|
|
||||||
$flashes = [];
|
$flashes = [];
|
||||||
if ($request->hasSession()) {
|
if ($request->hasSession()) {
|
||||||
$session = $request->getSession();
|
$session = $request->getSession();
|
||||||
|
@ -130,7 +130,6 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
|
|||||||
$response->headers->set('Cache-Control', implode(', ', array_keys($flags)));
|
$response->headers->set('Cache-Control', implode(', ', array_keys($flags)));
|
||||||
|
|
||||||
$maxAge = null;
|
$maxAge = null;
|
||||||
$sMaxage = null;
|
|
||||||
|
|
||||||
if (is_numeric($this->ageDirectives['max-age'])) {
|
if (is_numeric($this->ageDirectives['max-age'])) {
|
||||||
$maxAge = $this->ageDirectives['max-age'] + $this->age;
|
$maxAge = $this->ageDirectives['max-age'] + $this->age;
|
||||||
|
@ -256,7 +256,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
|||||||
public function testControllersAreMadePublic()
|
public function testControllersAreMadePublic()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
$resolver = $container->register('argument_resolver.service')->addArgument([]);
|
$container->register('argument_resolver.service')->addArgument([]);
|
||||||
|
|
||||||
$container->register('foo', ArgumentWithoutTypeController::class)
|
$container->register('foo', ArgumentWithoutTypeController::class)
|
||||||
->setPublic(false)
|
->setPublic(false)
|
||||||
|
@ -52,7 +52,7 @@ class StoreTest extends TestCase
|
|||||||
|
|
||||||
public function testUnlockFileThatDoesExist()
|
public function testUnlockFileThatDoesExist()
|
||||||
{
|
{
|
||||||
$cacheKey = $this->storeSimpleEntry();
|
$this->storeSimpleEntry();
|
||||||
$this->store->lock($this->request);
|
$this->store->lock($this->request);
|
||||||
|
|
||||||
$this->assertTrue($this->store->unlock($this->request));
|
$this->assertTrue($this->store->unlock($this->request));
|
||||||
@ -92,7 +92,7 @@ class StoreTest extends TestCase
|
|||||||
{
|
{
|
||||||
$cacheKey = $this->storeSimpleEntry();
|
$cacheKey = $this->storeSimpleEntry();
|
||||||
$entries = $this->getStoreMetadata($cacheKey);
|
$entries = $this->getStoreMetadata($cacheKey);
|
||||||
list($req, $res) = $entries[0];
|
list(, $res) = $entries[0];
|
||||||
|
|
||||||
$this->assertEquals('en9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', $res['x-content-digest'][0]);
|
$this->assertEquals('en9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', $res['x-content-digest'][0]);
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ class StoreTest extends TestCase
|
|||||||
{
|
{
|
||||||
$req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);
|
$req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);
|
||||||
$res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']);
|
$res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']);
|
||||||
$key = $this->store->write($req1, $res1);
|
$this->store->write($req1, $res1);
|
||||||
$this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 1')), $this->store->lookup($req1)->getContent());
|
$this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 1')), $this->store->lookup($req1)->getContent());
|
||||||
|
|
||||||
$req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']);
|
$req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']);
|
||||||
@ -229,7 +229,7 @@ class StoreTest extends TestCase
|
|||||||
$req = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);
|
$req = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);
|
||||||
$this->assertTrue($this->store->lock($req));
|
$this->assertTrue($this->store->lock($req));
|
||||||
|
|
||||||
$path = $this->store->lock($req);
|
$this->store->lock($req);
|
||||||
$this->assertTrue($this->store->isLocked($req));
|
$this->assertTrue($this->store->isLocked($req));
|
||||||
|
|
||||||
$this->store->unlock($req);
|
$this->store->unlock($req);
|
||||||
|
@ -19,7 +19,7 @@ class RouteTest extends TestCase
|
|||||||
public function testInvalidRouteParameter()
|
public function testInvalidRouteParameter()
|
||||||
{
|
{
|
||||||
$this->expectException('BadMethodCallException');
|
$this->expectException('BadMethodCallException');
|
||||||
$route = new Route(['foo' => 'bar']);
|
new Route(['foo' => 'bar']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTryingToSetLocalesDirectly()
|
public function testTryingToSetLocalesDirectly()
|
||||||
|
@ -6,7 +6,7 @@ trait FooTrait
|
|||||||
{
|
{
|
||||||
public function doBar()
|
public function doBar()
|
||||||
{
|
{
|
||||||
$baz = self::class;
|
self::class;
|
||||||
if (true) {
|
if (true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ class CompiledUrlGeneratorDumperTest extends TestCase
|
|||||||
file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump());
|
file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump());
|
||||||
|
|
||||||
$projectUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext());
|
$projectUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext());
|
||||||
$url = $projectUrlGenerator->generate('NonExisting', []);
|
$projectUrlGenerator->generate('NonExisting', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDumpForRouteWithDefaults()
|
public function testDumpForRouteWithDefaults()
|
||||||
|
@ -247,7 +247,7 @@ class RouteCompilerTest extends TestCase
|
|||||||
$this->expectException('LogicException');
|
$this->expectException('LogicException');
|
||||||
$route = new Route('/{name}/{name}');
|
$route = new Route('/{name}/{name}');
|
||||||
|
|
||||||
$compiled = $route->compile();
|
$route->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRouteCharsetMismatch()
|
public function testRouteCharsetMismatch()
|
||||||
@ -255,7 +255,7 @@ class RouteCompilerTest extends TestCase
|
|||||||
$this->expectException('LogicException');
|
$this->expectException('LogicException');
|
||||||
$route = new Route("/\xE9/{bar}", [], ['bar' => '.'], ['utf8' => true]);
|
$route = new Route("/\xE9/{bar}", [], ['bar' => '.'], ['utf8' => true]);
|
||||||
|
|
||||||
$compiled = $route->compile();
|
$route->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRequirementCharsetMismatch()
|
public function testRequirementCharsetMismatch()
|
||||||
@ -263,7 +263,7 @@ class RouteCompilerTest extends TestCase
|
|||||||
$this->expectException('LogicException');
|
$this->expectException('LogicException');
|
||||||
$route = new Route('/foo/{bar}', [], ['bar' => "\xE9"], ['utf8' => true]);
|
$route = new Route('/foo/{bar}', [], ['bar' => "\xE9"], ['utf8' => true]);
|
||||||
|
|
||||||
$compiled = $route->compile();
|
$route->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRouteWithFragmentAsPathParameter()
|
public function testRouteWithFragmentAsPathParameter()
|
||||||
@ -271,7 +271,7 @@ class RouteCompilerTest extends TestCase
|
|||||||
$this->expectException('InvalidArgumentException');
|
$this->expectException('InvalidArgumentException');
|
||||||
$route = new Route('/{_fragment}');
|
$route = new Route('/{_fragment}');
|
||||||
|
|
||||||
$compiled = $route->compile();
|
$route->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +61,7 @@ CHANGELOG
|
|||||||
* Marked all dispatched event classes as `@final`
|
* Marked all dispatched event classes as `@final`
|
||||||
* Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`.
|
* Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`.
|
||||||
* Deprecated passing more than one attribute to `AccessDecisionManager::decide()` and `AuthorizationChecker::isGranted()`
|
* 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.)
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Security\Core\Encoder;
|
namespace Symfony\Component\Security\Core\Encoder;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic encoder factory implementation.
|
* A generic encoder factory implementation.
|
||||||
*
|
*
|
||||||
@ -114,6 +116,12 @@ class EncoderFactory implements EncoderFactoryInterface
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
case 'bcrypt':
|
||||||
|
$config['algorithm'] = 'native';
|
||||||
|
$config['native_algorithm'] = PASSWORD_BCRYPT;
|
||||||
|
|
||||||
|
return $this->getEncoderConfigFromAlgorithm($config);
|
||||||
|
|
||||||
case 'native':
|
case 'native':
|
||||||
return [
|
return [
|
||||||
'class' => NativePasswordEncoder::class,
|
'class' => NativePasswordEncoder::class,
|
||||||
@ -121,7 +129,7 @@ class EncoderFactory implements EncoderFactoryInterface
|
|||||||
$config['time_cost'] ?? null,
|
$config['time_cost'] ?? null,
|
||||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||||
$config['cost'] ?? null,
|
$config['cost'] ?? null,
|
||||||
],
|
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
case 'sodium':
|
case 'sodium':
|
||||||
@ -132,6 +140,30 @@ class EncoderFactory implements EncoderFactoryInterface
|
|||||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
case 'argon2i':
|
||||||
|
if (SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||||
|
$config['algorithm'] = 'sodium';
|
||||||
|
} elseif (\defined('PASSWORD_ARGON2I')) {
|
||||||
|
$config['algorithm'] = 'native';
|
||||||
|
$config['native_algorithm'] = PASSWORD_ARGON2I;
|
||||||
|
} else {
|
||||||
|
throw new LogicException(sprintf('Algorithm "argon2i" is not available. Either use %s"auto" or upgrade to PHP 7.2+ instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? '"argon2id", ' : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getEncoderConfigFromAlgorithm($config);
|
||||||
|
|
||||||
|
case 'argon2id':
|
||||||
|
if (($hasSodium = SodiumPasswordEncoder::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||||
|
$config['algorithm'] = 'sodium';
|
||||||
|
} elseif (\defined('PASSWORD_ARGON2ID')) {
|
||||||
|
$config['algorithm'] = 'native';
|
||||||
|
$config['native_algorithm'] = PASSWORD_ARGON2ID;
|
||||||
|
} else {
|
||||||
|
throw new LogicException(sprintf('Algorithm "argon2id" is not available. Either use %s"auto", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? '"argon2i", ' : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getEncoderConfigFromAlgorithm($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -22,7 +22,8 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
|
|||||||
{
|
{
|
||||||
private $algorithm;
|
private $algorithm;
|
||||||
private $encodeHashAsBase64;
|
private $encodeHashAsBase64;
|
||||||
private $iterations;
|
private $iterations = 1;
|
||||||
|
private $encodedLength = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $algorithm The digest algorithm to use
|
* @param string $algorithm The digest algorithm to use
|
||||||
@ -33,6 +34,13 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
|
|||||||
{
|
{
|
||||||
$this->algorithm = $algorithm;
|
$this->algorithm = $algorithm;
|
||||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->encodedLength = \strlen($this->encodePassword('', 'salt'));
|
||||||
|
} catch (\LogicException $e) {
|
||||||
|
// ignore algorithm not supported
|
||||||
|
}
|
||||||
|
|
||||||
$this->iterations = $iterations;
|
$this->iterations = $iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +73,10 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
|
|||||||
*/
|
*/
|
||||||
public function isPasswordValid(string $encoded, string $raw, ?string $salt)
|
public function isPasswordValid(string $encoded, string $raw, ?string $salt)
|
||||||
{
|
{
|
||||||
|
if (\strlen($encoded) !== $this->encodedLength || false !== strpos($encoded, '$')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,10 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
private $algo;
|
private $algo;
|
||||||
private $options;
|
private $options;
|
||||||
|
|
||||||
public function __construct(int $opsLimit = null, int $memLimit = null, int $cost = null)
|
/**
|
||||||
|
* @param string|null $algo An algorithm supported by password_hash() or null to use the stronger available algorithm
|
||||||
|
*/
|
||||||
|
public function __construct(int $opsLimit = null, int $memLimit = null, int $cost = null, string $algo = null)
|
||||||
{
|
{
|
||||||
$cost = $cost ?? 13;
|
$cost = $cost ?? 13;
|
||||||
$opsLimit = $opsLimit ?? max(4, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE : 4);
|
$opsLimit = $opsLimit ?? max(4, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE : 4);
|
||||||
@ -45,7 +48,7 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
|
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->algo = \defined('PASSWORD_ARGON2I') ? max(PASSWORD_DEFAULT, \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : PASSWORD_ARGON2I) : PASSWORD_DEFAULT;
|
$this->algo = (string) ($algo ?? \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : (\defined('PASSWORD_ARGON2I') ? PASSWORD_ARGON2I : PASSWORD_BCRYPT));
|
||||||
$this->options = [
|
$this->options = [
|
||||||
'cost' => $cost,
|
'cost' => $cost,
|
||||||
'time_cost' => $opsLimit,
|
'time_cost' => $opsLimit,
|
||||||
@ -59,20 +62,13 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
*/
|
*/
|
||||||
public function encodePassword(string $raw, ?string $salt): string
|
public function encodePassword(string $raw, ?string $salt): string
|
||||||
{
|
{
|
||||||
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
|
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || ((string) PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) {
|
||||||
throw new BadCredentialsException('Invalid password.');
|
throw new BadCredentialsException('Invalid password.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore $salt, the auto-generated one is always the best
|
// Ignore $salt, the auto-generated one is always the best
|
||||||
|
|
||||||
$encoded = password_hash($raw, $this->algo, $this->options);
|
return password_hash($raw, $this->algo, $this->options);
|
||||||
|
|
||||||
if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
|
|
||||||
// BCrypt encodes only the first 72 chars
|
|
||||||
throw new BadCredentialsException('Invalid password.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $encoded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,12 +76,24 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
*/
|
*/
|
||||||
public function isPasswordValid(string $encoded, string $raw, ?string $salt): bool
|
public function isPasswordValid(string $encoded, string $raw, ?string $salt): bool
|
||||||
{
|
{
|
||||||
if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
|
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
|
||||||
// BCrypt encodes only the first 72 chars
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return \strlen($raw) <= self::MAX_PASSWORD_LENGTH && password_verify($raw, $encoded);
|
if (0 === strpos($encoded, '$2')) {
|
||||||
|
// BCrypt encodes only the first 72 chars
|
||||||
|
return 72 >= \strlen($raw) && password_verify($raw, $encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\extension_loaded('sodium') && version_compare(\SODIUM_LIBRARY_VERSION, '1.0.14', '>=')) {
|
||||||
|
return sodium_crypto_pwhash_str_verify($encoded, $raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\extension_loaded('libsodium') && version_compare(phpversion('libsodium'), '1.0.14', '>=')) {
|
||||||
|
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return password_verify($raw, $encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,8 +30,9 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder
|
|||||||
{
|
{
|
||||||
private $algorithm;
|
private $algorithm;
|
||||||
private $encodeHashAsBase64;
|
private $encodeHashAsBase64;
|
||||||
private $iterations;
|
private $iterations = 1;
|
||||||
private $length;
|
private $length;
|
||||||
|
private $encodedLength = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $algorithm The digest algorithm to use
|
* @param string $algorithm The digest algorithm to use
|
||||||
@ -43,8 +44,15 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder
|
|||||||
{
|
{
|
||||||
$this->algorithm = $algorithm;
|
$this->algorithm = $algorithm;
|
||||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||||
$this->iterations = $iterations;
|
|
||||||
$this->length = $length;
|
$this->length = $length;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->encodedLength = \strlen($this->encodePassword('', 'salt'));
|
||||||
|
} catch (\LogicException $e) {
|
||||||
|
// ignore algorithm not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->iterations = $iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,6 +80,10 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder
|
|||||||
*/
|
*/
|
||||||
public function isPasswordValid(string $encoded, string $raw, ?string $salt)
|
public function isPasswordValid(string $encoded, string $raw, ?string $salt)
|
||||||
{
|
{
|
||||||
|
if (\strlen($encoded) !== $this->encodedLength || false !== strpos($encoded, '$')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ final class SodiumPasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
|
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,7 +117,7 @@ class EncoderFactoryTest extends TestCase
|
|||||||
|
|
||||||
$user = new EncAwareUser('user', 'pass');
|
$user = new EncAwareUser('user', 'pass');
|
||||||
$user->encoderName = 'invalid_encoder_name';
|
$user->encoderName = 'invalid_encoder_name';
|
||||||
$encoder = $factory->getEncoder($user);
|
$factory->getEncoder($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetEncoderForEncoderAwareWithClassName()
|
public function testGetEncoderForEncoderAwareWithClassName()
|
||||||
|
@ -55,6 +55,14 @@ class NativePasswordEncoderTest extends TestCase
|
|||||||
$this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null));
|
$this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testConfiguredAlgorithm()
|
||||||
|
{
|
||||||
|
$encoder = new NativePasswordEncoder(null, null, null, PASSWORD_BCRYPT);
|
||||||
|
$result = $encoder->encodePassword('password', null);
|
||||||
|
$this->assertTrue($encoder->isPasswordValid($result, 'password', null));
|
||||||
|
$this->assertStringStartsWith('$2', $result);
|
||||||
|
}
|
||||||
|
|
||||||
public function testCheckPasswordLength()
|
public function testCheckPasswordLength()
|
||||||
{
|
{
|
||||||
$encoder = new NativePasswordEncoder(null, null, 4);
|
$encoder = new NativePasswordEncoder(null, null, 4);
|
||||||
|
@ -131,7 +131,7 @@ class GuardAuthenticationProviderTest extends TestCase
|
|||||||
$token->setAuthenticated(false);
|
$token->setAuthenticated(false);
|
||||||
|
|
||||||
$provider = new GuardAuthenticationProvider([], $this->userProvider, $providerKey, $this->userChecker);
|
$provider = new GuardAuthenticationProvider([], $this->userProvider, $providerKey, $this->userChecker);
|
||||||
$actualToken = $provider->authenticate($token);
|
$provider->authenticate($token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSupportsChecksGuardAuthenticatorsTokenOrigin()
|
public function testSupportsChecksGuardAuthenticatorsTokenOrigin()
|
||||||
|
@ -21,7 +21,7 @@ class LogoutListenerTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function testHandleUnmatchedPath()
|
public function testHandleUnmatchedPath()
|
||||||
{
|
{
|
||||||
list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener();
|
list($listener, , $httpUtils, $options) = $this->getListener();
|
||||||
|
|
||||||
list($event, $request) = $this->getGetResponseEvent();
|
list($event, $request) = $this->getGetResponseEvent();
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class LogoutListenerTest extends TestCase
|
|||||||
$this->expectException('RuntimeException');
|
$this->expectException('RuntimeException');
|
||||||
$successHandler = $this->getSuccessHandler();
|
$successHandler = $this->getSuccessHandler();
|
||||||
|
|
||||||
list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener($successHandler);
|
list($listener, , $httpUtils, $options) = $this->getListener($successHandler);
|
||||||
|
|
||||||
list($event, $request) = $this->getGetResponseEvent();
|
list($event, $request) = $this->getGetResponseEvent();
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ class LogoutListenerTest extends TestCase
|
|||||||
$this->expectException('Symfony\Component\Security\Core\Exception\LogoutException');
|
$this->expectException('Symfony\Component\Security\Core\Exception\LogoutException');
|
||||||
$tokenManager = $this->getTokenManager();
|
$tokenManager = $this->getTokenManager();
|
||||||
|
|
||||||
list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener(null, $tokenManager);
|
list($listener, , $httpUtils, $options) = $this->getListener(null, $tokenManager);
|
||||||
|
|
||||||
list($event, $request) = $this->getGetResponseEvent();
|
list($event, $request) = $this->getGetResponseEvent();
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ class RememberMeListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testSessionStrategy()
|
public function testSessionStrategy()
|
||||||
{
|
{
|
||||||
list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, true);
|
list($listener, $tokenStorage, $service, $manager, , , $sessionStrategy) = $this->getListener(false, true, true);
|
||||||
|
|
||||||
$tokenStorage
|
$tokenStorage
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
@ -289,7 +289,7 @@ class RememberMeListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testSessionIsMigratedByDefault()
|
public function testSessionIsMigratedByDefault()
|
||||||
{
|
{
|
||||||
list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false);
|
list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, true, false);
|
||||||
|
|
||||||
$tokenStorage
|
$tokenStorage
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
|
@ -60,7 +60,7 @@ class RemoteUserAuthenticationListenerTest extends TestCase
|
|||||||
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
$result = $method->invokeArgs($listener, [$request]);
|
$method->invokeArgs($listener, [$request]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetPreAuthenticatedDataWithDifferentKeys()
|
public function testGetPreAuthenticatedDataWithDifferentKeys()
|
||||||
|
@ -98,7 +98,7 @@ class X509AuthenticationListenerTest extends TestCase
|
|||||||
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
$result = $method->invokeArgs($listener, [$request]);
|
$method->invokeArgs($listener, [$request]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetPreAuthenticatedDataWithDifferentKeys()
|
public function testGetPreAuthenticatedDataWithDifferentKeys()
|
||||||
|
@ -66,8 +66,6 @@ class ResponseListenerTest extends TestCase
|
|||||||
|
|
||||||
public function testItSubscribesToTheOnKernelResponseEvent()
|
public function testItSubscribesToTheOnKernelResponseEvent()
|
||||||
{
|
{
|
||||||
$listener = new ResponseListener();
|
|
||||||
|
|
||||||
$this->assertSame([KernelEvents::RESPONSE => 'onKernelResponse'], ResponseListener::getSubscribedEvents());
|
$this->assertSame([KernelEvents::RESPONSE => 'onKernelResponse'], ResponseListener::getSubscribedEvents());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ class FilesystemLoaderTest extends TestCase
|
|||||||
public function testConstructor()
|
public function testConstructor()
|
||||||
{
|
{
|
||||||
$pathPattern = self::$fixturesPath.'/templates/%name%.%engine%';
|
$pathPattern = self::$fixturesPath.'/templates/%name%.%engine%';
|
||||||
$path = self::$fixturesPath.'/templates';
|
|
||||||
$loader = new ProjectTemplateLoader2($pathPattern);
|
$loader = new ProjectTemplateLoader2($pathPattern);
|
||||||
$this->assertEquals([$pathPattern], $loader->getTemplatePathPatterns(), '__construct() takes a path as its second argument');
|
$this->assertEquals([$pathPattern], $loader->getTemplatePathPatterns(), '__construct() takes a path as its second argument');
|
||||||
$loader = new ProjectTemplateLoader2([$pathPattern]);
|
$loader = new ProjectTemplateLoader2([$pathPattern]);
|
||||||
|
@ -61,7 +61,7 @@ class FileValidator extends ConstraintValidator
|
|||||||
$binaryFormat = null === $constraint->binaryFormat ? true : $constraint->binaryFormat;
|
$binaryFormat = null === $constraint->binaryFormat ? true : $constraint->binaryFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($sizeAsString, $limitAsString, $suffix) = $this->factorizeSizes(0, $limitInBytes, $binaryFormat);
|
list(, $limitAsString, $suffix) = $this->factorizeSizes(0, $limitInBytes, $binaryFormat);
|
||||||
$this->context->buildViolation($constraint->uploadIniSizeErrorMessage)
|
$this->context->buildViolation($constraint->uploadIniSizeErrorMessage)
|
||||||
->setParameter('{{ limit }}', $limitAsString)
|
->setParameter('{{ limit }}', $limitAsString)
|
||||||
->setParameter('{{ suffix }}', $suffix)
|
->setParameter('{{ suffix }}', $suffix)
|
||||||
|
@ -456,7 +456,7 @@ abstract class FileValidatorTest extends ConstraintValidatorTestCase
|
|||||||
$reflection = new \ReflectionClass(\get_class(new FileValidator()));
|
$reflection = new \ReflectionClass(\get_class(new FileValidator()));
|
||||||
$method = $reflection->getMethod('factorizeSizes');
|
$method = $reflection->getMethod('factorizeSizes');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
list($sizeAsString, $limit, $suffix) = $method->invokeArgs(new FileValidator(), [0, UploadedFile::getMaxFilesize(), false]);
|
list(, $limit, $suffix) = $method->invokeArgs(new FileValidator(), [0, UploadedFile::getMaxFilesize(), false]);
|
||||||
|
|
||||||
// it correctly parses the maxSize option and not only uses simple string comparison
|
// it correctly parses the maxSize option and not only uses simple string comparison
|
||||||
// 1000M should be bigger than the ini value
|
// 1000M should be bigger than the ini value
|
||||||
|
@ -32,6 +32,7 @@ class PropertyPathTest extends TestCase
|
|||||||
['foo', 'bar', 'foo.bar', 'It append the subPath to the basePath'],
|
['foo', 'bar', 'foo.bar', 'It append the subPath to the basePath'],
|
||||||
['foo', '[bar]', 'foo[bar]', 'It does not include the dot separator if subPath uses the array notation'],
|
['foo', '[bar]', 'foo[bar]', 'It does not include the dot separator if subPath uses the array notation'],
|
||||||
['0', 'bar', '0.bar', 'Leading zeros are kept.'],
|
['0', 'bar', '0.bar', 'Leading zeros are kept.'],
|
||||||
|
['0', 1, '0.1', 'Numeric subpaths do not cause PHP 7.4 errors.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException('Symfony\Component\Workflow\Exception\LogicException');
|
$this->expectException('Symfony\Component\Workflow\Exception\LogicException');
|
||||||
$this->expectExceptionMessage('Place "d" cannot be the initial place as it does not exist.');
|
$this->expectExceptionMessage('Place "d" cannot be the initial place as it does not exist.');
|
||||||
$definition = new Definition([], [], 'd');
|
new Definition([], [], 'd');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddTransition()
|
public function testAddTransition()
|
||||||
|
@ -7,6 +7,13 @@ use Symfony\Component\Workflow\Transition;
|
|||||||
|
|
||||||
class TransitionTest extends TestCase
|
class TransitionTest extends TestCase
|
||||||
{
|
{
|
||||||
|
public function testValidateName()
|
||||||
|
{
|
||||||
|
$this->expectException('Symfony\Component\Workflow\Exception\InvalidArgumentException');
|
||||||
|
$this->expectExceptionMessage('The transition "foo.bar" contains invalid characters.');
|
||||||
|
new Transition('foo.bar', 'a', 'b');
|
||||||
|
}
|
||||||
|
|
||||||
public function testConstructor()
|
public function testConstructor()
|
||||||
{
|
{
|
||||||
$transition = new Transition('name', 'a', 'b');
|
$transition = new Transition('name', 'a', 'b');
|
||||||
|
@ -314,7 +314,7 @@ class WorkflowTest extends TestCase
|
|||||||
$this->assertFalse($marking->has('b'));
|
$this->assertFalse($marking->has('b'));
|
||||||
$this->assertFalse($marking->has('c'));
|
$this->assertFalse($marking->has('c'));
|
||||||
|
|
||||||
$marking = $workflow->apply($subject, 'a_to_bc');
|
$workflow->apply($subject, 'a_to_bc');
|
||||||
$marking = $workflow->apply($subject, 'b_to_c');
|
$marking = $workflow->apply($subject, 'b_to_c');
|
||||||
|
|
||||||
$this->assertFalse($marking->has('a'));
|
$this->assertFalse($marking->has('a'));
|
||||||
@ -406,7 +406,7 @@ class WorkflowTest extends TestCase
|
|||||||
'workflow.workflow_name.announce.t2',
|
'workflow.workflow_name.announce.t2',
|
||||||
];
|
];
|
||||||
|
|
||||||
$marking = $workflow->apply($subject, 't1');
|
$workflow->apply($subject, 't1');
|
||||||
|
|
||||||
$this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents);
|
$this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents);
|
||||||
}
|
}
|
||||||
@ -446,7 +446,7 @@ class WorkflowTest extends TestCase
|
|||||||
'workflow.workflow_name.announce',
|
'workflow.workflow_name.announce',
|
||||||
];
|
];
|
||||||
|
|
||||||
$marking = $workflow->apply($subject, 'a-b');
|
$workflow->apply($subject, 'a-b');
|
||||||
|
|
||||||
$this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents);
|
$this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents);
|
||||||
}
|
}
|
||||||
|
@ -108,14 +108,6 @@ class Parser
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public function getLastLineNumberBeforeDeprecation(): int
|
|
||||||
{
|
|
||||||
return $this->getRealCurrentLineNb();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function doParse(string $value, int $flags)
|
private function doParse(string $value, int $flags)
|
||||||
{
|
{
|
||||||
$this->currentLineNb = -1;
|
$this->currentLineNb = -1;
|
||||||
|
@ -97,7 +97,7 @@ YAML;
|
|||||||
$filename = $this->createFile('');
|
$filename = $this->createFile('');
|
||||||
unlink($filename);
|
unlink($filename);
|
||||||
|
|
||||||
$ret = $tester->execute(['filename' => $filename], ['decorated' => false]);
|
$tester->execute(['filename' => $filename], ['decorated' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createFile($content): string
|
private function createFile($content): string
|
||||||
|
@ -64,7 +64,7 @@ class ParserTest extends TestCase
|
|||||||
|
|
||||||
foreach ($yamls as $yaml) {
|
foreach ($yamls as $yaml) {
|
||||||
try {
|
try {
|
||||||
$content = $this->parser->parse($yaml);
|
$this->parser->parse($yaml);
|
||||||
|
|
||||||
$this->fail('YAML files must not contain tabs');
|
$this->fail('YAML files must not contain tabs');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
@ -82,6 +82,11 @@ switch ($vars['REQUEST_URI']) {
|
|||||||
header('Location: ..', true, 302);
|
header('Location: ..', true, 302);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '/304':
|
||||||
|
header('Content-Length: 10', true, 304);
|
||||||
|
echo '12345';
|
||||||
|
return;
|
||||||
|
|
||||||
case '/307':
|
case '/307':
|
||||||
header('Location: http://localhost:8057/post', true, 307);
|
header('Location: http://localhost:8057/post', true, 307);
|
||||||
break;
|
break;
|
||||||
|
@ -72,6 +72,33 @@ abstract class HttpClientTestCase extends TestCase
|
|||||||
$response->getContent();
|
$response->getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testHeadRequest()
|
||||||
|
{
|
||||||
|
$client = $this->getHttpClient(__FUNCTION__);
|
||||||
|
$response = $client->request('HEAD', 'http://localhost:8057', [
|
||||||
|
'headers' => ['Foo' => 'baR'],
|
||||||
|
'user_data' => $data = new \stdClass(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame([], $response->getInfo('response_headers'));
|
||||||
|
$this->assertSame($data, $response->getInfo()['user_data']);
|
||||||
|
$this->assertSame(200, $response->getStatusCode());
|
||||||
|
|
||||||
|
$info = $response->getInfo();
|
||||||
|
$this->assertNull($info['error']);
|
||||||
|
$this->assertSame(0, $info['redirect_count']);
|
||||||
|
$this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]);
|
||||||
|
$this->assertSame('Host: localhost:8057', $info['response_headers'][1]);
|
||||||
|
$this->assertSame('http://localhost:8057/', $info['url']);
|
||||||
|
|
||||||
|
$headers = $response->getHeaders();
|
||||||
|
|
||||||
|
$this->assertSame('localhost:8057', $headers['host'][0]);
|
||||||
|
$this->assertSame(['application/json'], $headers['content-type']);
|
||||||
|
|
||||||
|
$this->assertSame('', $response->getContent());
|
||||||
|
}
|
||||||
|
|
||||||
public function testNonBufferedGetRequest()
|
public function testNonBufferedGetRequest()
|
||||||
{
|
{
|
||||||
$client = $this->getHttpClient(__FUNCTION__);
|
$client = $this->getHttpClient(__FUNCTION__);
|
||||||
@ -297,6 +324,17 @@ abstract class HttpClientTestCase extends TestCase
|
|||||||
$response->getStatusCode();
|
$response->getStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test304()
|
||||||
|
{
|
||||||
|
$client = $this->getHttpClient(__FUNCTION__);
|
||||||
|
$response = $client->request('GET', 'http://localhost:8057/304', [
|
||||||
|
'headers' => ['If-Match' => '"abc"'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(304, $response->getStatusCode());
|
||||||
|
$this->assertSame('', $response->getContent(false));
|
||||||
|
}
|
||||||
|
|
||||||
public function testRedirects()
|
public function testRedirects()
|
||||||
{
|
{
|
||||||
$client = $this->getHttpClient(__FUNCTION__);
|
$client = $this->getHttpClient(__FUNCTION__);
|
||||||
|
Reference in New Issue
Block a user