32 $session_id =
$session->getSessionId();
33 if (is_null($session_id)) {
35 throw new \SimpleSAML_Error_Exception(
'Cannot save POST data to a transient session.');
42 return preg_replace(
'#^https:#',
'http:',
$url);
56 if (array_key_exists(
'HTTP_HOST',
$_SERVER)) {
58 } elseif (array_key_exists(
'SERVER_NAME',
$_SERVER)) {
66 $decomposed = explode(
":",
$current);
67 $port = array_pop($decomposed);
68 if (!is_numeric($port)) {
69 array_push($decomposed, $port);
71 $current = implode(
":", $decomposed);
86 if (!array_key_exists(
'HTTPS',
$_SERVER)) {
111 $default_port = self::getServerHTTPS() ?
'443' :
'80';
112 $port = isset(
$_SERVER[
'SERVER_PORT']) ?
$_SERVER[
'SERVER_PORT'] : $default_port;
115 $port = strval($port);
117 if ($port !== $default_port) {
149 if (!is_string(
$url) || empty(
$url) || !is_array($parameters)) {
150 throw new \InvalidArgumentException(
'Invalid input parameters.');
152 if (!empty($parameters)) {
153 $url = self::addURLParameters(
$url, $parameters);
160 if (
$_SERVER[
'SERVER_PROTOCOL'] ===
'HTTP/1.1' &&
161 $_SERVER[
'REQUEST_METHOD'] ===
'POST' 168 if (strlen(
$url) > 2048) {
172 if (!headers_sent()) {
177 header(
'Pragma: no-cache');
178 header(
'Cache-Control: no-cache, no-store, must-revalidate');
182 echo '<?xml version="1.0" encoding="UTF-8"?>'.
"\n";
183 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"';
184 echo ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'.
"\n";
185 echo '<html xmlns="http://www.w3.org/1999/xhtml">'.
"\n";
187 echo ' <meta http-equiv="content-type" content="text/html; charset=utf-8">'.
"\n";
188 echo ' <meta http-equiv="refresh" content="0;URL=\''.htmlspecialchars(
$url).
'\'">'."\n
"; 189 echo " <title>Redirect</title>
\n"; 192 echo " <h1>Redirect</h1>
\n"; 193 echo ' <p>You were redirected to: <a id="redirlink
" href="'.htmlspecialchars($url).'">'; 194 echo htmlspecialchars($url)."</
a>
\n"; 195 echo ' <script type="text/javascript
">document.getElementById("redirlink
").focus();</script>'."\n"; 200 // end script execution 217 private static function savePOSTData(\SimpleSAML_Session $session, $destination, $data) 219 // generate a random ID to avoid replay attacks 220 $id = Random::generateID(); 223 'url' => $destination, 226 // save the post data to the session, tied to the random ID 227 $session->setData('core_postdatalink', $id, $postData); 246 public static function addURLParameters($url, $parameters) 248 if (!is_string($url) || !is_array($parameters)) { 249 throw new \InvalidArgumentException('Invalid input parameters.'); 252 $queryStart = strpos($url, '?'); 253 if ($queryStart === false) { 258 $oldQuery = substr($url, $queryStart + 1); 259 if ($oldQuery === false) { 262 $oldQuery = self::parseQueryString($oldQuery); 264 $url = substr($url, 0, $queryStart + 1); 268 $query = array_merge($oldQuery, $parameters); 269 $url .= http_build_query($query, '', '&'); 286 public static function checkSessionCookie($retryURL = null) 288 if (!is_null($retryURL) && !is_string($retryURL)) { 289 throw new \InvalidArgumentException('Invalid input parameters.'); 292 $session = \SimpleSAML_Session::getSessionFromRequest(); 293 if ($session->hasSessionCookie()) { 297 // we didn't have a session cookie. Redirect to the no-cookie page 299 $url = Module::getModuleURL('core/no_cookie.php'); 300 if ($retryURL !== null) { 301 $url = self::addURLParameters($url, array('retryURL' => $retryURL)); 303 self::redirectTrustedURL($url); 321 public static function checkURLAllowed($url, array $trustedSites = null) 326 $url = self::normalizeURL($url); 328 if (filter_var($url, FILTER_VALIDATE_URL) === false) { 329 throw new \SimpleSAML_Error_Exception('Invalid URL: '.$url); 332 // get the white list of domains 333 if ($trustedSites === null) { 334 $trustedSites = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.domains', array()); 337 // validates the URL's host is among those allowed 338 if (is_array($trustedSites)) { 339 assert(is_array($trustedSites)); 340 $components = parse_url($url); 341 $hostname = $components['host']; 343 // check for userinfo 344 if ((isset($components['user']) && strpos($components['user'], '\\') !== false) || 345 (isset($components['pass']) && strpos($components['pass'], '\\') !== false) 347 throw new \SimpleSAML_Error_Exception('Invalid URL: '.$url); 350 // allow URLs with standard ports specified (non-standard ports must then be allowed explicitly) 351 if (isset($components['port']) && 352 (($components['scheme'] === 'http' && $components['port'] !== 80) || 353 ($components['scheme'] === 'https' && $components['port'] !== 443)) 355 $hostname = $hostname.':'.$components['port']; 358 $self_host = self::getSelfHostWithNonStandardPort(); 360 $trustedRegex = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.regex', false); 364 // add self host to the white list 365 $trustedSites[] = preg_quote($self_host); 366 foreach ($trustedSites as $regex) { 367 // Add start and end delimiters. 368 $regex = "@^{$regex}$
@"; 369 if (preg_match($regex, $hostname)) { 375 // add self host to the white list 376 $trustedSites[] = $self_host; 377 $trusted = in_array($hostname, $trustedSites, true); 380 // throw exception due to redirection to untrusted site 382 throw new \SimpleSAML_Error_Exception('URL not allowed: '.$url); 408 public static function fetch($url, $context = array(), $getHeaders = false) 410 if (!is_string($url)) { 411 throw new \InvalidArgumentException('Invalid input parameters.'); 414 $config = \SimpleSAML_Configuration::getInstance(); 416 $proxy = $config->getString('proxy', null); 417 if ($proxy !== null) { 418 if (!isset($context['http']['proxy'])) { 419 $context['http']['proxy'] = $proxy; 421 $proxy_auth = $config->getString('proxy.auth', false); 422 if ($proxy_auth !== false) { 423 $context['http']['header'] = "Proxy-Authorization: Basic
".base64_encode($proxy_auth); 425 if (!isset($context['http']['request_fulluri'])) { 426 $context['http']['request_fulluri'] = true; 429 * If the remote endpoint over HTTPS uses the SNI extension (Server Name Indication RFC 4366), the proxy 430 * could introduce a mismatch between the names in the Host: HTTP header and the SNI_server_name in TLS 431 * negotiation (thanks to Cristiano Valli @ GARR-IDEM to have pointed this problem). 432 * See: https://bugs.php.net/bug.php?id=63519 433 * These controls will force the same value for both fields. 434 * Marco Ferrante (marco@csita.unige.it), Nov 2012 436 if (preg_match('#^https#i', $url) 437 && defined('OPENSSL_TLSEXT_SERVER_NAME') 438 && OPENSSL_TLSEXT_SERVER_NAME 440 // extract the hostname 441 $hostname = parse_url($url, PHP_URL_HOST); 442 if (!empty($hostname)) { 443 $context['ssl'] = array( 444 'SNI_server_name' => $hostname, 445 'SNI_enabled' => true, 448 Logger::warning('Invalid URL format or local URL used through a proxy'); 453 $context = stream_context_create($context); 454 $data = @file_get_contents($url, false, $context); 455 if ($data === false) { 456 $error = error_get_last(); 457 throw new \SimpleSAML_Error_Exception('Error fetching '.var_export($url, true).':'. 458 (is_array($error) ? $error['message'] : 'no error available')); 463 if (isset($http_response_header)) { 465 foreach ($http_response_header as $h) { 466 if (preg_match('@^HTTP/1\.[01]\s+\d{3}\s+@', $h)) { 467 $headers = array(); // reset 471 $bits = explode(':', $h, 2); 472 if (count($bits) === 2) { 473 $headers[strtolower($bits[0])] = trim($bits[1]); 477 // no HTTP headers, probably a different protocol, e.g. file 480 return array($data, $headers); 498 public static function getAcceptLanguage() 500 if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) { 501 // no Accept-Language header, return an empty set 505 $languages = explode(',', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); 509 foreach ($languages as $l) { 510 $opts = explode(';', $l); 512 $l = trim(array_shift($opts)); // the language is the first element 516 // iterate over all options, and check for the quality option 517 foreach ($opts as $o) { 518 $o = explode('=', $o); 520 // skip option with no value 525 $value = trim($o[1]); 532 // remove the old key to ensure that the element is added to the end 535 // set the quality in the result 538 if (strpos($l, '-')) { 539 // the language includes a region part 541 // extract the language without the region 542 $l = explode('-', $l); 545 // add this language to the result (unless it is defined already) 546 if (!array_key_exists($l, $ret)) { 562 public static function guessBasePath() 564 if (!array_key_exists('REQUEST_URI', $_SERVER) || !array_key_exists('SCRIPT_FILENAME', $_SERVER)) { 567 // get the name of the current script 568 $path = explode('/', $_SERVER['SCRIPT_FILENAME']); 569 $script = array_pop($path); 571 // get the portion of the URI up to the script, i.e.: /simplesaml/some/directory/script.php 572 if (!preg_match('#^/(?:[^/]+/)*'.$script.'#', $_SERVER['REQUEST_URI'], $matches)) { 575 $uri_s = explode('/', $matches[0]); 576 $file_s = explode('/', $_SERVER['SCRIPT_FILENAME']); 578 // compare both arrays from the end, popping elements matching out of them 579 while ($uri_s[count($uri_s) - 1] === $file_s[count($file_s) - 1]) { 583 // we are now left with the minimum part of the URI that does not match anything in the file system, use it 584 return join('/', $uri_s).'/'; 597 public static function getBaseURL() 599 $globalConfig = \SimpleSAML_Configuration::getInstance(); 600 $baseURL = $globalConfig->getString('baseurlpath', 'simplesaml/'); 602 if (preg_match('#^https?://.*/?$#D', $baseURL, $matches)) { 603 // full URL in baseurlpath, override local server values 604 return rtrim($baseURL, '/').'/'; 605 } elseif ((preg_match('#^/?([^/]?.*/)$#D', $baseURL, $matches)) || 606 (preg_match('#^\*(.*)/$#D', $baseURL, $matches)) || 611 $protocol .= (self::getServerHTTPS()) ? 's' : ''; 614 $hostname = self::getServerHost(); 615 $port = self::getServerPort(); 616 $path = $globalConfig->getBasePath(); 618 return $protocol.$hostname.$port.$path; 621 * Invalid 'baseurlpath'. We cannot recover from this, so throw a critical exception and try to be graceful 622 * with the configuration. Use a guessed base path instead of the one provided. 624 $c = $globalConfig->toArray(); 625 $c['baseurlpath'] = self::guessBasePath(); 626 throw new \SimpleSAML\Error\CriticalConfigurationError( 627 'Invalid value for \'baseurlpath\' in config.php. Valid format is in the form: '. 628 '[(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/]. It must end with a \'/\'.', 645 public static function getFirstPathElement($trailingslash = true) 647 if (preg_match('|^/(.*?)/|', $_SERVER['SCRIPT_NAME'], $matches)) { 648 return ($trailingslash ? '/' : '').$matches[1]; 666 public static function getPOSTRedirectURL($destination, $data) 668 if (!is_string($destination) || !is_array($data)) { 669 throw new \InvalidArgumentException('Invalid input parameters.'); 672 $config = \SimpleSAML_Configuration::getInstance(); 673 $allowed = $config->getBoolean('enable.http_post', false); 675 if ($allowed && preg_match("#^
http:#
", $destination) && self::isHTTPS()) { 676 // we need to post the data to HTTP 677 $url = self::getSecurePOSTRedirectURL($destination, $data); 678 } else { // post the data directly 679 $session = \SimpleSAML_Session::getSessionFromRequest(); 680 $id = self::savePOSTData($session, $destination, $data); 681 $url = Module::getModuleURL('core/postredirect.php', array('RedirId' => $id)); 697 public static function getSelfHost() 699 $decomposed = explode(':', self::getSelfHostWithNonStandardPort()); 700 return array_shift($decomposed); 715 public static function getSelfHostWithNonStandardPort() 717 $url = self::getBaseURL(); 720 $colon = strpos($url, '://'); 722 $length = strcspn($url, '/', $start); 724 return substr($url, $start, $length); 736 public static function getSelfHostWithPath() 738 $baseurl = explode("/
", self::getBaseURL()); 739 $elements = array_slice($baseurl, 3 - count($baseurl), count($baseurl) - 4); 740 $path = implode("/
", $elements); 741 return self::getSelfHostWithNonStandardPort()."/
".$path; 760 public static function getSelfURL() 762 $cfg = \SimpleSAML_Configuration::getInstance(); 763 $baseDir = $cfg->getBaseDir(); 764 $cur_path = realpath($_SERVER['SCRIPT_FILENAME']); 765 // make sure we got a string from realpath() 766 $cur_path = is_string($cur_path) ? $cur_path : ''; 767 // find the path to the current script relative to the www/ directory of SimpleSAMLphp 768 $rel_path = str_replace($baseDir.'www'.DIRECTORY_SEPARATOR, '', $cur_path); 769 // convert that relative path to an HTTP query 770 $url_path = str_replace(DIRECTORY_SEPARATOR, '/', $rel_path); 771 // find where the relative path starts in the current request URI 772 $uri_pos = (!empty($url_path)) ? strpos($_SERVER['REQUEST_URI'], $url_path) : false; 774 if ($cur_path == $rel_path || $uri_pos === false) { 776 * We were accessed from an external script. This can happen in the following cases: 778 * - $_SERVER['SCRIPT_FILENAME'] points to a script that doesn't exist. E.g. functional testing. In this 779 * case, realpath() returns false and str_replace an empty string, so we compare them loosely. 781 * - The URI requested does not belong to a script in the www/ directory of SimpleSAMLphp. In that case, 782 * removing SimpleSAMLphp's base dir from the current path yields the same path, so $cur_path and 783 * $rel_path are equal. 785 * - The request URI does not match the current script. Even if the current script is located in the www/ 786 * directory of SimpleSAMLphp, the URI does not contain its relative path, and $uri_pos is false. 788 * It doesn't matter which one of those cases we have. We just know we can't apply our base URL to the 789 * current URI, so we need to build it back from the PHP environment, unless we have a base URL specified 790 * for this case in the configuration. First, check if that's the case. 794 $appcfg = $cfg->getConfigItem('application', null); 795 $appurl = ($appcfg instanceof \SimpleSAML_Configuration) ? $appcfg->getString('baseURL', '') : ''; 796 if (!empty($appurl)) { 797 $protocol = parse_url($appurl, PHP_URL_SCHEME); 798 $hostname = parse_url($appurl, PHP_URL_HOST); 799 $port = parse_url($appurl, PHP_URL_PORT); 800 $port = !empty($port) ? ':'.$port : ''; 801 } else { // no base URL specified for app, just use the current URL 803 $protocol .= (self::getServerHTTPS()) ? 's' : ''; 804 $hostname = self::getServerHost(); 805 $port = self::getServerPort(); 807 return $protocol.'://'.$hostname.$port.$_SERVER['REQUEST_URI']; 810 return self::getBaseURL().$url_path.substr($_SERVER['REQUEST_URI'], $uri_pos + strlen($url_path)); 823 public static function getSelfURLHost() 825 $url = self::getSelfURL(); 828 $colon = strpos($url, '://'); 830 $length = strcspn($url, '/', $start) + $start; 831 return substr($url, 0, $length); 843 public static function getSelfURLNoQuery() 845 $url = self::getSelfURL(); 846 $pos = strpos($url, '?'); 850 return substr($url, 0, $pos); 862 public static function isHTTPS() 864 return strpos(self::getSelfURL(), 'https://') === 0; 880 public static function normalizeURL($url) 882 if (!is_string($url)) { 883 throw new \InvalidArgumentException('Invalid input parameters.'); 886 $url = self::resolveURL($url, self::getSelfURL()); 888 // verify that the URL is to a http or https site 889 if (!preg_match('@^https?://@i', $url)) { 890 throw new \InvalidArgumentException('Invalid URL: '.$url); 912 public static function parseQueryString($query_string) 914 if (!is_string($query_string)) { 915 throw new \InvalidArgumentException('Invalid input parameters.'); 919 if (empty($query_string)) { 923 foreach (explode('&', $query_string) as $param) { 924 $param = explode('=', $param); 925 $name = urldecode($param[0]); 926 if (count($param) === 1) { 929 $value = urldecode($param[1]); 931 $res[$name] = $value; 959 public static function redirectTrustedURL($url, $parameters = array()) 961 if (!is_string($url) || !is_array($parameters)) { 962 throw new \InvalidArgumentException('Invalid input parameters.'); 965 $url = self::normalizeURL($url); 966 self::redirect($url, $parameters); 991 public static function redirectUntrustedURL($url, $parameters = array()) 993 if (!is_string($url) || !is_array($parameters)) { 994 throw new \InvalidArgumentException('Invalid input parameters.'); 997 $url = self::checkURLAllowed($url); 998 self::redirect($url, $parameters); 1023 public static function resolveURL($url, $base = null) 1025 if ($base === null) { 1026 $base = self::getBaseURL(); 1029 if (!is_string($url) || !is_string($base)) { 1030 throw new \InvalidArgumentException('Invalid input parameters.'); 1033 if (!preg_match('/^((((\w+:)\/\/[^\/]+)(\/[^?#]*))(?:\?[^#]*)?)(?:#.*)?/', $base, $baseParsed)) { 1034 throw new \InvalidArgumentException('Unable to parse base url: '.$base); 1037 $baseDir = dirname($baseParsed[5].'filename'); 1038 $baseScheme = $baseParsed[4]; 1039 $baseHost = $baseParsed[3]; 1040 $basePath = $baseParsed[2]; 1041 $baseQuery = $baseParsed[1]; 1043 if (preg_match('$^\w+:$', $url)) { 1047 if (substr($url, 0, 2) === '//') { 1048 return $baseScheme.$url; 1051 if ($url[0] === '/') { 1052 return $baseHost.$url; 1054 if ($url[0] === '?') { 1055 return $basePath.$url; 1057 if ($url[0] === '#') { 1058 return $baseQuery.$url; 1061 // we have a relative path. Remove query string/fragment and save it as $tail 1062 $queryPos = strpos($url, '?'); 1063 $fragmentPos = strpos($url, '#'); 1064 if ($queryPos !== false || $fragmentPos !== false) { 1065 if ($queryPos === false) { 1066 $tailPos = $fragmentPos; 1067 } elseif ($fragmentPos === false) { 1068 $tailPos = $queryPos; 1069 } elseif ($queryPos < $fragmentPos) { 1070 $tailPos = $queryPos; 1072 $tailPos = $fragmentPos; 1075 $tail = substr($url, $tailPos); 1076 $dir = substr($url, 0, $tailPos); 1082 $dir = System::resolvePath($dir, $baseDir); 1084 return $baseHost.$dir.$tail; 1104 public static function setCookie($name, $value, $params = null, $throw = true) 1106 if (!(is_string($name) && // $name must be a string 1107 (is_string($value) || is_null($value)) && // $value can be a string or null 1108 (is_array($params) || is_null($params)) && // $params can be an array or null 1109 is_bool($throw)) // $throw must be boolean 1111 throw new \InvalidArgumentException('Invalid input parameters.'); 1114 $default_params = array( 1124 if ($params !== null) { 1125 $params = array_merge($default_params, $params); 1127 $params = $default_params; 1130 // Do not set secure cookie if not on HTTPS 1131 if ($params['secure'] && !self::isHTTPS()) { 1133 throw new \SimpleSAML\Error\CannotSetCookie( 1134 'Setting secure cookie on plain HTTP is not allowed.', 1135 \SimpleSAML\Error\CannotSetCookie::SECURE_COOKIE 1138 Logger::warning('Error setting cookie: setting secure cookie on plain HTTP is not allowed.'); 1142 if ($value === null) { 1143 $expire = time() - 365 * 24 * 60 * 60; 1144 } elseif (isset($params['expire'])) { 1145 $expire = $params['expire']; 1146 } elseif ($params['lifetime'] === 0) { 1149 $expire = time() + $params['lifetime']; 1152 if ($params['raw']) { 1153 $success = @setrawcookie( 1163 $success = @setcookie( 1176 throw new \SimpleSAML\Error\CannotSetCookie( 1177 'Headers already sent.', 1178 \SimpleSAML\Error\CannotSetCookie::HEADERS_SENT 1181 Logger::warning('Error setting cookie: headers already sent.'); 1202 public static function submitPOSTData($destination, $data) 1204 if (!is_string($destination) || !is_array($data)) { 1205 throw new \InvalidArgumentException('Invalid input parameters.'); 1208 $config = \SimpleSAML_Configuration::getInstance(); 1209 $allowed = $config->getBoolean('enable.http_post', false); 1211 if ($allowed && preg_match("#^
http:#
", $destination) && self::isHTTPS()) { 1212 // we need to post the data to HTTP 1213 self::redirect(self::getSecurePOSTRedirectURL($destination, $data)); 1216 $p = new \SimpleSAML_XHTML_Template($config, 'post.php'); 1217 $p->data['destination'] = $destination; 1218 $p->data['post'] = $data; static redirect($url, $parameters=array())
This function redirects the user to the specified address.
static getServerHost()
Retrieve Host value from $_SERVER environment variables.
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
static getServerHTTPS()
Retrieve HTTPS status from $_SERVER environment variables.
static aesEncrypt($data)
Encrypt data using AES-256-CBC and the system-wide secret salt as key.
if(!array_key_exists('StateId', $_REQUEST)) $id
if(! $in) print Initializing normalization quick check tables n
static getModuleURL($resource, array $parameters=array())
Get absolute URL to a specified module resource.
static http()
Fetches the global http state from ILIAS.
static getServerPort()
Retrieve the port number from $_SERVER environment variables.
static getSecurePOSTRedirectURL($destination, $data)
Obtain a URL where we can redirect to securely post a form with the given data to a specific destinat...
static getSessionFromRequest()
Retrieves the current session.