diff --git a/config-templates/config.php b/config-templates/config.php index 97ae7b7c9784a20c100650735fd61c13a3110ec0..33915d604e4c000d1bd7ff229e49259057829ab3 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -10,6 +10,17 @@ $config = array ( /** * Setup the following parameters to match the directory of your installation. * See the user manual for more details. + * + * Valid format for baseurlpath is: + * [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/] + * (note that it must end with a '/') + * + * The full url format is useful if your simpleSAMLphp setup is hosted behind + * a reverse proxy. In that case you can specify the external url here. + * + * Please note that simpleSAMLphp will then redirect all queries to the + * external url, no matter where you come from (direct access or via the + * reverse proxy). */ 'baseurlpath' => 'simplesaml/', 'certdir' => 'cert/', diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php index f0d1ece8ab80856caa9802b65a1f55e8f7293d28..ac86d2d3ffbbb587757a1318550780f544d94d29 100644 --- a/lib/SimpleSAML/Configuration.php +++ b/lib/SimpleSAML/Configuration.php @@ -337,14 +337,36 @@ class SimpleSAML_Configuration { return FALSE; } - - + /** + * Retrieve the absolute path of the simpleSAMLphp installation, + * relative to the root of the website. + * + * For example: simplesaml/ + * + * The path will always end with a '/' and never have a leading slash. + * + * @return string The absolute path relative to the root of the website. + */ public function getBaseURL() { - if (preg_match('/^\*(.*)$/D', $this->getString('baseurlpath', 'simplesaml/'), $matches)) { + $baseURL = $this->getString('baseurlpath', 'simplesaml/'); + + if (preg_match('/^\*(.*)$/D', $baseURL, $matches)) { + /* deprecated behaviour, will be removed in the future */ return SimpleSAML_Utilities::getFirstPathElement(false) . $matches[1]; } - return $this->getString('baseurlpath', 'simplesaml/'); + if (preg_match('#^https?://[^/]*/(.*)$#', $baseURL, $matches)) { + /* we have a full url, we need to strip the path */ + return $matches[1]; + } elseif (preg_match('#^/?([^/]?.*/)#D', $baseURL, $matches)) { + /* local path only */ + return $matches[1]; + } else { + /* invalid format */ + throw new SimpleSAML_Error_Exception('Incorrect format for option \'baseurlpath\'. Value is: "'. + $this->getString('baseurlpath', 'simplesaml/') . '". Valid format is in the form'. + ' [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/].'); + } } diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index e0feecd4005a4c69ce353bfe48d366e14cbc12a2..c522d120767d537ecbd1b1507a737b68d0b0e7bf 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -33,7 +33,21 @@ class SimpleSAML_Utilities { * Will return sp.example.org */ public static function getSelfHost() { + + $url = self::getBaseURL(); + + $start = strpos($url,'://') + 3; + $length = strcspn($url,'/:',$start); + + return substr($url, $start, $length); + + } + /** + * Retrieve Host value from $_SERVER environment variables + */ + private static function getServerHost() { + if (array_key_exists('HTTP_HOST', $_SERVER)) { $currenthost = $_SERVER['HTTP_HOST']; } elseif (array_key_exists('SERVER_NAME', $_SERVER)) { @@ -47,7 +61,8 @@ class SimpleSAML_Utilities { $currenthostdecomposed = explode(":", $currenthost); $currenthost = $currenthostdecomposed[0]; } - return $currenthost;# . self::getFirstPathElement() ; + return $currenthost; + } @@ -55,27 +70,15 @@ class SimpleSAML_Utilities { * Will return https://sp.example.org */ public static function selfURLhost() { - - $currenthost = self::getSelfHost(); - if (SimpleSAML_Utilities::isHTTPS()) { - $protocol = 'https'; - } else { - $protocol = 'http'; - } - - $portnumber = $_SERVER["SERVER_PORT"]; - $port = ':' . $portnumber; - if ($protocol == 'http') { - if ($portnumber == '80') $port = ''; - } elseif ($protocol == 'https') { - if ($portnumber == '443') $port = ''; - } - - $querystring = ''; - return $protocol."://" . $currenthost . $port; - + $url = self::getBaseURL(); + + $start = strpos($url,'://') + 3; + $length = strcspn($url,'/:',$start) + $start; + + return substr($url, 0, $length); } + /** * This function checks if we should set a secure cookie. @@ -84,8 +87,26 @@ class SimpleSAML_Utilities { */ public static function isHTTPS() { + $url = self::getBaseURL(); + + $end = strpos($url,'://'); + $protocol = substr($url, 0, $end); + + if ($protocol === 'https') { + return TRUE; + } else { + return FALSE; + } + + } + + /** + * retrieve HTTPS status from $_SERVER environment variables + */ + private static function getServerHTTPS() { + if(!array_key_exists('HTTPS', $_SERVER)) { - /* Not a https-request. */ + /* Not an https-request. */ return FALSE; } @@ -96,8 +117,30 @@ class SimpleSAML_Utilities { /* Otherwise, HTTPS will be a non-empty string. */ return $_SERVER['HTTPS'] !== ''; + } - + + + /** + * Retrieve port number from $_SERVER environment variables + * return it as a string such as ":80" if different from + * protocol default port, otherwise returns an empty string + */ + private static function getServerPort() { + + $portnumber = $_SERVER["SERVER_PORT"]; + $port = ':' . $portnumber; + + if (self::getServerHTTPS()) { + if ($portnumber == '443') $port = ''; + } else { + if ($portnumber == '80') $port = ''; + } + + return $port; + + } + /** * Will return https://sp.example.org/universities/ruc/baz/simplesaml/saml2/SSOService.php */ @@ -139,6 +182,7 @@ class SimpleSAML_Utilities { public static function selfURL() { + $selfURLhost = self::selfURLhost(); $requestURI = $_SERVER['REQUEST_URI']; @@ -150,14 +194,14 @@ class SimpleSAML_Utilities { } return $selfURLhost . $requestURI; + } /** - * Retrieve the absolute base URL for the simpleSAMLphp installation. + * Retrieve and return the absolute base URL for the simpleSAMLphp installation. * - * This function will return the absolute base URL for the simpleSAMLphp - * installation. For example: https://idp.example.org/simplesaml/ + * For example: https://idp.example.org/simplesaml/ * * The URL will always end with a '/'. * @@ -166,13 +210,35 @@ class SimpleSAML_Utilities { public static function getBaseURL() { $globalConfig = SimpleSAML_Configuration::getInstance(); - $ret = SimpleSAML_Utilities::selfURLhost() . '/' . $globalConfig->getBaseURL(); - if (substr($ret, -1) !== '/') { - throw new SimpleSAML_Error_Exception('Invalid value of \'baseurl\' in ' . - 'config.php. It must end with a \'/\'.'); + $baseURL = $globalConfig->getString('baseurlpath', 'simplesaml/'); + + if (preg_match('#^https?://([^/]*)/(.*)/$#D', $baseURL, $matches)) { + /* full url in baseurlpath, override local server values */ + return $baseURL; + } elseif ( + (preg_match('#^/?([^/]?.*/)$#D', $baseURL, $matches)) || + (preg_match('#^\*(.*)/$#D', $baseURL, $matches))) { + /* get server values */ + + if (self::getServerHTTPS()) { + $protocol = 'https://'; + } else { + $protocol = 'http://'; + } + + $hostname = self::getServerHost(); + $port = self::getServerPort(); + $path = $globalConfig->getBaseURL(); + if ($path[0] != '/') $path = '/' . $path; + + return $protocol.$hostname.$port.$path; + } else { + throw new SimpleSAML_Error_Exception('Invalid value of \'baseurl\' in '. + 'config.php. Valid format is in the form: '. + '[(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/]. '. + 'It must end with a \'/\'.'); } - return $ret; }