This changeset removes the static class `OC_Request` and moves the functions either into `IRequest` which is accessible via `\OC::$server::->getRequest()` or into a separated `TrustedDomainHelper` class for some helper methods which should not be publicly exposed. This changes only internal methods and nothing on the public API. Some public functions in `util.php` have been deprecated though in favour of the new non-static functions. Unfortunately some part of this code uses things like `__DIR__` and thus is not completely unit-testable. Where tests where possible they ahve been added though. Fixes https://github.com/owncloud/core/issues/13976 which was requested in https://github.com/owncloud/core/pull/13973#issuecomment-73492969remotes/origin/log-external-deletes
parent
7f624188a7
commit
886bda5f81
@ -1,330 +0,0 @@ |
||||
<?php |
||||
/** |
||||
* Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
|
||||
class OC_Request { |
||||
|
||||
const USER_AGENT_IE = '/MSIE/'; |
||||
// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent |
||||
const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#'; |
||||
const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#'; |
||||
const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost)$/'; |
||||
|
||||
/** |
||||
* Returns the remote address, if the connection came from a trusted proxy and `forwarded_for_headers` has been configured |
||||
* then the IP address specified in this header will be returned instead. |
||||
* Do always use this instead of $_SERVER['REMOTE_ADDR'] |
||||
* @return string IP address |
||||
*/ |
||||
public static function getRemoteAddress() { |
||||
$remoteAddress = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; |
||||
$trustedProxies = \OC::$server->getConfig()->getSystemValue('trusted_proxies', array()); |
||||
|
||||
if(is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) { |
||||
$forwardedForHeaders = \OC::$server->getConfig()->getSystemValue('forwarded_for_headers', array()); |
||||
|
||||
foreach($forwardedForHeaders as $header) { |
||||
if (array_key_exists($header, $_SERVER) === true) { |
||||
foreach (explode(',', $_SERVER[$header]) as $IP) { |
||||
$IP = trim($IP); |
||||
if (filter_var($IP, FILTER_VALIDATE_IP) !== false) { |
||||
return $IP; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return $remoteAddress; |
||||
} |
||||
|
||||
/** |
||||
* Check overwrite condition |
||||
* @param string $type |
||||
* @return bool |
||||
*/ |
||||
private static function isOverwriteCondition($type = '') { |
||||
$regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/'; |
||||
return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1 |
||||
or ($type !== 'protocol' and OC_Config::getValue('forcessl', false)); |
||||
} |
||||
|
||||
/** |
||||
* Strips a potential port from a domain (in format domain:port) |
||||
* @param $host |
||||
* @return string $host without appended port |
||||
*/ |
||||
public static function getDomainWithoutPort($host) { |
||||
$pos = strrpos($host, ':'); |
||||
if ($pos !== false) { |
||||
$port = substr($host, $pos + 1); |
||||
if (is_numeric($port)) { |
||||
$host = substr($host, 0, $pos); |
||||
} |
||||
} |
||||
return $host; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether a domain is considered as trusted from the list |
||||
* of trusted domains. If no trusted domains have been configured, returns |
||||
* true. |
||||
* This is used to prevent Host Header Poisoning. |
||||
* @param string $domainWithPort |
||||
* @return bool true if the given domain is trusted or if no trusted domains |
||||
* have been configured |
||||
*/ |
||||
public static function isTrustedDomain($domainWithPort) { |
||||
// Extract port from domain if needed |
||||
$domain = self::getDomainWithoutPort($domainWithPort); |
||||
|
||||
// FIXME: Empty config array defaults to true for now. - Deprecate this behaviour with ownCloud 8. |
||||
$trustedList = \OC::$server->getConfig()->getSystemValue('trusted_domains', array()); |
||||
if (empty($trustedList)) { |
||||
return true; |
||||
} |
||||
|
||||
// FIXME: Workaround for older instances still with port applied. Remove for ownCloud 9. |
||||
if(in_array($domainWithPort, $trustedList)) { |
||||
return true; |
||||
} |
||||
|
||||
// Always allow access from localhost |
||||
if (preg_match(self::REGEX_LOCALHOST, $domain) === 1) { |
||||
return true; |
||||
} |
||||
|
||||
return in_array($domain, $trustedList); |
||||
} |
||||
|
||||
/** |
||||
* Returns the unverified server host from the headers without checking |
||||
* whether it is a trusted domain |
||||
* @return string the server host |
||||
* |
||||
* Returns the server host, even if the website uses one or more |
||||
* reverse proxies |
||||
*/ |
||||
public static function insecureServerHost() { |
||||
$host = null; |
||||
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { |
||||
if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { |
||||
$parts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); |
||||
$host = trim(current($parts)); |
||||
} else { |
||||
$host = $_SERVER['HTTP_X_FORWARDED_HOST']; |
||||
} |
||||
} else { |
||||
if (isset($_SERVER['HTTP_HOST'])) { |
||||
$host = $_SERVER['HTTP_HOST']; |
||||
} else if (isset($_SERVER['SERVER_NAME'])) { |
||||
$host = $_SERVER['SERVER_NAME']; |
||||
} |
||||
} |
||||
return $host; |
||||
} |
||||
|
||||
/** |
||||
* Returns the overwritehost setting from the config if set and |
||||
* if the overwrite condition is met |
||||
* @return string|null overwritehost value or null if not defined or the defined condition |
||||
* isn't met |
||||
*/ |
||||
public static function getOverwriteHost() { |
||||
if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { |
||||
return OC_Config::getValue('overwritehost'); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Returns the server host from the headers, or the first configured |
||||
* trusted domain if the host isn't in the trusted list |
||||
* @return string the server host |
||||
* |
||||
* Returns the server host, even if the website uses one or more |
||||
* reverse proxies |
||||
*/ |
||||
public static function serverHost() { |
||||
if (OC::$CLI && defined('PHPUNIT_RUN')) { |
||||
return 'localhost'; |
||||
} |
||||
|
||||
// overwritehost is always trusted |
||||
$host = self::getOverwriteHost(); |
||||
if ($host !== null) { |
||||
return $host; |
||||
} |
||||
|
||||
// get the host from the headers |
||||
$host = self::insecureServerHost(); |
||||
|
||||
// Verify that the host is a trusted domain if the trusted domains |
||||
// are defined |
||||
// If no trusted domain is provided the first trusted domain is returned |
||||
if (self::isTrustedDomain($host)) { |
||||
return $host; |
||||
} else { |
||||
$trustedList = \OC_Config::getValue('trusted_domains', array('')); |
||||
return $trustedList[0]; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the server protocol |
||||
* @return string the server protocol |
||||
* |
||||
* Returns the server protocol. It respects reverse proxy servers and load balancers |
||||
*/ |
||||
public static function serverProtocol() { |
||||
if(OC_Config::getValue('overwriteprotocol', '') !== '' and self::isOverwriteCondition('protocol')) { |
||||
return OC_Config::getValue('overwriteprotocol'); |
||||
} |
||||
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { |
||||
$proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']); |
||||
// Verify that the protocol is always HTTP or HTTPS |
||||
// default to http if an invalid value is provided |
||||
return $proto === 'https' ? 'https' : 'http'; |
||||
} |
||||
if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') { |
||||
return 'https'; |
||||
} |
||||
return 'http'; |
||||
} |
||||
|
||||
/** |
||||
* Returns the request uri |
||||
* @return string the request uri |
||||
* |
||||
* Returns the request uri, even if the website uses one or more |
||||
* reverse proxies |
||||
* @return string |
||||
*/ |
||||
public static function requestUri() { |
||||
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; |
||||
if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) { |
||||
$uri = self::scriptName() . substr($uri, strlen($_SERVER['SCRIPT_NAME'])); |
||||
} |
||||
return $uri; |
||||
} |
||||
|
||||
/** |
||||
* Returns the script name |
||||
* @return string the script name |
||||
* |
||||
* Returns the script name, even if the website uses one or more |
||||
* reverse proxies |
||||
*/ |
||||
public static function scriptName() { |
||||
$name = $_SERVER['SCRIPT_NAME']; |
||||
$overwriteWebRoot = OC_Config::getValue('overwritewebroot', ''); |
||||
if ($overwriteWebRoot !== '' and self::isOverwriteCondition()) { |
||||
$serverroot = str_replace("\\", '/', substr(__DIR__, 0, -strlen('lib/private/'))); |
||||
$suburi = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen($serverroot))); |
||||
$name = '/' . ltrim($overwriteWebRoot . $suburi, '/'); |
||||
} |
||||
return $name; |
||||
} |
||||
|
||||
/** |
||||
* get Path info from request |
||||
* @return string Path info or false when not found |
||||
*/ |
||||
public static function getPathInfo() { |
||||
if (array_key_exists('PATH_INFO', $_SERVER)) { |
||||
$path_info = $_SERVER['PATH_INFO']; |
||||
}else{ |
||||
$path_info = self::getRawPathInfo(); |
||||
// following is taken from \Sabre\DAV\URLUtil::decodePathSegment |
||||
$path_info = rawurldecode($path_info); |
||||
$encoding = mb_detect_encoding($path_info, array('UTF-8', 'ISO-8859-1')); |
||||
|
||||
switch($encoding) { |
||||
|
||||
case 'ISO-8859-1' : |
||||
$path_info = utf8_encode($path_info); |
||||
|
||||
} |
||||
// end copy |
||||
} |
||||
return $path_info; |
||||
} |
||||
|
||||
/** |
||||
* get Path info from request, not urldecoded |
||||
* @throws Exception |
||||
* @return string Path info or false when not found |
||||
*/ |
||||
public static function getRawPathInfo() { |
||||
$requestUri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; |
||||
// remove too many leading slashes - can be caused by reverse proxy configuration |
||||
if (strpos($requestUri, '/') === 0) { |
||||
$requestUri = '/' . ltrim($requestUri, '/'); |
||||
} |
||||
|
||||
$requestUri = preg_replace('%/{2,}%', '/', $requestUri); |
||||
|
||||
// Remove the query string from REQUEST_URI |
||||
if ($pos = strpos($requestUri, '?')) { |
||||
$requestUri = substr($requestUri, 0, $pos); |
||||
} |
||||
|
||||
$scriptName = $_SERVER['SCRIPT_NAME']; |
||||
$path_info = $requestUri; |
||||
|
||||
// strip off the script name's dir and file name |
||||
list($path, $name) = \Sabre\DAV\URLUtil::splitPath($scriptName); |
||||
if (!empty($path)) { |
||||
if( $path === $path_info || strpos($path_info, $path.'/') === 0) { |
||||
$path_info = substr($path_info, strlen($path)); |
||||
} else { |
||||
throw new Exception("The requested uri($requestUri) cannot be processed by the script '$scriptName')"); |
||||
} |
||||
} |
||||
if (strpos($path_info, '/'.$name) === 0) { |
||||
$path_info = substr($path_info, strlen($name) + 1); |
||||
} |
||||
if (strpos($path_info, $name) === 0) { |
||||
$path_info = substr($path_info, strlen($name)); |
||||
} |
||||
if($path_info === '/'){ |
||||
return ''; |
||||
} else { |
||||
return $path_info; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Check if the requester sent along an mtime |
||||
* @return false or an mtime |
||||
*/ |
||||
static public function hasModificationTime () { |
||||
if (isset($_SERVER['HTTP_X_OC_MTIME'])) { |
||||
return $_SERVER['HTTP_X_OC_MTIME']; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Checks whether the user agent matches a given regex |
||||
* @param string|array $agent agent name or array of agent names |
||||
* @return boolean true if at least one of the given agent matches, |
||||
* false otherwise |
||||
*/ |
||||
static public function isUserAgent($agent) { |
||||
if (!is_array($agent)) { |
||||
$agent = array($agent); |
||||
} |
||||
foreach ($agent as $regex) { |
||||
if (preg_match($regex, $_SERVER['HTTP_USER_AGENT'])) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
<?php |
||||
/** |
||||
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
|
||||
namespace OC\Security; |
||||
use OC\AppFramework\Http\Request; |
||||
use OCP\IConfig; |
||||
|
||||
/** |
||||
* Class TrustedDomain |
||||
* |
||||
* @package OC\Security |
||||
*/ |
||||
class TrustedDomainHelper { |
||||
/** @var IConfig */ |
||||
private $config; |
||||
|
||||
/** |
||||
* @param IConfig $config |
||||
*/ |
||||
function __construct(IConfig $config) { |
||||
$this->config = $config; |
||||
} |
||||
|
||||
/** |
||||
* Strips a potential port from a domain (in format domain:port) |
||||
* @param $host |
||||
* @return string $host without appended port |
||||
*/ |
||||
private function getDomainWithoutPort($host) { |
||||
$pos = strrpos($host, ':'); |
||||
if ($pos !== false) { |
||||
$port = substr($host, $pos + 1); |
||||
if (is_numeric($port)) { |
||||
$host = substr($host, 0, $pos); |
||||
} |
||||
} |
||||
return $host; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether a domain is considered as trusted from the list |
||||
* of trusted domains. If no trusted domains have been configured, returns |
||||
* true. |
||||
* This is used to prevent Host Header Poisoning. |
||||
* @param string $domainWithPort |
||||
* @return bool true if the given domain is trusted or if no trusted domains |
||||
* have been configured |
||||
*/ |
||||
public function isTrustedDomain($domainWithPort) { |
||||
$domain = $this->getDomainWithoutPort($domainWithPort); |
||||
|
||||
// Read trusted domains from config |
||||
$trustedList = $this->config->getSystemValue('trusted_domains', []); |
||||
if(!is_array($trustedList)) { |
||||
return false; |
||||
} |
||||
|
||||
// TODO: Workaround for older instances still with port applied. Remove for ownCloud 9. |
||||
if(in_array($domainWithPort, $trustedList)) { |
||||
return true; |
||||
} |
||||
|
||||
// Always allow access from localhost |
||||
if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) { |
||||
return true; |
||||
} |
||||
return in_array($domain, $trustedList); |
||||
} |
||||
|
||||
} |
@ -1,333 +0,0 @@ |
||||
<?php |
||||
/** |
||||
* Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
|
||||
class Test_Request extends \Test\TestCase { |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
OC::$server->getConfig()->setSystemValue('overwritewebroot', '/domain.tld/ownCloud'); |
||||
|
||||
OC::$server->getConfig()->setSystemValue('trusted_proxies', array()); |
||||
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array()); |
||||
} |
||||
|
||||
protected function tearDown() { |
||||
OC::$server->getConfig()->setSystemValue('overwritewebroot', ''); |
||||
OC::$server->getConfig()->setSystemValue('trusted_proxies', array()); |
||||
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array()); |
||||
|
||||
parent::tearDown(); |
||||
} |
||||
|
||||
public function testScriptNameOverWrite() { |
||||
$_SERVER['REMOTE_ADDR'] = '10.0.0.1'; |
||||
$_SERVER['SCRIPT_FILENAME'] = __FILE__; |
||||
|
||||
$scriptName = OC_Request::scriptName(); |
||||
$this->assertEquals('/domain.tld/ownCloud/tests/lib/request.php', $scriptName); |
||||
} |
||||
|
||||
public function testGetRemoteAddress() { |
||||
$_SERVER['REMOTE_ADDR'] = '10.0.0.2'; |
||||
$_SERVER['HTTP_X_FORWARDED'] = '10.4.0.5, 10.4.0.4'; |
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = '192.168.0.233'; |
||||
|
||||
// Without having specified a trusted remote address |
||||
$this->assertEquals('10.0.0.2', OC_Request::getRemoteAddress()); |
||||
|
||||
// With specifying a trusted remote address but no trusted header |
||||
OC::$server->getConfig()->setSystemValue('trusted_proxies', array('10.0.0.2')); |
||||
$this->assertEquals('10.0.0.2', OC_Request::getRemoteAddress()); |
||||
|
||||
// With specifying a trusted remote address and trusted headers |
||||
OC::$server->getConfig()->setSystemValue('trusted_proxies', array('10.0.0.2')); |
||||
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_X_FORWARDED')); |
||||
$this->assertEquals('10.4.0.5', OC_Request::getRemoteAddress()); |
||||
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED')); |
||||
$this->assertEquals('192.168.0.233', OC_Request::getRemoteAddress()); |
||||
|
||||
// With specifying multiple trusted remote addresses and trusted headers |
||||
OC::$server->getConfig()->setSystemValue('trusted_proxies', array('10.3.4.2', '10.0.0.2', '127.0.3.3')); |
||||
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_X_FORWARDED')); |
||||
$this->assertEquals('10.4.0.5', OC_Request::getRemoteAddress()); |
||||
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED')); |
||||
$this->assertEquals('192.168.0.233', OC_Request::getRemoteAddress()); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider rawPathInfoProvider |
||||
* @param $expected |
||||
* @param $requestUri |
||||
* @param $scriptName |
||||
*/ |
||||
public function testRawPathInfo($expected, $requestUri, $scriptName) { |
||||
$_SERVER['REQUEST_URI'] = $requestUri; |
||||
$_SERVER['SCRIPT_NAME'] = $scriptName; |
||||
$rawPathInfo = OC_Request::getRawPathInfo(); |
||||
$this->assertEquals($expected, $rawPathInfo); |
||||
} |
||||
|
||||
function rawPathInfoProvider() { |
||||
return array( |
||||
array('/core/ajax/translations.php', 'index.php/core/ajax/translations.php', 'index.php'), |
||||
array('/core/ajax/translations.php', '/index.php/core/ajax/translations.php', '/index.php'), |
||||
array('/core/ajax/translations.php', '//index.php/core/ajax/translations.php', '/index.php'), |
||||
array('', '/oc/core', '/oc/core/index.php'), |
||||
array('', '/oc/core/', '/oc/core/index.php'), |
||||
array('', '/oc/core/index.php', '/oc/core/index.php'), |
||||
array('/core/ajax/translations.php', '/core/ajax/translations.php', 'index.php'), |
||||
array('/core/ajax/translations.php', '//core/ajax/translations.php', '/index.php'), |
||||
array('/core/ajax/translations.php', '/oc/core/ajax/translations.php', '/oc/index.php'), |
||||
array('/core/ajax/translations.php', '/oc//index.php/core/ajax/translations.php', '/oc/index.php'), |
||||
array('/1', '/oc/core/1', '/oc/core/index.php'), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider rawPathInfoThrowsExceptionProvider |
||||
* @expectedException Exception |
||||
* |
||||
* @param $requestUri |
||||
* @param $scriptName |
||||
*/ |
||||
public function testRawPathInfoThrowsException($requestUri, $scriptName) { |
||||
$_SERVER['REQUEST_URI'] = $requestUri; |
||||
$_SERVER['SCRIPT_NAME'] = $scriptName; |
||||
OC_Request::getRawPathInfo(); |
||||
} |
||||
|
||||
function rawPathInfoThrowsExceptionProvider() { |
||||
return array( |
||||
array('/oc/core1', '/oc/core/index.php'), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider userAgentProvider |
||||
*/ |
||||
public function testUserAgent($testAgent, $userAgent, $matches) { |
||||
$_SERVER['HTTP_USER_AGENT'] = $testAgent; |
||||
$this->assertEquals($matches, OC_Request::isUserAgent($userAgent)); |
||||
} |
||||
|
||||
function userAgentProvider() { |
||||
return array( |
||||
array( |
||||
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', |
||||
OC_Request::USER_AGENT_IE, |
||||
true |
||||
), |
||||
array( |
||||
'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0', |
||||
OC_Request::USER_AGENT_IE, |
||||
false |
||||
), |
||||
array( |
||||
'Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36', |
||||
OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
||||
true |
||||
), |
||||
array( |
||||
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', |
||||
OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
||||
false |
||||
), |
||||
// test two values |
||||
array( |
||||
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', |
||||
array( |
||||
OC_Request::USER_AGENT_IE, |
||||
OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
||||
), |
||||
true |
||||
), |
||||
array( |
||||
'Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36', |
||||
array( |
||||
OC_Request::USER_AGENT_IE, |
||||
OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
||||
), |
||||
true |
||||
), |
||||
array( |
||||
'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0', |
||||
OC_Request::USER_AGENT_FREEBOX, |
||||
false |
||||
), |
||||
array( |
||||
'Mozilla/5.0', |
||||
OC_Request::USER_AGENT_FREEBOX, |
||||
true |
||||
), |
||||
array( |
||||
'Fake Mozilla/5.0', |
||||
OC_Request::USER_AGENT_FREEBOX, |
||||
false |
||||
), |
||||
); |
||||
} |
||||
|
||||
public function testInsecureServerHost() { |
||||
unset($_SERVER['HTTP_X_FORWARDED_HOST']); |
||||
unset($_SERVER['HTTP_HOST']); |
||||
unset($_SERVER['SERVER_NAME']); |
||||
$_SERVER['SERVER_NAME'] = 'from.server.name:8080'; |
||||
$host = OC_Request::insecureServerHost(); |
||||
$this->assertEquals('from.server.name:8080', $host); |
||||
|
||||
$_SERVER['HTTP_HOST'] = 'from.host.header:8080'; |
||||
$host = OC_Request::insecureServerHost(); |
||||
$this->assertEquals('from.host.header:8080', $host); |
||||
|
||||
$_SERVER['HTTP_X_FORWARDED_HOST'] = 'from.forwarded.host:8080'; |
||||
$host = OC_Request::insecureServerHost(); |
||||
$this->assertEquals('from.forwarded.host:8080', $host); |
||||
|
||||
$_SERVER['HTTP_X_FORWARDED_HOST'] = 'from.forwarded.host2:8080,another.one:9000'; |
||||
$host = OC_Request::insecureServerHost(); |
||||
$this->assertEquals('from.forwarded.host2:8080', $host); |
||||
|
||||
// clean up |
||||
unset($_SERVER['HTTP_X_FORWARDED_HOST']); |
||||
unset($_SERVER['HTTP_HOST']); |
||||
unset($_SERVER['SERVER_NAME']); |
||||
} |
||||
|
||||
public function testGetOverwriteHost() { |
||||
unset($_SERVER['REMOTE_ADDR']); |
||||
OC_Config::deleteKey('overwritecondaddr'); |
||||
OC_Config::deleteKey('overwritehost'); |
||||
$host = OC_Request::getOverwriteHost(); |
||||
$this->assertNull($host); |
||||
|
||||
OC_Config::setValue('overwritehost', ''); |
||||
$host = OC_Request::getOverwriteHost(); |
||||
$this->assertNull($host); |
||||
|
||||
OC_Config::setValue('overwritehost', 'host.one.test:8080'); |
||||
$host = OC_Request::getOverwriteHost(); |
||||
$this->assertEquals('host.one.test:8080', $host); |
||||
|
||||
$_SERVER['REMOTE_ADDR'] = 'somehost.test:8080'; |
||||
OC_Config::setValue('overwritecondaddr', '^somehost\..*$'); |
||||
$host = OC_Request::getOverwriteHost(); |
||||
$this->assertEquals('host.one.test:8080', $host); |
||||
|
||||
OC_Config::setValue('overwritecondaddr', '^somethingelse.*$'); |
||||
$host = OC_Request::getOverwriteHost(); |
||||
$this->assertNull($host); |
||||
|
||||
// clean up |
||||
unset($_SERVER['REMOTE_ADDR']); |
||||
OC_Config::deleteKey('overwritecondaddr'); |
||||
OC_Config::deleteKey('overwritehost'); |
||||
} |
||||
|
||||
public function hostWithPortProvider() { |
||||
return array( |
||||
array('localhost:500', 'localhost'), |
||||
array('foo.com', 'foo.com'), |
||||
array('[1fff:0:a88:85a3::ac1f]:801', '[1fff:0:a88:85a3::ac1f]'), |
||||
array('[1fff:0:a88:85a3::ac1f]', '[1fff:0:a88:85a3::ac1f]') |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider hostWithPortProvider |
||||
*/ |
||||
public function testGetDomainWithoutPort($hostWithPort, $host) { |
||||
$this->assertEquals($host, OC_Request::getDomainWithoutPort($hostWithPort)); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* @dataProvider trustedDomainDataProvider |
||||
*/ |
||||
public function testIsTrustedDomain($trustedDomains, $testDomain, $result) { |
||||
OC_Config::deleteKey('trusted_domains'); |
||||
if ($trustedDomains !== null) { |
||||
OC_Config::setValue('trusted_domains', $trustedDomains); |
||||
} |
||||
|
||||
$this->assertEquals($result, OC_Request::isTrustedDomain($testDomain)); |
||||
|
||||
// clean up |
||||
OC_Config::deleteKey('trusted_domains'); |
||||
} |
||||
|
||||
public function trustedDomainDataProvider() { |
||||
$trustedHostTestList = array('host.one.test', 'host.two.test', '[1fff:0:a88:85a3::ac1f]'); |
||||
return array( |
||||
// empty defaults to true |
||||
array(null, 'host.one.test:8080', true), |
||||
array('', 'host.one.test:8080', true), |
||||
array(array(), 'host.one.test:8080', true), |
||||
|
||||
// trust list when defined |
||||
array($trustedHostTestList, 'host.two.test:8080', true), |
||||
array($trustedHostTestList, 'host.two.test:9999', true), |
||||
array($trustedHostTestList, 'host.three.test:8080', false), |
||||
array($trustedHostTestList, 'host.two.test:8080:aa:222', false), |
||||
array($trustedHostTestList, '[1fff:0:a88:85a3::ac1f]', true), |
||||
array($trustedHostTestList, '[1fff:0:a88:85a3::ac1f]:801', true), |
||||
array($trustedHostTestList, '[1fff:0:a88:85a3::ac1f]:801:34', false), |
||||
|
||||
// trust localhost regardless of trust list |
||||
array($trustedHostTestList, 'localhost', true), |
||||
array($trustedHostTestList, 'localhost:8080', true), |
||||
array($trustedHostTestList, '127.0.0.1', true), |
||||
array($trustedHostTestList, '127.0.0.1:8080', true), |
||||
|
||||
// do not trust invalid localhosts |
||||
array($trustedHostTestList, 'localhost:1:2', false), |
||||
array($trustedHostTestList, 'localhost: evil.host', false), |
||||
); |
||||
} |
||||
|
||||
public function testServerHost() { |
||||
OC_Config::deleteKey('overwritecondaddr'); |
||||
OC_Config::setValue('overwritehost', 'overwritten.host:8080'); |
||||
OC_Config::setValue( |
||||
'trusted_domains', |
||||
array( |
||||
'trusted.host:8080', |
||||
'second.trusted.host:8080' |
||||
) |
||||
); |
||||
$_SERVER['HTTP_HOST'] = 'trusted.host:8080'; |
||||
|
||||
// CLI always gives localhost |
||||
$oldCLI = OC::$CLI; |
||||
OC::$CLI = true; |
||||
$host = OC_Request::serverHost(); |
||||
$this->assertEquals('localhost', $host); |
||||
OC::$CLI = false; |
||||
|
||||
// overwritehost overrides trusted domain |
||||
$host = OC_Request::serverHost(); |
||||
$this->assertEquals('overwritten.host:8080', $host); |
||||
|
||||
// trusted domain returned when used |
||||
OC_Config::deleteKey('overwritehost'); |
||||
$host = OC_Request::serverHost(); |
||||
$this->assertEquals('trusted.host:8080', $host); |
||||
|
||||
// trusted domain returned when untrusted one in header |
||||
$_SERVER['HTTP_HOST'] = 'untrusted.host:8080'; |
||||
OC_Config::deleteKey('overwritehost'); |
||||
$host = OC_Request::serverHost(); |
||||
$this->assertEquals('trusted.host:8080', $host); |
||||
|
||||
// clean up |
||||
OC_Config::deleteKey('overwritecondaddr'); |
||||
OC_Config::deleteKey('overwritehost'); |
||||
unset($_SERVER['HTTP_HOST']); |
||||
OC::$CLI = $oldCLI; |
||||
} |
||||
} |
@ -0,0 +1,70 @@ |
||||
<?php |
||||
/** |
||||
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
|
||||
use \OC\Security\TrustedDomainHelper; |
||||
use OCP\IConfig; |
||||
|
||||
/** |
||||
* Class TrustedDomainHelperTest |
||||
*/ |
||||
class TrustedDomainHelperTest extends \Test\TestCase { |
||||
/** @var IConfig */ |
||||
protected $config; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->config = $this->getMockBuilder('\OCP\IConfig')->getMock(); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider trustedDomainDataProvider |
||||
* @param string $trustedDomains |
||||
* @param string $testDomain |
||||
* @param bool $result |
||||
*/ |
||||
public function testIsTrustedDomain($trustedDomains, $testDomain, $result) { |
||||
$this->config->expects($this->once()) |
||||
->method('getSystemValue') |
||||
->with('trusted_domains') |
||||
->will($this->returnValue($trustedDomains)); |
||||
|
||||
$trustedDomainHelper = new TrustedDomainHelper($this->config); |
||||
$this->assertEquals($result, $trustedDomainHelper->isTrustedDomain($testDomain)); |
||||
} |
||||
|
||||
/** |
||||
* @return array |
||||
*/ |
||||
public function trustedDomainDataProvider() { |
||||
$trustedHostTestList = ['host.one.test', 'host.two.test', '[1fff:0:a88:85a3::ac1f]']; |
||||
return [ |
||||
// empty defaults to false with 8.1 |
||||
[null, 'host.one.test:8080', false], |
||||
['', 'host.one.test:8080', false], |
||||
[[], 'host.one.test:8080', false], |
||||
// trust list when defined |
||||
[$trustedHostTestList, 'host.two.test:8080', true], |
||||
[$trustedHostTestList, 'host.two.test:9999', true], |
||||
[$trustedHostTestList, 'host.three.test:8080', false], |
||||
[$trustedHostTestList, 'host.two.test:8080:aa:222', false], |
||||
[$trustedHostTestList, '[1fff:0:a88:85a3::ac1f]', true], |
||||
[$trustedHostTestList, '[1fff:0:a88:85a3::ac1f]:801', true], |
||||
[$trustedHostTestList, '[1fff:0:a88:85a3::ac1f]:801:34', false], |
||||
// trust localhost regardless of trust list |
||||
[$trustedHostTestList, 'localhost', true], |
||||
[$trustedHostTestList, 'localhost:8080', true], |
||||
[$trustedHostTestList, '127.0.0.1', true], |
||||
[$trustedHostTestList, '127.0.0.1:8080', true], |
||||
// do not trust invalid localhosts |
||||
[$trustedHostTestList, 'localhost:1:2', false], |
||||
[$trustedHostTestList, 'localhost: evil.host', false], |
||||
]; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue