[FrameworkBundle] allow configuring trusted proxies using semantic configuration

This commit is contained in:
Nicolas Grekas 2020-06-19 15:56:57 +02:00
parent 2c9e9cd0c2
commit af9dd52752
9 changed files with 72 additions and 12 deletions

View File

@ -5,6 +5,7 @@ CHANGELOG
-----
* Added `framework.http_cache` configuration tree
* Added `framework.trusted_proxies` and `framework.trusted_headers` configuration options
5.1.0
-----

View File

@ -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()

View File

@ -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',
@ -2098,6 +2104,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}
*/

View File

@ -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)

View File

@ -42,6 +42,9 @@
<xsd:attribute name="default-locale" type="xsd:string" />
<xsd:attribute name="test" type="xsd:boolean" />
<xsd:attribute name="error-controller" type="xsd:string" />
<xsd:attribute name="trusted_hosts" type="xsd:string" />
<xsd:attribute name="trusted_proxies" type="xsd:string" />
<xsd:attribute name="trusted_headers" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="form">

View File

@ -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([

View File

@ -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,
],

View File

@ -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
-----

View File

@ -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;
}
/**