Unverified Commit 2aa7c3a6 authored by larowlan's avatar larowlan

Issue #3030501 by alexpott, Gábor Hojtsy, Berdir: [Symfony 4]...

Issue #3030501 by alexpott, Gábor Hojtsy, Berdir: [Symfony 4] Drupal\Core\StackMiddleware\ReverseProxyMiddleware calls Symfony\Component\HttpFoundation\Request::setTrustedHeaderName() which does not exist
parent 60bd499c
......@@ -58,24 +58,35 @@ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch =
public static function setSettingsOnRequest(Request $request, Settings $settings) {
// Initialize proxy settings.
if ($settings->get('reverse_proxy', FALSE)) {
$ip_header = $settings->get('reverse_proxy_header', 'X_FORWARDED_FOR');
$request::setTrustedHeaderName($request::HEADER_X_FORWARDED_FOR, $ip_header);
$proto_header = $settings->get('reverse_proxy_proto_header', 'X_FORWARDED_PROTO');
$request::setTrustedHeaderName($request::HEADER_X_FORWARDED_PROTO, $proto_header);
$host_header = $settings->get('reverse_proxy_host_header', 'X_FORWARDED_HOST');
$request::setTrustedHeaderName($request::HEADER_X_FORWARDED_HOST, $host_header);
$port_header = $settings->get('reverse_proxy_port_header', 'X_FORWARDED_PORT');
$request::setTrustedHeaderName($request::HEADER_X_FORWARDED_PORT, $port_header);
$forwarded_header = $settings->get('reverse_proxy_forwarded_header', 'FORWARDED');
$request::setTrustedHeaderName($request::HEADER_FORWARDED, $forwarded_header);
$proxies = $settings->get('reverse_proxy_addresses', []);
if (count($proxies) > 0) {
$request::setTrustedProxies($proxies, Request::HEADER_X_FORWARDED_ALL | Request::HEADER_FORWARDED);
$deprecated_settings = [
'reverse_proxy_header' => Request::HEADER_X_FORWARDED_FOR,
'reverse_proxy_proto_header' => Request::HEADER_X_FORWARDED_PROTO,
'reverse_proxy_host_header' => Request::HEADER_X_FORWARDED_HOST,
'reverse_proxy_port_header' => Request::HEADER_X_FORWARDED_PORT,
'reverse_proxy_forwarded_header' => Request::HEADER_FORWARDED,
];
$all = $settings->getAll();
// Set the default value. This is the most relaxed setting possible and
// not recommended for production.
$trusted_header_set = Request::HEADER_X_FORWARDED_ALL | Request::HEADER_FORWARDED;
foreach ($deprecated_settings as $deprecated_setting => $bit_value) {
if (array_key_exists($deprecated_setting, $all)) {
@trigger_error(sprintf("The '%s' setting in settings.php is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use the 'reverse_proxy_trusted_headers' setting instead. See https://www.drupal.org/node/3030558", $deprecated_setting), E_USER_DEPRECATED);
$request::setTrustedHeaderName($bit_value, $all[$deprecated_setting]);
if ($all[$deprecated_setting] === NULL) {
// If the value is NULL do not trust the header.
$trusted_header_set &= ~$bit_value;
}
}
}
$request::setTrustedProxies(
$proxies,
$settings->get('reverse_proxy_trusted_headers', $trusted_header_set)
);
}
}
}
......
......@@ -4,6 +4,7 @@
use Drupal\Core\Site\Settings;
use Drupal\Core\StackMiddleware\ReverseProxyMiddleware;
use Drupal\Tests\Traits\ExpectDeprecationTrait;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
......@@ -13,6 +14,7 @@
* @group StackMiddleware
*/
class ReverseProxyMiddlewareTest extends UnitTestCase {
use ExpectDeprecationTrait;
/**
* @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit_Framework_MockObject_MockObject
......@@ -47,30 +49,83 @@ public function testNoProxy() {
* Tests that subscriber sets trusted headers when reverse proxy is set.
*
* @dataProvider reverseProxyEnabledProvider
*/
public function testReverseProxyEnabled($provided_settings, $expected_trusted_header_set) {
// Enable reverse proxy and add test values.
$settings = new Settings(['reverse_proxy' => 1] + $provided_settings);
$this->trustedHeadersAreSet($settings, $expected_trusted_header_set);
}
/**
* Data provider for testReverseProxyEnabled.
*/
public function reverseProxyEnabledProvider() {
return [
'Proxy with default trusted headers' => [
['reverse_proxy_addresses' => ['127.0.0.2', '127.0.0.3']],
Request::HEADER_FORWARDED | Request::HEADER_X_FORWARDED_ALL,
],
'Proxy with AWS trusted headers' => [
[
'reverse_proxy_addresses' => ['127.0.0.2', '127.0.0.3'],
'reverse_proxy_trusted_headers' => Request::HEADER_X_FORWARDED_AWS_ELB,
],
Request::HEADER_X_FORWARDED_AWS_ELB,
],
'Proxy with custom trusted headers' => [
[
'reverse_proxy_addresses' => ['127.0.0.2', '127.0.0.3'],
'reverse_proxy_trusted_headers' => Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST,
],
Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST,
],
];
}
/**
* Tests that subscriber sets trusted headers when reverse proxy is set.
*
* @dataProvider reverseProxyEnabledProviderLegacy
* @group legacy
*
* @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
*/
public function testReverseProxyEnabled($provided_settings) {
public function testReverseProxyEnabledLegacy($provided_settings, $expected_trusted_header_set, array $expected_deprecations) {
$this->expectedDeprecations($expected_deprecations);
// Enable reverse proxy and add test values.
$settings = new Settings(['reverse_proxy' => 1] + $provided_settings);
$this->trustedHeadersAreSet($settings);
$this->trustedHeadersAreSet($settings, $expected_trusted_header_set);
}
/**
* Data provider for testReverseProxyEnabled.
*/
public function reverseProxyEnabledProvider() {
public function reverseProxyEnabledProviderLegacy() {
return [
[
'Proxy with deprecated custom headers' => [
[
'reverse_proxy_header' => 'X_FORWARDED_FOR_CUSTOMIZED',
'reverse_proxy_proto_header' => 'X_FORWARDED_PROTO_CUSTOMIZED',
'reverse_proxy_host_header' => 'X_FORWARDED_HOST_CUSTOMIZED',
'reverse_proxy_port_header' => 'X_FORWARDED_PORT_CUSTOMIZED',
'reverse_proxy_forwarded_header' => 'FORWARDED_CUSTOMIZED',
'reverse_proxy_addresses' => ['127.0.0.2', '127.0.0.3'],
'reverse_proxy_host_header' => NULL,
'reverse_proxy_forwarded_header' => NULL,
],
// For AWS configuration forwarded and x_forwarded_host headers are not
// trusted.
Request::HEADER_X_FORWARDED_AWS_ELB,
[
'The \'reverse_proxy_host_header\' setting in settings.php is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use the \'reverse_proxy_trusted_headers\' setting instead. See https://www.drupal.org/node/3030558',
'The \'reverse_proxy_forwarded_header\' setting in settings.php is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use the \'reverse_proxy_trusted_headers\' setting instead. See https://www.drupal.org/node/3030558',
'The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.',
],
],
'Proxy with deprecated custom header' => [
[
'reverse_proxy_addresses' => ['127.0.0.2', '127.0.0.3'],
'reverse_proxy_forwarded_header' => NULL,
],
// The forwarded header is not trusted which is the same as trusting all
// the x_forwarded headers.
Request::HEADER_X_FORWARDED_ALL,
[
'The \'reverse_proxy_forwarded_header\' setting in settings.php is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use the \'reverse_proxy_trusted_headers\' setting instead. See https://www.drupal.org/node/3030558',
'The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.',
],
],
];
......@@ -85,18 +140,17 @@ public function reverseProxyEnabledProvider() {
*
* @param \Drupal\Core\Site\Settings $settings
* The settings object that holds reverse proxy configuration.
* @param int $expected_trusted_header_set
* The expected bit value returned by
* \Symfony\Component\HttpFoundation\Request::getTrustedHeaderSet()
*/
protected function trustedHeadersAreSet(Settings $settings) {
protected function trustedHeadersAreSet(Settings $settings, $expected_trusted_header_set) {
$middleware = new ReverseProxyMiddleware($this->mockHttpKernel, $settings);
$request = new Request();
$middleware->handle($request);
$this->assertSame($settings->get('reverse_proxy_header'), $request->getTrustedHeaderName($request::HEADER_X_FORWARDED_FOR));
$this->assertSame($settings->get('reverse_proxy_proto_header'), $request->getTrustedHeaderName($request::HEADER_X_FORWARDED_PROTO));
$this->assertSame($settings->get('reverse_proxy_host_header'), $request->getTrustedHeaderName($request::HEADER_X_FORWARDED_HOST));
$this->assertSame($settings->get('reverse_proxy_port_header'), $request->getTrustedHeaderName($request::HEADER_X_FORWARDED_PORT));
$this->assertSame($settings->get('reverse_proxy_forwarded_header'), $request->getTrustedHeaderName($request::HEADER_FORWARDED));
$this->assertSame($settings->get('reverse_proxy_addresses'), $request->getTrustedProxies());
$this->assertSame($expected_trusted_header_set, $request->getTrustedHeaderSet());
}
}
......@@ -342,11 +342,10 @@
* configuration requires the IP addresses of all remote proxies to be
* specified in $settings['reverse_proxy_addresses'] to work correctly.
*
* Enable this setting to get Drupal to determine the client IP from
* the X-Forwarded-For header (or $settings['reverse_proxy_header'] if set).
* If you are unsure about this setting, do not have a reverse proxy,
* or Drupal operates in a shared hosting environment, this setting
* should remain commented out.
* Enable this setting to get Drupal to determine the client IP from the
* X-Forwarded-For header. If you are unsure about this setting, do not have a
* reverse proxy, or Drupal operates in a shared hosting environment, this
* setting should remain commented out.
*
* In order for this setting to be used you must specify every possible
* reverse proxy IP address in $settings['reverse_proxy_addresses'].
......@@ -365,34 +364,35 @@
# $settings['reverse_proxy_addresses'] = ['a.b.c.d', ...];
/**
* Set this value if your proxy server sends the client IP in a header
* other than X-Forwarded-For.
*/
# $settings['reverse_proxy_header'] = 'X_CLUSTER_CLIENT_IP';
/**
* Set this value if your proxy server sends the client protocol in a header
* other than X-Forwarded-Proto.
*/
# $settings['reverse_proxy_proto_header'] = 'X_FORWARDED_PROTO';
/**
* Set this value if your proxy server sends the client protocol in a header
* other than X-Forwarded-Host.
*/
# $settings['reverse_proxy_host_header'] = 'X_FORWARDED_HOST';
/**
* Set this value if your proxy server sends the client protocol in a header
* other than X-Forwarded-Port.
* Reverse proxy trusted headers.
*
* Sets which headers to trust from your reverse proxy.
*
* Common values are:
* - \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL
* - \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED
*
* Note the default value of
* @code
* \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL | \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED
* @endcode
* is not secure by default. The value should be set to only the specific
* headers the reverse proxy uses. For example:
* @code
* \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL
* @endcode
* This would trust the following headers:
* - X_FORWARDED_FOR
* - X_FORWARDED_HOST
* - X_FORWARDED_PROTO
* - X_FORWARDED_PORT
*
* @see \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL
* @see \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED
* @see \Symfony\Component\HttpFoundation\Request::setTrustedProxies
*/
# $settings['reverse_proxy_port_header'] = 'X_FORWARDED_PORT';
# $settings['reverse_proxy_trusted_headers'] = \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL | \Symfony\Component\HttpFoundation\Request::HEADER_FORWARDED;
/**
* Set this value if your proxy server sends the client protocol in a header
* other than Forwarded.
*/
# $settings['reverse_proxy_forwarded_header'] = 'FORWARDED';
/**
* Page caching:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment