Merge branch '4.4' into 5.2

* 4.4:
  [Console] minor fix
  [Validator] Avoid triggering the autoloader for user-input values
  Hardening Security - Unserialize DumpDataCollector
  [HttpClient] remove using $http_response_header
  [Security] Handle properly 'auto' option for remember me cookie security
This commit is contained in:
Nicolas Grekas 2021-03-23 13:45:44 +01:00
commit 88d222d856
8 changed files with 87 additions and 6 deletions

View File

@ -108,7 +108,7 @@ class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactor
$container
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remember_me'))
->replaceArgument(0, new Reference($rememberMeServicesId))
->replaceArgument(3, array_intersect_key($config, $this->options))
->replaceArgument(3, $container->getDefinition($rememberMeServicesId)->getArgument(3))
;
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
@ -201,7 +201,12 @@ class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactor
}
// remember-me options
$rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
$mergedOptions = array_intersect_key($config, $this->options);
if ('auto' === $mergedOptions['secure']) {
$mergedOptions['secure'] = null;
}
$rememberMeServices->replaceArgument(3, $mergedOptions);
if ($config['user_providers']) {
$userProviders = [];

View File

@ -0,0 +1,33 @@
<?php
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class RememberMeCookieTest extends AbstractWebTestCase
{
/** @dataProvider getSessionRememberMeSecureCookieFlagAutoHttpsMap */
public function testSessionRememberMeSecureCookieFlagAuto($https, $expectedSecureFlag)
{
$client = $this->createClient(['test_case' => 'RememberMeCookie', 'root_config' => 'config.yml']);
$client->request('POST', '/login', [
'_username' => 'test',
'_password' => 'test',
], [], [
'HTTPS' => (int) $https,
]);
$cookies = $client->getResponse()->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertEquals($expectedSecureFlag, $cookies['']['/']['REMEMBERME']->isSecure());
}
public function getSessionRememberMeSecureCookieFlagAutoHttpsMap()
{
return [
[true, true],
[false, false],
];
}
}

View File

@ -0,0 +1,9 @@
<?php
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
return [
new FrameworkBundle(),
new SecurityBundle(),
];

View File

@ -0,0 +1,25 @@
imports:
- { resource: ./../config/framework.yml }
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
in_memory:
memory:
users:
test: { password: test, roles: [ROLE_USER] }
firewalls:
default:
form_login:
check_path: login
remember_me: true
require_previous_session: false
remember_me:
always_remember_me: true
secret: key
secure: auto
logout: ~
anonymous: ~

View File

@ -0,0 +1,2 @@
login:
path: /login

View File

@ -149,7 +149,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface
// Send request and follow redirects when needed
$this->handle = $h = fopen($url, 'r', false, $this->context);
self::addResponseHeaders($http_response_header, $this->info, $this->headers, $this->info['debug']);
self::addResponseHeaders(stream_get_meta_data($h)['wrapper_data'], $this->info, $this->headers, $this->info['debug']);
$url = $resolver($this->multi, $this->headers['location'][0] ?? null, $this->context);
if (null === $url) {

View File

@ -178,6 +178,11 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$charset = array_pop($this->data);
$fileLinkFormat = array_pop($this->data);
$this->dataCount = \count($this->data);
foreach ($this->data as $dump) {
if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) {
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
}
self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null);
}
@ -252,7 +257,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
}
}
private function doDump(DataDumperInterface $dumper, $data, string $name, string $file, int $line)
private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line)
{
if ($dumper instanceof CliDumper) {
$contextDumper = function ($name, $file, $line, $fmt) {

View File

@ -649,8 +649,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
return;
}
// If the value is a scalar, pass it anyway, because we want
// a NoSuchMetadataException to be thrown in that case
if (!\is_object($value)) {
throw new NoSuchMetadataException(sprintf('Cannot create metadata for non-objects. Got: "%s".', \gettype($value)));
}
$this->validateObject(
$value,
$propertyPath,