diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index a66937add4..214209bedc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -5,6 +5,7 @@ CHANGELOG
-----
* Added `framework.http_cache` configuration tree
+ * Added `framework.trusted_proxies` and `framework.trusted_headers` configuration options
5.1.0
-----
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index f644a57075..3711701565 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -85,6 +85,20 @@ class Configuration implements ConfigurationInterface
->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end()
->prototype('scalar')->end()
->end()
+ ->scalarNode('trusted_proxies')->end()
+ ->arrayNode('trusted_headers')
+ ->fixXmlConfig('trusted_header')
+ ->performNoDeepMerging()
+ ->defaultValue(['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'])
+ ->beforeNormalization()->ifString()->then(function ($v) { return $v ? array_map('trim', explode(',', $v)) : []; })->end()
+ ->enumPrototype()
+ ->values([
+ 'forwarded',
+ 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port',
+ 'x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix',
+ ])
+ ->end()
+ ->end()
->scalarNode('error_controller')
->defaultValue('error_controller')
->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 38825befe4..f942548ff8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -65,6 +65,7 @@ use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\Form\FormTypeGuesserInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpClient\ScopingHttpClient;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@@ -242,6 +243,11 @@ class FrameworkExtension extends Extension
$container->setParameter('kernel.default_locale', $config['default_locale']);
$container->setParameter('kernel.error_controller', $config['error_controller']);
+ if (($config['trusted_proxies'] ?? false) && ($config['trusted_headers'] ?? false)) {
+ $container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
+ $container->setParameter('kernel.trusted_headers', $this->resolveTrustedHeaders($config['trusted_headers']));
+ }
+
if (!$container->hasParameter('debug.file_link_format')) {
$links = [
'textmate' => 'txmt://open?url=file://%%f&line=%%l',
@@ -2094,6 +2100,30 @@ class FrameworkExtension extends Extension
}
}
+ private function resolveTrustedHeaders(array $headers): int
+ {
+ $trustedHeaders = 0;
+
+ foreach ($headers as $h) {
+ switch ($h) {
+ case 'forwarded': $trustedHeaders |= Request::HEADER_FORWARDED; break;
+ case 'x-forwarded-for': $trustedHeaders |= Request::HEADER_X_FORWARDED_FOR; break;
+ case 'x-forwarded-host': $trustedHeaders |= Request::HEADER_X_FORWARDED_HOST; break;
+ case 'x-forwarded-proto': $trustedHeaders |= Request::HEADER_X_FORWARDED_PROTO; break;
+ case 'x-forwarded-port': $trustedHeaders |= Request::HEADER_X_FORWARDED_PORT; break;
+ case '!x-forwarded-host': $trustedHeaders &= ~Request::HEADER_X_FORWARDED_HOST; break;
+ case 'x-forwarded-all':
+ if (!\in_array('!x-forwarded-prefix', $headers)) {
+ throw new LogicException('When using "x-forwarded-all" in "framework.trusted_headers", "!x-forwarded-prefix" must be explicitly listed until support for X-Forwarded-Prefix is implemented.');
+ }
+ $trustedHeaders |= Request::HEADER_X_FORWARDED_ALL;
+ break;
+ }
+ }
+
+ return $trustedHeaders;
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index 1244db0347..7f439bb572 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -95,10 +95,6 @@ class FrameworkBundle extends Bundle
if ($this->container->getParameter('kernel.http_method_override')) {
Request::enableHttpMethodParameterOverride();
}
-
- if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
- Request::setTrustedHosts($trustedHosts);
- }
}
public function build(ContainerBuilder $container)
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index 21ddccf342..7cc318a92a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -42,6 +42,9 @@
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php
index 071572b33f..f0cd2b9350 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php
@@ -132,9 +132,9 @@ return static function (ContainerConfigurator $container) {
->tag('container.hot_path')
->set('http_cache.store', Store::class)
- ->args([
- param('kernel.cache_dir').'/http_cache',
- ])
+ ->args([
+ param('kernel.cache_dir').'/http_cache',
+ ])
->set('url_helper', UrlHelper::class)
->args([
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
index 523d8919c3..7e1ed5f731 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -30,10 +30,7 @@ class ConfigurationTest extends TestCase
$processor = new Processor();
$config = $processor->processConfiguration(new Configuration(true), [['secret' => 's3cr3t']]);
- $this->assertEquals(
- array_merge(['secret' => 's3cr3t', 'trusted_hosts' => []], self::getBundleDefaultConfig()),
- $config
- );
+ $this->assertEquals(self::getBundleDefaultConfig(), $config);
}
public function getTestValidSessionName()
@@ -341,6 +338,13 @@ class ConfigurationTest extends TestCase
'http_method_override' => true,
'ide' => null,
'default_locale' => 'en',
+ 'secret' => 's3cr3t',
+ 'trusted_hosts' => [],
+ 'trusted_headers' => [
+ 'x-forwarded-all',
+ '!x-forwarded-host',
+ '!x-forwarded-prefix',
+ ],
'csrf_protection' => [
'enabled' => false,
],
diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md
index 6bf20c948f..19f8d9f3bd 100644
--- a/src/Symfony/Component/HttpKernel/CHANGELOG.md
+++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md
@@ -5,6 +5,8 @@ CHANGELOG
-----
* made the public `http_cache` service handle requests when available
+ * allowed enabling trusted hosts and proxies using new `kernel.trusted_hosts`,
+ `kernel.trusted_proxies` and `kernel.trusted_headers` parameters
5.1.0
-----
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index cf4329fc16..8f7ff96808 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -764,7 +764,17 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
$this->initializeBundles();
$this->initializeContainer();
- return $this->container;
+ $container = $this->container;
+
+ if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts = $container->getParameter('kernel.trusted_hosts')) {
+ Request::setTrustedHosts($trustedHosts);
+ }
+
+ if ($container->hasParameter('kernel.trusted_proxies') && $container->hasParameter('kernel.trusted_headers') && $trustedProxies = $container->getParameter('kernel.trusted_proxies')) {
+ Request::setTrustedProxies(\is_array($trustedProxies) ? $trustedProxies : array_map('trim', explode(',', $trustedProxies)), $container->getParameter('kernel.trusted_headers'));
+ }
+
+ return $container;
}
/**