diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php index 25d5596e951c163c906be43c89682fcdd7fcab2a..9f5a50e40aa2d540bad8eb3c61277e629a4619d3 100644 --- a/lib/SimpleSAML/Utils/HTTP.php +++ b/lib/SimpleSAML/Utils/HTTP.php @@ -729,11 +729,31 @@ class HTTP { $cfg = \SimpleSAML_Configuration::getInstance(); $baseDir = $cfg->getBaseDir(); - $current_path = realpath($_SERVER['SCRIPT_FILENAME']); - $rel_path = str_replace($baseDir.'www'.DIRECTORY_SEPARATOR, '', $current_path); - - if ($current_path == $rel_path) { // compare loosely ($current_path can be false) - // we were accessed from an external script, do not try to apply our base URL + $cur_path = realpath($_SERVER['SCRIPT_FILENAME']); + // find the path to the current script relative to the www/ directory of SimpleSAMLphp + $rel_path = str_replace($baseDir.'www'.DIRECTORY_SEPARATOR, '', $cur_path); + // convert that relative path to an HTTP query + $url_path = str_replace(DIRECTORY_SEPARATOR, '/', $rel_path); + // find where the relative path starts in the current request URI + $uri_pos = (!empty($url_path)) ? strpos($_SERVER['REQUEST_URI'], $url_path) : false; + + if ($cur_path == $rel_path || $uri_pos === false) { + /* + * We were accessed from an external script. This can happen in the following cases: + * + * - $_SERVER['SCRIPT_FILENAME'] points to a script that doesn't exist. E.g. functional testing. In this + * case, realpath() returns false and str_replace an empty string, so we compare them loosely. + * + * - The URI requested does not belong to a script in the www/ directory of SimpleSAMLphp. In that case, + * removing SimpleSAMLphp's base dir from the current path yields the same path, so $cur_path and + * $rel_path are equal. + * + * - The request URI does not match the current script. Even if the current script is located in the www/ + * directory of SimpleSAMLphp, the URI does not contain its relative path, and $uri_pos is false. + * + * It doesn't matter which one of those cases we have. We just know we can't apply our base URL to the + * current URI, so we need to build it back from the PHP environment. + */ $protocol = 'http'; $protocol .= (self::getServerHTTPS()) ? 's' : ''; $protocol .= '://'; @@ -743,10 +763,7 @@ class HTTP return $protocol.$hostname.$port.$_SERVER['REQUEST_URI']; } - $url = self::getBaseURL(); - $rel_path = str_replace(DIRECTORY_SEPARATOR, '/', $rel_path); - $pos = strpos($_SERVER['REQUEST_URI'], $rel_path) + strlen($rel_path); - return $url.$rel_path.substr($_SERVER['REQUEST_URI'], $pos); + return self::getBaseURL().$rel_path.substr($_SERVER['REQUEST_URI'], $uri_pos + strlen($url_path)); } diff --git a/tests/lib/SimpleSAML/Utils/HTTPTest.php b/tests/lib/SimpleSAML/Utils/HTTPTest.php index b6bfb6b160016b7093289a9e582d1cb9adae031e..4fd540cfb241d38575cf0638b9fa10902f54fb2d 100644 --- a/tests/lib/SimpleSAML/Utils/HTTPTest.php +++ b/tests/lib/SimpleSAML/Utils/HTTPTest.php @@ -189,12 +189,24 @@ class HTTPTest extends \PHPUnit_Framework_TestCase $this->assertTrue(HTTP::isHTTPS()); $this->assertEquals('https://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost()); - // test a valid, full URL, based on a full URL in the configuration + // test a request URI that doesn't match the current script $cfg = \SimpleSAML_Configuration::loadFromArray(array( - 'baseurlpath' => 'https://example.com/simplesaml/', + 'baseurlpath' => 'https://example.org/simplesaml/', ), '[ARRAY]', 'simplesaml'); $baseDir = $cfg->getBaseDir(); $_SERVER['SCRIPT_FILENAME'] = $baseDir.'www/module.php'; + $this->setupEnvFromURL('http://www.example.com/protected/resource.asp?foo=bar'); + $this->assertEquals('http://www.example.com/protected/resource.asp?foo=bar', HTTP::getSelfURL()); + $this->assertEquals('http://www.example.com', HTTP::getSelfURLHost()); + $this->assertEquals('http://www.example.com/protected/resource.asp', HTTP::getSelfURLNoQuery()); + $this->assertFalse(HTTP::isHTTPS()); + $this->assertEquals('example.org', HTTP::getSelfHostWithNonStandardPort()); + $this->assertEquals('http://www.example.com', HTTP::getSelfURLHost()); + + // test a valid, full URL, based on a full URL in the configuration + \SimpleSAML_Configuration::loadFromArray(array( + 'baseurlpath' => 'https://example.com/simplesaml/', + ), '[ARRAY]', 'simplesaml'); $this->setupEnvFromURL('http://www.example.org/module.php/module/file.php?foo=bar'); $this->assertEquals( 'https://example.com/simplesaml/module.php/module/file.php?foo=bar',