new class Api\Header\Http to handle X-Forwarded-Host and -Schema headers

also kope now with multiple comma-separated host-names in X-Forwarded-Host header happening with multiple proxys
This commit is contained in:
Ralf Becker 2019-11-12 20:13:24 +01:00
parent 26434ab2c2
commit 302800b414
5 changed files with 88 additions and 28 deletions

View File

@ -140,8 +140,9 @@ class Egw extends Egw\Base
} }
if (isset($_SERVER['HTTP_X_FORWARDED_HOST']) && $GLOBALS['egw_info']['server']['webserver_url'][0] != '/') if (isset($_SERVER['HTTP_X_FORWARDED_HOST']) && $GLOBALS['egw_info']['server']['webserver_url'][0] != '/')
{ {
$GLOBALS['egw_info']['server']['webserver_url'] = ($_SERVER['HTTPS'] ? 'https://' : 'http://'). $GLOBALS['egw_info']['server']['webserver_url'] =
$_SERVER['HTTP_X_FORWARDED_HOST'].parse_url($GLOBALS['egw_info']['server']['webserver_url'], PHP_URL_PATH); Header\Http::schema().'://'.Header\Http::host().
parse_url($GLOBALS['egw_info']['server']['webserver_url'], PHP_URL_PATH);
} }
// if no server timezone set, use date_default_timezone_get() to determine it once // if no server timezone set, use date_default_timezone_get() to determine it once

View File

@ -189,34 +189,11 @@ abstract class Framework extends Framework\Extra
/** /**
* Get a full / externally usable URL from an EGroupware link * Get a full / externally usable URL from an EGroupware link
* *
* Code is only used, if the Setup defined webserver_url is only a path!
*
* The following HTTP Headers / $_SERVER variables and EGroupware configuration
* is taken into account to determine if URL should use https schema:
* - $_SERVER['HTTPS'] !== off
* - $GLOBALS['egw_info']['server']['enforce_ssl'] (EGroupware Setup)
* - $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' (X-Forwarded-Proto HTTP header)
*
* Host is determined in the following order / priority:
* 1. $GLOBALS['egw_info']['server']['hostname'] !== 'localhost' (EGroupware Setup)
* 2. $_SERVER['HTTP_X_FORWARDED_HOST'] (X-Forwarded-Host HTTP header)
* 3. $_SERVER['HTTP_HOST'] (Host HTTP header)
*
* @param string $link * @param string $link
*/ */
static function getUrl($link) static function getUrl($link)
{ {
if ($link[0] === '/') return Header\Http::fullUrl($link);
{
$link = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443 ||
!empty($GLOBALS['egw_info']['server']['enforce_ssl']) || $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ?
'https://' : 'http://').
($GLOBALS['egw_info']['server']['hostname'] && $GLOBALS['egw_info']['server']['hostname'] !== 'localhost' ?
$GLOBALS['egw_info']['server']['hostname'] :
(isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST'])).
$link;
}
return $link;
} }
/** /**

82
api/src/Header/Http.php Normal file
View File

@ -0,0 +1,82 @@
<?php
/**
* EGroupware API: HTTP header handling for host and schema
*
* @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright 2019 by RalfBecker@outdoor-training.de
* @package api
* @subpackage header
*/
namespace EGroupware\Api\Header;
/**
* HTTP header handling for host and schema
*/
class Http
{
/**
* Get host considering X-Forwarded-Host and Host header
*
* Host is determined in the following order / priority:
* 1. $GLOBALS['egw_info']['server']['hostname'] !== 'localhost' (EGroupware Setup)
* 2. $_SERVER['HTTP_X_FORWARDED_HOST'] (X-Forwarded-Host HTTP header)
* 3. $_SERVER['HTTP_HOST'] (Host HTTP header)
*
* @return string
*/
static function host()
{
if (!empty($GLOBALS['egw_info']['server']['hostname']) && $GLOBALS['egw_info']['server']['hostname'] !== 'localhost')
{
$host = $GLOBALS['egw_info']['server']['hostname'];
}
elseif (isset($_SERVER['HTTP_X_FORWARDED_HOST']))
{
list($host) = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
}
else
{
$host = $_SERVER['HTTP_HOST'];
}
return $host;
}
/**
* Get schema considering X-Forwarded-Schema and used schema
*
* The following HTTP Headers / $_SERVER variables and EGroupware configuration
* is taken into account to determine if URL should use https schema:
* - $_SERVER['HTTPS'] !== off
* - $GLOBALS['egw_info']['server']['enforce_ssl'] (EGroupware Setup)
* - $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' (X-Forwarded-Proto HTTP header)
*
* @return string
*/
static function schema()
{
return !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ||
$_SERVER['SERVER_PORT'] == 443 ||
!empty($GLOBALS['egw_info']['server']['enforce_ssl']) ||
$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ?
'https' : 'http';
}
/**
* Get a full / externally usable URL from an EGroupware link
*
* Code is only used, if $link is only a path (starts with slash)
*
* @param string $link
*/
static function fullUrl($link)
{
if ($link[0] === '/')
{
$link = self::schema().'://'.self::host().$link;
}
return $link;
}
}

View File

@ -1650,7 +1650,7 @@ class Session
else else
{ {
// Use HTTP_X_FORWARDED_HOST if set, which is the case behind a none-transparent proxy // Use HTTP_X_FORWARDED_HOST if set, which is the case behind a none-transparent proxy
self::$cookie_domain = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST']; self::$cookie_domain = Header\Http::host();
} }
// remove port from HTTP_HOST // remove port from HTTP_HOST
$arr = null; $arr = null;

View File

@ -157,7 +157,7 @@ class setup
static function cookiedomain() static function cookiedomain()
{ {
// Use HTTP_X_FORWARDED_HOST if set, which is the case behind a none-transparent proxy // Use HTTP_X_FORWARDED_HOST if set, which is the case behind a none-transparent proxy
$cookie_domain = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST']; $cookie_domain = Api\Header\Http::host();
// remove port from HTTP_HOST // remove port from HTTP_HOST
$arr = null; $arr = null;