Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 085d8fe

Browse files
committed
bug #23067 [HttpFoundation][FrameworkBundle] Revert "trusted proxies" BC break (nicolas-grekas)
This PR was merged into the 3.3 branch. Discussion ---------- [HttpFoundation][FrameworkBundle] Revert "trusted proxies" BC break | Q | A | ------------- | --- | Branch? | 3.3 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Basically reverts #22238 + cleanups some comments + adds missing syncing logic in setTrustedHeaderName. The reason for this proposal is that the BC break can go un-noticed until prod, *even if you have proper CI*. That's because your CI may not replicate exactly what your prod have (ie a reverse proxy), so that maybe only prod has a trusted-proxies configuration. I realized this while thinking about #23049: it made this situation even more likely, by removing an opportunity for you to notice the break before prod. The reasons for the BC break are still valid and all of this is security-related. But the core security issue is already fixed. The remaining issue still exists (an heisenbug related to some people having both Forwarded and X-Forwarded-* set for some reason), but deprecating might still be enough. WDYT? (I'm sure everyone is going to be happy with the BC break reversal, but I'm asking for feedback from people who actually could take the time to *understand* and *balance* the rationales here, thanks :) ) Commits ------- 2132333 [HttpFoundation][FrameworkBundle] Revert "trusted proxies" BC break
2 parents 58f03a7 + 2132333 commit 085d8fe

File tree

7 files changed

+123
-24
lines changed

7 files changed

+123
-24
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ CHANGELOG
77
* Not defining the `type` option of the `framework.workflows.*` configuration entries is deprecated.
88
The default value will be `state_machine` in Symfony 4.0.
99
* Deprecated the `CompilerDebugDumpPass` class
10-
* [BC BREAK] Removed the "framework.trusted_proxies" configuration option and the corresponding "kernel.trusted_proxies" parameter
10+
* Deprecated the "framework.trusted_proxies" configuration option and the corresponding "kernel.trusted_proxies" parameter
1111
* Added a new new version strategy option called json_manifest_path
1212
that allows you to use the `JsonManifestVersionStrategy`.
1313
* Added `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`. It provides

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,38 @@ public function getConfigTreeBuilder()
6565
->info("Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. Note: When using the HttpCache, you need to call the method in your front controller instead")
6666
->defaultTrue()
6767
->end()
68-
->arrayNode('trusted_proxies') // @deprecated in version 3.3, to be removed in 4.0
68+
->arrayNode('trusted_proxies')
6969
->beforeNormalization()
70-
->ifTrue(function ($v) { return empty($v); })
71-
->then(function () { @trigger_error('The "framework.trusted_proxies" configuration key has been removed in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.', E_USER_DEPRECATED); })
70+
->ifTrue(function ($v) {
71+
@trigger_error('The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.', E_USER_DEPRECATED);
72+
73+
return !is_array($v) && null !== $v;
74+
})
75+
->then(function ($v) { return is_bool($v) ? array() : preg_split('/\s*,\s*/', $v); })
7276
->end()
73-
->beforeNormalization()
74-
->ifTrue(function ($v) { return !empty($v); })
75-
->thenInvalid('The "framework.trusted_proxies" configuration key has been removed in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.')
77+
->prototype('scalar')
78+
->validate()
79+
->ifTrue(function ($v) {
80+
if (empty($v)) {
81+
return false;
82+
}
83+
84+
if (false !== strpos($v, '/')) {
85+
if ('0.0.0.0/0' === $v) {
86+
return false;
87+
}
88+
89+
list($v, $mask) = explode('/', $v, 2);
90+
91+
if (strcmp($mask, (int) $mask) || $mask < 1 || $mask > (false !== strpos($v, ':') ? 128 : 32)) {
92+
return true;
93+
}
94+
}
95+
96+
return !filter_var($v, FILTER_VALIDATE_IP);
97+
})
98+
->thenInvalid('Invalid proxy IP "%s"')
99+
->end()
76100
->end()
77101
->end()
78102
->scalarNode('ide')->defaultNull()->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ public function load(array $configs, ContainerBuilder $container)
146146

147147
$container->setParameter('kernel.http_method_override', $config['http_method_override']);
148148
$container->setParameter('kernel.trusted_hosts', $config['trusted_hosts']);
149+
if ($config['trusted_proxies']) {
150+
$container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
151+
}
149152
$container->setParameter('kernel.default_locale', $config['default_locale']);
150153

