From 2d00d18e6cb25c228eef410ed06062b812b6cb3a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 8 Jan 2023 09:54:19 +0100 Subject: [PATCH] Rename 'request_uri_field' to 'request_path' and allow a path in it (#8738, #8770) --- CHANGELOG.md | 2 +- config/defaults.inc.php | 9 +++++--- program/include/rcmail.php | 47 +++++++++++++++++++++++--------------- tests/Rcmail/Rcmail.php | 14 ++++++++---- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e8af023..9c1b6c662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ - Fix authenticating to Courier IMAP with passwords containing a '~' character (#8772) - Fix handling of smtp/imap port options on configuration file update (#8756) - Fix bug where array values could not be saved in utils/save_pref action (#8781) -- Add workaround for using Roundcube behind a reverse proxy with a subpath: 'request_uri_field' option (#8738, #8770) +- Add workaround for using Roundcube behind a reverse proxy with a subpath: 'request_path' option (#8738, #8770) - Fix bug where "Invalid skin name" error was logged on preferences save if there's only one skin (#8825) - Fix SIGBUS raised in ImageMagick when more than one process tried to generate a thumbnail of the same image attachment (#8511) - Fix bug where updater does not update the vendor packages (#8642) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 634b883a9..5bd6bb8d5 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -818,12 +818,15 @@ $config['no_save_sent_messages'] = false; // Note: Use assets_path to not prevent the browser from caching assets $config['use_secure_urls'] = false; -// Specify the $_SERVER field that contains the full path of the original HTTP request. -// This might be changed when Roundcube runs behind a reverse proxy using a subpath. +// Specifies the full path of the original HTTP request, either as a real path or +// $_SERVER field name. This might be useful when Roundcube runs behind a reverse +// proxy using a subpath. This is a path part of the URL, not the full URL! // The reverse proxy config can specify a custom header (e.g. X-Forwarded-Path) containing // the path under which Roundcube is exposed to the outside world (e.g. /rcube/). // This header value is then available in PHP with $_SERVER['HTTP_X_FORWARDED_PATH']. -$config['request_uri_field'] = 'REQUEST_URI'; +// By default the path comes from 'REQUEST_URI', 'REDIRECT_SCRIPT_URL' or 'SRIPT_NAME', +// whichever is set (in this order). +$config['request_path'] = null; // Allows to define separate server/path for image/js/css files // Warning: If the domain is different cross-domain access to some diff --git a/program/include/rcmail.php b/program/include/rcmail.php index a71ba8a66..f5de898ad 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1120,18 +1120,7 @@ class rcmail extends rcube } } - $base_path = ''; - $server_var = $this->get_request_uri_field(); - if ($server_var && !empty($_SERVER[$server_var])) { - $base_path = preg_replace('/[?&].*$/', '', $_SERVER[$server_var]); - } - else if (!empty($_SERVER['REDIRECT_SCRIPT_URL'])) { - $base_path = $_SERVER['REDIRECT_SCRIPT_URL']; - } - else if (!empty($_SERVER['SCRIPT_NAME'])) { - $base_path = $_SERVER['SCRIPT_NAME']; - } - $base_path = preg_replace('![^/]+$!', '', $base_path); + $base_path = $this->get_request_path(); if ($secure && ($token = $this->get_secure_url_token(true))) { // add token to the url @@ -1167,16 +1156,36 @@ class rcmail extends rcube } /** - * Get the 'request_uri_field' config option - * with an additional check against the 'proxy_whitelist' config + * Get the the request path */ - protected function get_request_uri_field() + protected function get_request_path() { - $server_var = $this->config->get('request_uri_field'); - if (!empty($server_var) && (strpos($server_var, 'HTTP_') !== 0 || rcube_utils::check_proxy_whitelist_ip())) { - return $server_var; + $path = $this->config->get('request_path'); + + if ($path && isset($_SERVER[$path])) { + // HTTP headers need to come from a trusted proxy host + if (strpos($path, 'HTTP_') === 0 && !rcube_utils::check_proxy_whitelist_ip()) { + return '/'; + } + + $path = $_SERVER[$path]; } - return null; + else if (empty($path)) { + foreach (['REQUEST_URI', 'REDIRECT_SCRIPT_URL', 'SCRIPT_NAME'] as $name) { + if (!empty($_SERVER[$name])) { + $path = $_SERVER[$name]; + break; + } + } + } + else { + return rtrim($path, '/') . '/'; + } + + $path = preg_replace('/[?&].*$/', '', $path); + $path = preg_replace('![^/]+$!', '', $path); + + return rtrim($path, '/') . '/'; } /** diff --git a/tests/Rcmail/Rcmail.php b/tests/Rcmail/Rcmail.php index 4c4de7c68..8feb8a727 100644 --- a/tests/Rcmail/Rcmail.php +++ b/tests/Rcmail/Rcmail.php @@ -143,15 +143,21 @@ class Rcmail_Rcmail extends ActionTestCase $rcmail->url(['_action' => 'test', '_b' => 'BB', '_c' => null]), "Prefixed parameters (skip empty)" ); - $this->assertEquals('/sub/?_task=cli', $rcmail->url([]), "Empty input"); $_SERVER['REQUEST_URI'] = '/rc/?_task=mail'; $this->assertEquals('/rc/?_task=cli', $rcmail->url([]), "Empty input with REQUEST_URI prefix"); - $rcmail->config->set('request_uri_field', 'X_FORWARDED_PATH'); - $this->assertEquals('/proxied/?_task=cli', $rcmail->url([]), "Consider request_uri_field config"); - $rcmail->config->set('request_uri_field', 'UNDEFINED'); + $rcmail->config->set('request_path', 'X_FORWARDED_PATH'); + $this->assertEquals('/proxied/?_task=cli', $rcmail->url([]), "Consider request_path config (_SERVER)"); + + $rcmail->config->set('request_path', '/test'); + $this->assertEquals('/test/?_task=cli', $rcmail->url([]), "Consider request_path config (/path)"); + $rcmail->config->set('request_path', '/test/'); + $this->assertEquals('/test/?_task=cli', $rcmail->url([]), "Consider request_path config (/path/)"); + + $_SERVER['REQUEST_URI'] = null; + $rcmail->config->set('request_path', null); $this->assertEquals( '/sub/?_task=cli&_action=test&_mode=ABS',