151154
if (!$container->hasParameter('debug.file_link_format')) {

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function testDoNoDuplicateDefaultFormResources()
4545

4646
/**
4747
* @group legacy
48-
* @expectedDeprecation The "framework.trusted_proxies" configuration key has been removed in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
48+
* @expectedDeprecation The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
4949
*/
5050
public function testTrustedProxiesSetToNullIsDeprecated()
5151
{
@@ -56,7 +56,7 @@ public function testTrustedProxiesSetToNullIsDeprecated()
5656

5757
/**
5858
* @group legacy
59-
* @expectedDeprecation The "framework.trusted_proxies" configuration key has been removed in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
59+
* @expectedDeprecation The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
6060
*/
6161
public function testTrustedProxiesSetToEmptyArrayIsDeprecated()
6262
{
@@ -66,7 +66,8 @@ public function testTrustedProxiesSetToEmptyArrayIsDeprecated()
6666
}
6767

6868
/**
69-
* @expectedException \InvalidArgumentException
69+
* @group legacy
70+
* @expectedDeprecation The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
7071
*/
7172
public function testTrustedProxiesSetToNonEmptyArrayIsInvalid()
7273
{
@@ -75,6 +76,70 @@ public function testTrustedProxiesSetToNonEmptyArrayIsInvalid()
7576
$processor->processConfiguration($configuration, array(array('trusted_proxies' => array('127.0.0.1'))));
7677
}
7778

79+
/**
80+
* @group legacy
81+
* @dataProvider getTestValidTrustedProxiesData
82+
*/
83+
public function testValidTrustedProxies($trustedProxies, $processedProxies)
84+
{
85+
$processor = new Processor();
86+
$configuration = new Configuration(true);
87+
$config = $processor->processConfiguration($configuration, array(array(
88+
'secret' => 's3cr3t',
89+
'trusted_proxies' => $trustedProxies,
90+
)));
91+
92+
$this->assertEquals($processedProxies, $config['trusted_proxies']);
93+
}
94+
95+
public function getTestValidTrustedProxiesData()
96+
{
97+
return array(
98+
array(array('127.0.0.1'), array('127.0.0.1')),
99+
array(array('::1'), array('::1')),
100+
array(array('127.0.0.1', '::1'), array('127.0.0.1', '::1')),
101+
array(null, array()),
102+
array(false, array()),
103+
array(array(), array()),
104+
array(array('10.0.0.0/8'), array('10.0.0.0/8')),
105+
array(array('::ffff:0:0/96'), array('::ffff:0:0/96')),
106+
array(array('0.0.0.0/0'), array('0.0.0.0/0')),
107+
);
108+
}
109+
110+
/**
111+
* @group legacy
112+
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
113+
*/
114+
public function testInvalidTypeTrustedProxies()
115+
{
116+
$processor = new Processor();
117+
$configuration = new Configuration(true);
118+
$processor->processConfiguration($configuration, array(
119+
array(
120+
'secret' => 's3cr3t',
121+
'trusted_proxies' => 'Not an IP address',
122+
),
123+
));
124+
}
125+
126+
/**
127+
* @group legacy
128+
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
129+
*/
130+
public function testInvalidValueTrustedProxies()
131+
{
132+
$processor = new Processor();
133+
$configuration = new Configuration(true);
134+
135+
$processor->processConfiguration($configuration, array(
136+
array(
137+
'secret' => 's3cr3t',
138+
'trusted_proxies' => array('Not an IP address'),
139+
),
140+
));
141+
}
142+
78143
public function testAssetsCanBeEnabled()
79144
{
80145
$processor = new Processor();
@@ -156,6 +221,7 @@ protected static function getBundleDefaultConfig()
156221
{
157222
return array(
158223
'http_method_override' => true,
224+
'trusted_proxies' => array(),
159225
'ide' => null,
160226
'default_locale' => 'en',
161227
'csrf_protection' => array(

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CHANGELOG
44
3.3.0
55
-----
66

7-
* [BC BREAK] the `Request::setTrustedProxies()` method takes a new `$trustedHeaderSet` argument,
7+
* the `Request::setTrustedProxies()` method takes a new `$trustedHeaderSet` argument,
88
see http://symfony.com/doc/current/components/http_foundation/trusting_proxies.html for more info,
99
* deprecated the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` methods,
1010
* added `File\Stream`, to be passed to `BinaryFileResponse` when the size of the served file is unknown,

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ public function overrideGlobals()
581581
* You should only list the reverse proxies that you manage directly.
582582
*
583583
* @param array $proxies A list of trusted proxies
584-
* @param int $trustedHeaderSet A bit field of Request::HEADER_*, usually either Request::HEADER_FORWARDED or Request::HEADER_X_FORWARDED_ALL, to set which headers to trust from your proxies
584+
* @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies
585585
*
586586
* @throws \InvalidArgumentException When $trustedHeaderSet is invalid
587587
*/
@@ -590,10 +590,11 @@ public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet
590590
self::$trustedProxies = $proxies;
591591

592592
if (2 > func_num_args()) {
593-
// @deprecated code path in 3.3, to be replaced by mandatory argument in 4.0.
594-
throw new \InvalidArgumentException(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument. Defining it is required since version 3.3. See http://symfony.com/doc/current/components/http_foundation/trusting_proxies.html for more info.', __METHOD__));
593+
@trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since version 3.3. Defining it will be required in 4.0. ', __METHOD__), E_USER_DEPRECATED);
594+
595+
return;
595596
}
596-
$trustedHeaderSet = func_get_arg(1);
597+
$trustedHeaderSet = (int) func_get_arg(1);
597598

598599
foreach (self::$trustedHeaderNames as $header => $name) {
599600
self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null;
@@ -665,11 +666,11 @@ public static function getTrustedHosts()
665666
*
666667
* @throws \InvalidArgumentException
667668
*
668-
* @deprecated since version 3.3, to be removed in 4.0. Use "X-Forwarded-*" headers or the "Forwarded" header defined in RFC7239, and the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
669+
* @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
669670
*/
670671
public static function setTrustedHeaderName($key, $value)
671672
{
672-
@trigger_error(sprintf('The "%s()" method is deprecated since version 3.3 and will be removed in 4.0. Use "X-Forwarded-*" headers or the "Forwarded" header defined in RFC7239, and the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED);
673+
@trigger_error(sprintf('The "%s()" method is deprecated since version 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED);
673674

674675
if (!array_key_exists($key, self::$trustedHeaders)) {
675676
throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
@@ -679,6 +680,9 @@ public static function setTrustedHeaderName($key, $value)
679680

680681
if (null !== $value) {
681682
self::$trustedHeaderNames[$key] = $value;
683+
self::$trustedHeaderSet |= $key;
684+
} else {
685+
self::$trustedHeaderSet &= ~$key;
682686
}
683687
}
684688

@@ -886,8 +890,8 @@ public function getClientIps()
886890
* adding the IP address where it received the request from.
887891
*
888892
* If your reverse proxy uses a different header name than "X-Forwarded-For",
889-
* ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with
890-
* the "client-ip" key.
893+
* ("Client-Ip" for instance), configure it via the $trustedHeaderSet
894+
* argument of the Request::setTrustedProxies() method instead.
891895
*
892896
* @return string|null The client IP address
893897
*
@@ -993,7 +997,8 @@ public function getScheme()
993997
* The "X-Forwarded-Port" header must contain the client port.
994998
*
995999
* If your reverse proxy uses a different header name than "X-Forwarded-Port",
996-
* configure it via "setTrustedHeaderName()" with the "client-port" key.
1000+
* configure it via via the $trustedHeaderSet argument of the
1001+
* Request::setTrustedProxies() method instead.
9971002
*
9981003
* @return int|string can be a string if fetched from the server bag
9991004
*/
@@ -1210,8 +1215,8 @@ public function getQueryString()
12101215
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
12111216
*
12121217
* If your reverse proxy uses a different header name than "X-Forwarded-Proto"
1213-
* ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
1214-
* the "client-proto" key.
1218+
* ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet
1219+
* argument of the Request::setTrustedProxies() method instead.
12151220
*
12161221
* @return bool
12171222
*/
@@ -1235,7 +1240,8 @@ public function isSecure()
12351240
* The "X-Forwarded-Host" header must contain the client host name.
12361241
*
12371242
* If your reverse proxy uses a different header name than "X-Forwarded-Host",
1238-
* configure it via "setTrustedHeaderName()" with the "client-host" key.
1243+
* configure it via the $trustedHeaderSet argument of the
1244+
* Request::setTrustedProxies() method instead.
12391245
*
12401246
* @return string
12411247
*

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1729,7 +1729,7 @@ public function testTrustedProxiesXForwardedFor()
17291729

17301730
/**
17311731
* @group legacy
1732-
* @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since version 3.3 and will be removed in 4.0. Use "X-Forwarded-*" headers or the "Forwarded" header defined in RFC7239, and the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
1732+
* @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since version 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
17331733
*/
17341734
public function testLegacyTrustedProxies()
17351735
{

0 commit comments

Comments
 (0)