diff --git a/config-templates/config.php b/config-templates/config.php index 66d1cf49e520959a3c9b754d1a18eb90b2fdb23a..989273329f8e6f801532b9073d4a3875ceb1a32b 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -701,13 +701,26 @@ $config = array ( 'proxy' => NULL, /* - * Array of URL's to allow a trusted redirect to. + * Array of domains that are allowed when generating links or redirections + * to URLs. simpleSAMLphp will use this option to determine whether to + * to consider a given URL valid or not, but you should always validate + * URLs obtained from the input on your own (i.e. ReturnTo or RelayState + * parameters obtained from the $_REQUEST array). * - * Set to NULL to disable. + * Set to NULL to disable checking of URLs. + * + * simpleSAMLphp will automatically add your own domain (either by checking + * it dinamically, or by using the domain defined in the 'baseurlpath' + * directive, the latter having precedence) to the list of trusted domains, + * in case this option is NOT set to NULL. In that case, you are explicitly + * telling simpleSAMLphp to verify URLs. + * + * Set to an empty array to disallow ALL redirections or links pointing to + * an external URL other than your own domain. * * Example: - * 'redirect.trustedsites' => array('sp.example.com', 'othersite.org'), + * 'trusted.url.domains' => array('sp.example.com', 'app.example.com'), */ - 'redirect.trustedsites' => NULL, + 'trusted.url.domains' => NULL, ); diff --git a/docs/simplesamlphp-sp-migration.txt b/docs/simplesamlphp-sp-migration.txt index 72a165e71a07ffd4cff1ed7a7f7566ffa60da17b..7b425e0e0dd48da8c041d8351a7947ad1aaa6734 100644 --- a/docs/simplesamlphp-sp-migration.txt +++ b/docs/simplesamlphp-sp-migration.txt @@ -209,6 +209,9 @@ If you want to return to a specific URL after logging out, you should include th $as->logout('https://example.org/'); +Please make sure the URL is trusted. If you obtain the URL from the user input, make sure it is trusted before +calling $as->logout(), by using the SimpleSAML_Utilities::checkURLAllowed() method. + #### Login link diff --git a/lib/SimpleSAML/Auth/BWC.php b/lib/SimpleSAML/Auth/BWC.php index 290c514b506e31d30f4af255e2a017188dbff135..923e9789a90d38f2b6c543e1289aa9da45c27411 100644 --- a/lib/SimpleSAML/Auth/BWC.php +++ b/lib/SimpleSAML/Auth/BWC.php @@ -143,19 +143,19 @@ class SimpleSAML_Auth_BWC extends SimpleSAML_Auth_Simple { $session = SimpleSAML_Session::getInstance(); if (!$session->isValid($this->authority)) { /* Not authenticated to this authentication source. */ - SimpleSAML_Utilities::redirectUntrustedURL($url); + SimpleSAML_Utilities::redirectTrustedURL($url); assert('FALSE'); } if ($this->authority === 'saml2') { $config = SimpleSAML_Configuration::getInstance(); - SimpleSAML_Utilities::redirectUntrustedURL('/' . $config->getBaseURL() . 'saml2/sp/initSLO.php', + SimpleSAML_Utilities::redirectTrustedURL('/' . $config->getBaseURL() . 'saml2/sp/initSLO.php', array('RelayState' => $url) ); } $session->doLogout($this->authority); - SimpleSAML_Utilities::redirectUntrustedURL($url); + SimpleSAML_Utilities::redirectTrustedURL($url); } } diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php index 34686aa2d0926feb1a3bfc2715467113fa36bfc1..ca02e748eca51984f49c8bb39766dca55f415a89 100644 --- a/lib/SimpleSAML/Auth/Default.php +++ b/lib/SimpleSAML/Auth/Default.php @@ -19,13 +19,21 @@ class SimpleSAML_Auth_Default { * This function never returns. * * @param string $authId The identifier of the authentication source. - * @param string|array $return The URL or function we should direct the user to after authentication. - * @param string|NULL $errorURL The URL we should direct the user to after failed authentication. - * Can be NULL, in which case a standard error page will be shown. - * @param array $params Extra information about the login. Different authentication requestors may - * provide different information. Optional, will default to an empty array. + * @param string|array $return The URL or function we should direct the + * user to after authentication. If using a URL obtained from user input, + * please make sure to check it by calling + * SimpleSAML_Utilities::checkURLAllowed(). + * @param string|NULL $errorURL The URL we should direct the user to after + * failed authentication. Can be NULL, in which case a standard error page + * will be shown. If using a URL obtained from user input, please make sure + * to check it by calling SimpleSAML_Utilities::checkURLAllowed(). + * @param array $params Extra information about the login. Different + * authentication requestors may provide different information. Optional, + * will default to an empty array. */ - public static function initLogin($authId, $return, $errorURL = NULL, array $params = array()) { + public static function initLogin($authId, $return, $errorURL = NULL, + array $params = array()) { + assert('is_string($authId)'); assert('is_string($return) || is_array($return)'); assert('is_string($errorURL) || is_null($errorURL)'); @@ -121,7 +129,7 @@ class SimpleSAML_Auth_Default { if (is_string($return)) { /* Redirect... */ - SimpleSAML_Utilities::redirectUntrustedURL($return); + SimpleSAML_Utilities::redirectTrustedURL($return); } else { call_user_func($return, $state); assert('FALSE'); @@ -132,11 +140,16 @@ class SimpleSAML_Auth_Default { /** * Start logout. * - * This function starts a logout operation from the current authentication source. This function - * will return if the logout operation does not require a redirect. + * This function starts a logout operation from the current authentication + * source. This function will return if the logout operation does not + * require a redirect. * - * @param string $returnURL The URL we should redirect the user to after logging out. - * @param string|NULL $authority The authentication source we are logging out from, or NULL to log out of the most recent. + * @param string $returnURL The URL we should redirect the user to after + * logging out. No checking is performed on the URL, so make sure to verify + * it on beforehand if the URL is obtained from user input. Refer to + * SimpleSAML_Utilities::checkURLAllowed() for more information. + * @param string|NULL $authority The authentication source we are logging + * out from, or NULL to log out from the most recent. */ public static function initLogoutReturn($returnURL, $authority = NULL) { assert('is_string($returnURL)'); @@ -171,11 +184,16 @@ class SimpleSAML_Auth_Default { /** * Start logout. * - * This function starts a logout operation from the current authentication source. This function - * never returns. + * This function starts a logout operation from the current authentication + * source. This function never returns. * - * @param string $returnURL The URL we should redirect the user to after logging out. - * @param string|NULL $authority The authentication source we are logging out from, or NULL to log out of the most recent. + * @param string $returnURL The URL we should redirect the user to after + * logging out. No checking is performed on the URL, so make sure to verify + * it on beforehand if the URL is obtained from user input. Refer to + * SimpleSAML_Utilities::checkURLAllowed() for more information. + * @param string|NULL $authority The authentication source we are logging + * out from, or NULL to log out from the most recent. + * @return void This function never returns. */ public static function initLogout($returnURL, $authority = NULL) { assert('is_string($returnURL)'); @@ -184,7 +202,7 @@ class SimpleSAML_Auth_Default { self::initLogoutReturn($returnURL, $authority); /* Redirect... */ - SimpleSAML_Utilities::redirectUntrustedURL($returnURL); + SimpleSAML_Utilities::redirectTrustedURL($returnURL); } @@ -202,7 +220,7 @@ class SimpleSAML_Auth_Default { $returnURL = $state['SimpleSAML_Auth_Default.ReturnURL']; /* Redirect... */ - SimpleSAML_Utilities::redirectUntrustedURL($returnURL); + SimpleSAML_Utilities::redirectTrustedURL($returnURL); } @@ -239,10 +257,14 @@ class SimpleSAML_Auth_Default { * * This is used to handle IdP initiated SSO. * - * @param string $authId The id of the authentication source that received the request. - * @param array $state A state array. - * @param string $redirectTo The URL we should redirect the user to after - * updating the session. + * @param string $authId The id of the authentication source that received + * the request. + * @param array $state A state array. + * @param string $redirectTo The URL we should redirect the user to after + * updating the session. The function will check if the URL is allowed, so + * there is no need to manually check the URL on beforehand. Please refer + * to the 'trusted.url.domains' configuration directive for more + * information about allowing (or disallowing) URLs. */ public static function handleUnsolicitedAuth($authId, array $state, $redirectTo) { assert('is_string($authId)'); diff --git a/lib/SimpleSAML/Auth/ProcessingChain.php b/lib/SimpleSAML/Auth/ProcessingChain.php index da04532642d0cff4679236166f29aca9e6c7fb6b..1b60e3326a82d25dae1125d4bf0a763e24d14e65 100644 --- a/lib/SimpleSAML/Auth/ProcessingChain.php +++ b/lib/SimpleSAML/Auth/ProcessingChain.php @@ -248,7 +248,7 @@ class SimpleSAML_Auth_ProcessingChain { * in $state['ReturnURL']. */ $id = SimpleSAML_Auth_State::saveState($state, self::COMPLETED_STAGE); - SimpleSAML_Utilities::redirectUntrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id)); + SimpleSAML_Utilities::redirectTrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id)); } else { /* Pass the state to the function defined in $state['ReturnCall']. */ @@ -302,8 +302,11 @@ class SimpleSAML_Auth_ProcessingChain { /** * Retrieve a state which has finished processing. * - * @param string $id The identifier of the state. This can be found in the request parameter - * with index from SimpleSAML_Auth_ProcessingChain::AUTHPARAM. + * @param string $id The state identifier. This can be found in the + * SimpleSAML_Auth_ProcessingChain::AUTHPARAM request parameter. Please + * make sure to sanitize it properly by calling the + * SimpleSAML_Utilities::checkURLAllowed() function with the embedded + * restart URL, if any. See also SimpleSAML_Utilities::getURLFromStateID(). */ public static function fetchProcessedState($id) { assert('is_string($id)'); @@ -351,5 +354,3 @@ class SimpleSAML_Auth_ProcessingChain { } } - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/Auth/Simple.php b/lib/SimpleSAML/Auth/Simple.php index 8577379e88e7d24a9f9c06314edc79081361f395..4f7d8fb057ef0b0aa53294693f53c8dd3eb83d93 100644 --- a/lib/SimpleSAML/Auth/Simple.php +++ b/lib/SimpleSAML/Auth/Simple.php @@ -219,7 +219,7 @@ class SimpleSAML_Auth_Simple { $params[$state['ReturnStateParam']] = $stateID; } - SimpleSAML_Utilities::redirectUntrustedURL($state['ReturnTo'], $params); + SimpleSAML_Utilities::redirectTrustedURL($state['ReturnTo'], $params); } } diff --git a/lib/SimpleSAML/Auth/State.php b/lib/SimpleSAML/Auth/State.php index 57387665d8045fe115ee2e8bd21d8983dd4063b7..0b74da24c533a9ec61259bd20b6c81f74d0f4486 100644 --- a/lib/SimpleSAML/Auth/State.php +++ b/lib/SimpleSAML/Auth/State.php @@ -211,13 +211,7 @@ class SimpleSAML_Auth_State { assert('is_bool($allowMissing)'); SimpleSAML_Logger::debug('Loading state: ' . var_export($id, TRUE)); - $tmp = explode(':', $id, 2); - $id = $tmp[0]; - if (count($tmp) === 2) { - $restartURL = $tmp[1]; - } else { - $restartURL = NULL; - } + $restartURL = SimpleSAML_Utilities::getURLFromStateID($id); $session = SimpleSAML_Session::getInstance(); $state = $session->getData('SimpleSAML_Auth_State', $id); diff --git a/lib/SimpleSAML/IdP.php b/lib/SimpleSAML/IdP.php index 630662dd752895131050ef9f3898cec75f2c7d7d..d94c4274acfd1e602d776fac35bd0d343310fb72 100644 --- a/lib/SimpleSAML/IdP.php +++ b/lib/SimpleSAML/IdP.php @@ -529,7 +529,7 @@ class SimpleSAML_IdP { public static function finishLogoutRedirect(SimpleSAML_IdP $idp, array $state) { assert('isset($state["core:Logout:URL"])'); - SimpleSAML_Utilities::redirectUntrustedURL($state['core:Logout:URL']); + SimpleSAML_Utilities::redirectTrustedURL($state['core:Logout:URL']); assert('FALSE'); } diff --git a/lib/SimpleSAML/IdP/LogoutTraditional.php b/lib/SimpleSAML/IdP/LogoutTraditional.php index 86ce301e9a717169bd52cfb41a029c4c2c6e4531..f9fa132f7ae9440421863a982a4e870f3e258f19 100644 --- a/lib/SimpleSAML/IdP/LogoutTraditional.php +++ b/lib/SimpleSAML/IdP/LogoutTraditional.php @@ -76,6 +76,12 @@ class SimpleSAML_IdP_LogoutTraditional extends SimpleSAML_IdP_LogoutHandler { throw new SimpleSAML_Error_Exception('RelayState lost during logout.'); } + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($relayState); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $state = SimpleSAML_Auth_State::loadState($relayState, 'core:LogoutTraditional'); if ($error === NULL) { diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index 0b37bf839d4bcde52a9266109c0ea8ab0b5842e3..cd7ef1f2877421f25b863d0605bab23c8e54496f 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -298,17 +298,80 @@ class SimpleSAML_Utilities { } + /** + * Check if a URL is valid and is in our list of allowed URLs. + * + * @param string $url The URL to check. + * @param array $trustedSites An optional white list of domains. If none + * specified, the 'trusted.url.domains' configuration directive will be + * used. + * @return string The normalized URL itself if it is allowed. + * @throws SimpleSAML_Error_Exception if the URL is malformed or is not + * allowed by configuration. + */ + public static function checkURLAllowed($url, array $trustedSites = NULL) { + $url = self::normalizeURL($url); + + // verify that the URL points to an http or https site + if (!preg_match('@^https?://@i', $url)) { + throw new SimpleSAML_Error_Exception('Invalid URL: '.$url); + } + + // get the white list of domains + if ($trustedSites === NULL) { + $trustedSites = SimpleSAML_Configuration::getInstance()->getArray('trusted.url.domains', NULL); + if ($trustedSites === NULL) { + $trustedSites = SimpleSAML_Configuration::getInstance()->getArray('redirect.trustedsites', NULL); + } + } + + // validates the URL's host is among those allowed + if ($trustedSites !== NULL) { + assert(is_array($trustedSites)); + preg_match('@^https?://([^/]+)@i', $url, $matches); + $hostname = $matches[1]; + + // add self host to the white list + $self_host = self::getSelfHost(); + $trustedSites[] = $self_host; + + /* Throw exception due to redirection to untrusted site */ + if (!in_array($hostname, $trustedSites)) { + throw new SimpleSAML_Error_Exception('URL not allowed: '.$url); + } + } + return $url; + } + + + /** + * Get a URL embedded in a StateID, in the form 'id:url'. + * + * @param string $stateId The state ID to use. + * @return string The embedded URL if found, NULL otherwise. + */ + public static function getURLFromStateID($stateId) { + $tmp = explode(':', $stateId, 2); + $id = $tmp[0]; + $url = NULL; + if (count($tmp) === 2) { + $url = $tmp[1]; + } + return $url; + } + + public static function checkDateConditions($start=NULL, $end=NULL) { $currentTime = time(); - if (! empty($start)) { + if (!empty($start)) { $startTime = SAML2_Utils::parseSAML2Time($start); /* Allow for a 10 minute difference in Time */ if (($startTime < 0) || (($startTime - 600) > $currentTime)) { return FALSE; } } - if (! empty($end)) { + if (!empty($end)) { $endTime = SAML2_Utils::parseSAML2Time($end); if (($endTime < 0) || ($endTime <= $currentTime)) { return FALSE; @@ -493,113 +556,20 @@ class SimpleSAML_Utilities { return true; } - - /** - * This function redirects the user to the specified address. - * - * This function will use the "HTTP 303 See Other" redirection if the - * current request used the POST method and the HTTP version is 1.1. - * Otherwise, a "HTTP 302 Found" redirection will be used. - * - * The fuction will also generate a simple web page with a clickable - * link to the target page. - * - * @param string $url The URL we should redirect to. This URL may include - * query parameters. If this URL is a relative URL (starting with '/'), - * then it will be turned into an absolute URL by prefixing it with the - * absolute URL to the root of the website. - * @param string[] $parameters An array with extra query string parameters - * which should be appended to the URL. The name of the parameter is the - * array index. The value of the parameter is the value stored in the index. - * Both the name and the value will be urlencoded. If the value is NULL, - * then the parameter will be encoded as just the name, without a value. - * @param string[] $allowed_redirect_hosts An array with a whitelist of - * hosts for which redirects are allowed. If NULL, redirections will be - * allowed to any host. Otherwise, the host of the $url provided must be - * present in this parameter. If the host is not whitelisted, an exception - * will be thrown. - * - * @return void This function never returns. - * @deprecated 1.12.0 This function will be removed from the API. Use - * accordingly the redirectTrustedURL or redirectUntrustedURL functions - * instead. + /* + * This is a temporary function, holding the redirect() functionality, + * meanwhile we are deprecating the it. */ - public static function redirect($url, $parameters = array(), $allowed_redirect_hosts = NULL) { - assert(is_string($url)); - assert(strlen($url) > 0); - assert(is_array($parameters)); - if($allowed_redirect_hosts != NULL) assert(is_array($allowed_redirect_hosts)); - - /* Check for relative URL. */ - if(substr($url, 0, 1) === '/') { - /* Prefix the URL with the url to the root of the - * website. - */ - $url = self::selfURLhost() . $url; + private static function _doRedirect($url, $parameters = array()) { + if (!empty($parameters)) { + $url = self::addURLparameter($url, $parameters); } - /* Verify that the URL points to an http or https site. */ - if (!preg_match('@^https?://@i', $url)) { - throw new SimpleSAML_Error_Exception('Redirect to invalid URL: ' . $url); - } - - /* Validates the URL's host is among those allowed. */ - if ($allowed_redirect_hosts !== NULL) { - preg_match('@^https?://([^/]+)@i', $url, $matches); - $hostname = $matches[1]; - - // add self host to the white list - $self_host = self::getSelfHost(); - $allowed_redirect_hosts[] = $self_host; - - /* Throw exception due to redirection to untrusted site */ - if(!in_array($hostname, $allowed_redirect_hosts)) { - throw new SimpleSAML_Error_Exception('Redirection not to allowed to URL: ' . $url); - } - } - - /* Determine which prefix we should put before the first - * parameter. - */ - if(strpos($url, '?') === FALSE) { - $paramPrefix = '?'; - } else { - $paramPrefix = '&'; - } - - /* Iterate over the parameters and append them to the query - * string. - */ - foreach($parameters as $name => $value) { - - /* Encode the parameter. */ - if($value === NULL) { - $param = urlencode($name); - } elseif (is_array($value)) { - $param = ""; - foreach ($value as $val) { - $param .= urlencode($name) . "[]=" . urlencode($val) . '&'; - } - } else { - $param = urlencode($name) . '=' . - urlencode($value); - } - - /* Append the parameter to the query string. */ - $url .= $paramPrefix . $param; - - /* Every following parameter is guaranteed to follow - * another parameter. Therefore we use the '&' prefix. - */ - $paramPrefix = '&'; - } - - /* Set the HTTP result code. This is either 303 See Other or * 302 Found. HTTP 303 See Other is sent if the HTTP version * is HTTP/1.1 and the request type was a POST request. */ - if($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1' && + if ($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1' && $_SERVER['REQUEST_METHOD'] === 'POST') { $code = 303; } else { @@ -630,7 +600,8 @@ class SimpleSAML_Utilities { echo '<h1>Redirect</h1>'; echo '<p>'; echo 'You were redirected to: '; - echo '<a id="redirlink" href="' . htmlspecialchars($url) . '">' . htmlspecialchars($url) . '</a>'; + echo '<a id="redirlink" href="' . + htmlspecialchars($url) . '">' . htmlspecialchars($url) . '</a>'; echo '<script type="text/javascript">document.getElementById("redirlink").focus();</script>'; echo '</p>'; echo '</body>'; @@ -638,6 +609,51 @@ class SimpleSAML_Utilities { /* End script execution. */ exit; + } + + + /** + * This function redirects the user to the specified address. + * + * This function will use the "HTTP 303 See Other" redirection if the + * current request used the POST method and the HTTP version is 1.1. + * Otherwise, a "HTTP 302 Found" redirection will be used. + * + * The fuction will also generate a simple web page with a clickable + * link to the target page. + * + * @param string $url The URL we should redirect to. This URL may include + * query parameters. If this URL is a relative URL (starting with '/'), + * then it will be turned into an absolute URL by prefixing it with the + * absolute URL to the root of the website. + * @param string[] $parameters An array with extra query string parameters + * which should be appended to the URL. The name of the parameter is the + * array index. The value of the parameter is the value stored in the index. + * Both the name and the value will be urlencoded. If the value is NULL, + * then the parameter will be encoded as just the name, without a value. + * @param string[] $allowed_redirect_hosts An array with a whitelist of + * hosts for which redirects are allowed. If NULL, redirections will be + * allowed to any host. Otherwise, the host of the $url provided must be + * present in this parameter. If the host is not whitelisted, an exception + * will be thrown. + * + * @return void This function never returns. + * @deprecated 1.12.0 This function will be removed from the API. Instead, + * use the redirectTrustedURL or redirectUntrustedURL functions + * accordingly. + */ + public static function redirect($url, $parameters = array(), + $allowed_redirect_hosts = NULL) { + + assert(is_string($url)); + assert(strlen($url) > 0); + assert(is_array($parameters)); + + $url = self::normalizeURL($url); + if ($allowed_redirect_hosts !== NULL) { + $url = self::checkURLAllowed($url, $allowed_redirect_hosts); + } + self::_doRedirect($url, $parameters); } /** @@ -665,26 +681,27 @@ class SimpleSAML_Utilities { * @return void This function never returns. */ public static function redirectTrustedURL($url, $parameters = array()) { - self::redirect($url, $parameters); + $url = self::normalizeURL($url); + self::_doRedirect($url, $parameters); } /** * This function redirects to the specified URL after performing the - * appropriate security checks on it. Particularly, it will make sure - * that the provided URL is allowed by the 'redirect.trustedsites' - * directive in the configuration. + * appropriate security checks on it. Particularly, it will make sure that + * the provided URL is allowed by the 'redirect.trustedsites' directive + * in the configuration. * - * If the aforementioned option is not set or the URL does corresponds - * to a trusted site, it performs a redirection to it. If the site is - * not trusted, an exception will be thrown. + * If the aforementioned option is not set or the URL does correspond to a + * trusted site, it performs a redirection to it. If the site is not + * trusted, an exception will be thrown. * * See the redirectTrustedURL function for more details. * * @return void This function never returns. */ public static function redirectUntrustedURL($url, $parameters = array()) { - $trustedSites = SimpleSAML_Configuration::getInstance()->getArray('redirect.trustedsites', NULL); - self::redirect($url, $parameters, $trustedSites); + $url = self::checkURLAllowed($url); + self::_doRedirect($url, $parameters); } /** @@ -1150,8 +1167,7 @@ class SimpleSAML_Utilities { $base = self::getBaseURL(); } - - if(!preg_match('$^((((\w+:)//[^/]+)(/[^?#]*))(?:\?[^#]*)?)(?:#.*)?$', $base, $baseParsed)) { + if(!preg_match('/^((((\w+:)\/\/[^\/]+)(\/[^?#]*))(?:\?[^#]*)?)(?:#.*)?/', $base, $baseParsed)) { throw new Exception('Unable to parse base url: ' . $base); } diff --git a/lib/SimpleSAML/XHTML/IdPDisco.php b/lib/SimpleSAML/XHTML/IdPDisco.php index c1c5be0c46c5769f026f2081bf6a6645c74da342..7e7eeb93859b95e88925ddbf7cf795edf11359c9 100644 --- a/lib/SimpleSAML/XHTML/IdPDisco.php +++ b/lib/SimpleSAML/XHTML/IdPDisco.php @@ -124,7 +124,7 @@ class SimpleSAML_XHTML_IdPDisco { if(!array_key_exists('return', $_GET)) { throw new Exception('Missing parameter: return'); } else { - $this->returnURL = $_GET['return']; + $this->returnURL = SimpleSAML_Utilities::checkURLAllowed($_GET['return']); } $this->isPassive = FALSE; @@ -474,7 +474,7 @@ class SimpleSAML_XHTML_IdPDisco { } else { $this->log('Choice made [' . $idp . '] (Redirecting the user back. returnIDParam=' . $this->returnIdParam . ')'); - SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL, array($this->returnIdParam => $idp)); + SimpleSAML_Utilities::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idp)); } return; @@ -482,7 +482,7 @@ class SimpleSAML_XHTML_IdPDisco { if ($this->isPassive) { $this->log('Choice not made. (Redirecting the user back without answer)'); - SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL); + SimpleSAML_Utilities::redirectTrustedURL($this->returnURL); return; } @@ -500,7 +500,7 @@ class SimpleSAML_XHTML_IdPDisco { if(sizeof($idpintersection) == 1) { $this->log('Choice made [' . $idpintersection[0] . '] (Redirecting the user back. returnIDParam=' . $this->returnIdParam . ')'); - SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL, array($this->returnIdParam => $idpintersection[0])); + SimpleSAML_Utilities::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idpintersection[0])); } /* diff --git a/modules/InfoCard/lib/Auth/Source/ICAuth.php b/modules/InfoCard/lib/Auth/Source/ICAuth.php index 39e746c56b6b409f0866ead18fa502eaab1daca8..0b76ed1c08b03ebf4500741de0dd58440e68ba7e 100644 --- a/modules/InfoCard/lib/Auth/Source/ICAuth.php +++ b/modules/InfoCard/lib/Auth/Source/ICAuth.php @@ -42,7 +42,6 @@ class sspmod_InfoCard_Auth_Source_ICAuth extends SimpleSAML_Auth_Source { public static function handleLogin($authStateId, $xmlToken) { -SimpleSAML_Logger::debug('ENTRA en icauth'); assert('is_string($authStateId)'); $config = SimpleSAML_Configuration::getInstance(); @@ -61,14 +60,20 @@ SimpleSAML_Logger::debug('ENTRA en icauth'); SimpleSAML_Logger::debug("NOXMLtoken: ".$xmlToken); $claims = $infocard->process($xmlToken); if($claims->isValid()) { -// if(false) { $attributes = array(); foreach ($Infocard['requiredClaims'] as $claim => $data){ $attributes[$claim] = array($claims->$claim); } foreach ($Infocard['optionalClaims'] as $claim => $data){ $attributes[$claim] = array($claims->$claim); - } + } + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID); /* Find authentication source. */ @@ -78,12 +83,10 @@ SimpleSAML_Logger::debug('ENTRA en icauth'); throw new Exception('Could not find authentication source with id ' . $state[self::AUTHID]); } $state['Attributes'] = $attributes; -SimpleSAML_Logger::debug('VALIDA'); unset($infocard); unset($claims); SimpleSAML_Auth_Source::completeAuth($state); } else { -SimpleSAML_Logger::debug('NO VALIDA ERROR:'.$claims->getErrorMsg()); unset($infocard); unset($claims); return 'wrong_IC'; diff --git a/modules/aselect/www/credentials.php b/modules/aselect/www/credentials.php index 3d3b8cba1204a903c768285f831c544bc253a113..dc0afe7e4bde51319df8d0de887d9fc6c9d93bd5 100644 --- a/modules/aselect/www/credentials.php +++ b/modules/aselect/www/credentials.php @@ -7,7 +7,18 @@ * @author Wessel Dankers, Tilburg University */ function check_credentials() { - $state = SimpleSAML_Auth_State::loadState($_REQUEST['ssp_state'], 'aselect:login'); + + if (!array_key_exists('ssp_state', $_REQUEST)) + SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Missing ssp_state parameter")); + $id = $_REQUEST['ssp_state']; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($id); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + + $state = SimpleSAML_Auth_State::loadState($id, 'aselect:login'); if(!array_key_exists('a-select-server', $_REQUEST)) SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Missing a-select-server parameter")); diff --git a/modules/authYubiKey/lib/Auth/Source/YubiKey.php b/modules/authYubiKey/lib/Auth/Source/YubiKey.php index ae98920d61113455fb6bea97f886567456e8ba81..6b14128974a15b0ee6fe092ae48443c8164fb998 100644 --- a/modules/authYubiKey/lib/Auth/Source/YubiKey.php +++ b/modules/authYubiKey/lib/Auth/Source/YubiKey.php @@ -124,6 +124,12 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source { assert('is_string($authStateId)'); assert('is_string($otp)'); + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID); diff --git a/modules/authfacebook/www/linkback.php b/modules/authfacebook/www/linkback.php index 3a27fe5ea90b031ecece39df264d2da6f9c5cd85..2305f773dbe96eb5aad664437b729534d55e74c2 100644 --- a/modules/authfacebook/www/linkback.php +++ b/modules/authfacebook/www/linkback.php @@ -9,6 +9,13 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState'])) } $stateID = $_REQUEST['AuthState']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($stateID, sspmod_authfacebook_Auth_Source_Facebook::STAGE_INIT); /* Find authentication source. */ diff --git a/modules/authlinkedin/www/linkback.php b/modules/authlinkedin/www/linkback.php index 961eaa6bf423e56b8719f152c4976be1b95a7ac2..a169f04ee17532fd329e3e72b9c3deb3e3390f3a 100644 --- a/modules/authlinkedin/www/linkback.php +++ b/modules/authlinkedin/www/linkback.php @@ -10,6 +10,12 @@ if (array_key_exists('stateid', $_REQUEST)) { throw new Exception('Lost OAuth Client State'); } +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authlinkedin_Auth_Source_LinkedIn::STAGE_INIT); // http://developer.linkedin.com/docs/DOC-1008#2_Redirect_the_User_to_our_Authorization_Server diff --git a/modules/authmyspace/www/linkback.php b/modules/authmyspace/www/linkback.php index 93c45153c5f76d96dd5fa76e47ccf25acd6f4ded..81683c8373f45b93fcc2b44d4639405881ff1dfe 100644 --- a/modules/authmyspace/www/linkback.php +++ b/modules/authmyspace/www/linkback.php @@ -10,6 +10,12 @@ if (array_key_exists('stateid', $_REQUEST)) { throw new Exception('State Lost - not returned by MySpace Auth'); } +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authmyspace_Auth_Source_MySpace::STAGE_INIT); if (array_key_exists('oauth_problem', $_REQUEST)) { diff --git a/modules/authorize/www/authorize_403.php b/modules/authorize/www/authorize_403.php index 54d702fb0c21d88bd4f9aae8ef9c8567e1054261..613fa1034aa5026e79d28b961b0bc58a10f5acf7 100644 --- a/modules/authorize/www/authorize_403.php +++ b/modules/authorize/www/authorize_403.php @@ -11,6 +11,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'authorize:Authorize'); $globalConfig = SimpleSAML_Configuration::getInstance(); diff --git a/modules/authtwitter/www/linkback.php b/modules/authtwitter/www/linkback.php index de6ec85ce392d5059567924129f06439f89fd99f..0ebea758af5b6061e57fd95cd2be340eef5ce9a5 100644 --- a/modules/authtwitter/www/linkback.php +++ b/modules/authtwitter/www/linkback.php @@ -9,6 +9,12 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState'])) } $stateID = $_REQUEST['AuthState']; +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($stateID, sspmod_authtwitter_Auth_Source_Twitter::STAGE_INIT); /* Find authentication source. */ diff --git a/modules/authwindowslive/www/linkback.php b/modules/authwindowslive/www/linkback.php index 7ae42661fbefa80587413ecac23b76fffac95807..ee8452de461c5b11ab54beb1d561ed6e2a59c0ea 100644 --- a/modules/authwindowslive/www/linkback.php +++ b/modules/authwindowslive/www/linkback.php @@ -6,6 +6,13 @@ if (array_key_exists('wrap_client_state', $_REQUEST)) { $stateId = $_REQUEST['wrap_client_state']; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authwindowslive_Auth_Source_LiveID::STAGE_INIT); } else { throw new Exception('Lost OAuth-WRAP Client State'); diff --git a/modules/cas/www/linkback.php b/modules/cas/www/linkback.php index 1e6740c0bdcc6ba9d2190c1656a0642aa821ce85..8fe43e2f50bac1452d63f2280f8545b392a7621b 100644 --- a/modules/cas/www/linkback.php +++ b/modules/cas/www/linkback.php @@ -13,6 +13,12 @@ if (!isset($_GET['ticket'])) { throw new SimpleSAML_Error_BadRequest('Missing ticket parameter.'); } +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_cas_Auth_Source_CAS::STAGE_INIT); $state['cas:ticket'] = (string)$_GET['ticket']; diff --git a/modules/casserver/www/login.php b/modules/casserver/www/login.php index e59c3324877acf4dd71320c2f5016cc897b9f781..0410acdc3229a65f821550ac441e2c89e38249dc 100644 --- a/modules/casserver/www/login.php +++ b/modules/casserver/www/login.php @@ -48,10 +48,8 @@ storeTicket($ticket, $path, array('service' => $service, 'proxies' => array(), 'validbefore' => time() + 5)); -SimpleSAML_Utilities::redirectUntrustedURL( +SimpleSAML_Utilities::redirectTrustedURL( SimpleSAML_Utilities::addURLparameter($service, array('ticket' => $ticket) ) ); - -?> diff --git a/modules/cdc/lib/Server.php b/modules/cdc/lib/Server.php index 8c962eb19fd2c02acf260c1e8841e4c3cf1fe27e..d4dacf736711f73ebb82540f009fc37b2d6061b0 100644 --- a/modules/cdc/lib/Server.php +++ b/modules/cdc/lib/Server.php @@ -327,7 +327,7 @@ class sspmod_cdc_Server { $url = SimpleSAML_Utilities::addURLparameter($to, $params); if (strlen($url) < 2048) { - SimpleSAML_Utilities::redirectUntrustedURL($url); + SimpleSAML_Utilities::redirectTrustedURL($url); } else { SimpleSAML_Utilities::postRedirect($to, $params); } diff --git a/modules/cdc/www/resume.php b/modules/cdc/www/resume.php index 6e4fcf381caa8613dbda4f593bf06c29481ea039..549be22885b8999aa4fe65b270898f01a4a07fbe 100644 --- a/modules/cdc/www/resume.php +++ b/modules/cdc/www/resume.php @@ -17,6 +17,12 @@ if (!isset($response['id'])) { throw new SimpleSAML_Error_BadRequest('CDCResponse without id.'); } +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($response['id']); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($response['id'], 'cdc:resume'); SimpleSAML_Auth_ProcessingChain::resumeProcessing($state); diff --git a/modules/consent/www/getconsent.php b/modules/consent/www/getconsent.php index 3628bd1abb95704f075d0b2ada61ba301b3846f6..3e30817022f73720206f32b872fa58ae1a49c2d1 100644 --- a/modules/consent/www/getconsent.php +++ b/modules/consent/www/getconsent.php @@ -31,6 +31,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'consent:request'); if (array_key_exists('core:SP', $state)) { diff --git a/modules/consent/www/logout.php b/modules/consent/www/logout.php index 55903707b5ad4c6cd8f7bf0cca4197cbdbb8f6e4..1e464294a1cc4089903d5e598a3e45c187a68c95 100644 --- a/modules/consent/www/logout.php +++ b/modules/consent/www/logout.php @@ -10,6 +10,13 @@ if (!array_key_exists('StateId', $_GET)) { throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.'); } $id = (string)$_GET['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'consent:request'); $state['Responder'] = array('sspmod_consent_Logout', 'postLogout'); diff --git a/modules/consent/www/noconsent.php b/modules/consent/www/noconsent.php index 06e5554c0ea7868e802c0622705ecacfd0346ae7..37b5920117a250715eaf794232ef29522561d12d 100644 --- a/modules/consent/www/noconsent.php +++ b/modules/consent/www/noconsent.php @@ -12,6 +12,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'consent:request'); $resumeFrom = SimpleSAML_Module::getModuleURL( diff --git a/modules/core/lib/Auth/UserPassBase.php b/modules/core/lib/Auth/UserPassBase.php index 633a7484afce369e9d2df6416edfeb910ca3d183..c7ff0bebebaf068296a33793c4d2aa1ee038d878 100644 --- a/modules/core/lib/Auth/UserPassBase.php +++ b/modules/core/lib/Auth/UserPassBase.php @@ -197,6 +197,12 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source { assert('is_string($username)'); assert('is_string($password)'); + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* Here we retrieve the state array we saved in the authenticate-function. */ $state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID); diff --git a/modules/core/lib/Auth/UserPassOrgBase.php b/modules/core/lib/Auth/UserPassOrgBase.php index f79c3aefa265b47339434a03d5528d349426e4c5..9c7af9731f17ea33bbf7f28864e6db8612e606ff 100644 --- a/modules/core/lib/Auth/UserPassOrgBase.php +++ b/modules/core/lib/Auth/UserPassOrgBase.php @@ -209,6 +209,12 @@ abstract class sspmod_core_Auth_UserPassOrgBase extends SimpleSAML_Auth_Source { assert('is_string($password)'); assert('is_string($organization)'); + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID); @@ -257,6 +263,12 @@ abstract class sspmod_core_Auth_UserPassOrgBase extends SimpleSAML_Auth_Source { public static function listOrganizations($authStateId) { assert('is_string($authStateId)'); + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID); diff --git a/modules/core/www/as_login.php b/modules/core/www/as_login.php index a30bd1f77f3c08c2d1f6695d2df52ac863fabf04..09c07209cf4c108f85d51317a862b33ba9dc7770 100644 --- a/modules/core/www/as_login.php +++ b/modules/core/www/as_login.php @@ -19,7 +19,7 @@ if (!is_string($_REQUEST['AuthId'])) { * Setting up the options for the requireAuth() call later.. */ $options = array( - 'ReturnTo' => $_REQUEST['ReturnTo'], + 'ReturnTo' => SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']), ); /* @@ -30,9 +30,7 @@ if (!empty($_REQUEST['saml:idp'])) { $options['saml:idp'] = $_REQUEST['saml:idp']; } - - $as = new SimpleSAML_Auth_Simple($_REQUEST['AuthId']); $as->requireAuth($options); -SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['ReturnTo']); +SimpleSAML_Utilities::redirectTrustedURL($options['ReturnTo']); diff --git a/modules/core/www/as_logout.php b/modules/core/www/as_logout.php index 5ae8a39c3d59eda109097e1ef77644967b6b971c..dad67d213ff2234adb08232de77353baae8ddb18 100644 --- a/modules/core/www/as_logout.php +++ b/modules/core/www/as_logout.php @@ -16,4 +16,4 @@ if (!isset($_REQUEST['AuthId']) || !is_string($_REQUEST['AuthId'])) { } $as = new SimpleSAML_Auth_Simple($_REQUEST['AuthId']); -$as->logout($_REQUEST['ReturnTo']); +$as->logout(SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo'])); diff --git a/modules/core/www/bwc_resumeauth.php b/modules/core/www/bwc_resumeauth.php index 68b2055049e7659819f1f320e297068f9362dcd5..df937077d15ff6dd58e05c0a82893465a2e9e07f 100644 --- a/modules/core/www/bwc_resumeauth.php +++ b/modules/core/www/bwc_resumeauth.php @@ -20,7 +20,7 @@ if ($requestcache['ForceAuthn'] && $requestcache['core:prevSession'] === $sessio } if (isset($state['ReturnTo'])) { - SimpleSAML_Utilities::redirectUntrustedURL($state['ReturnTo']); + SimpleSAML_Utilities::redirectTrustedURL($state['ReturnTo']); } foreach ($session->getAuthState($authority) as $k => $v) { diff --git a/modules/core/www/cleardiscochoices.php b/modules/core/www/cleardiscochoices.php index c94e411e211b4bef7f01f54becd4d04957862c45..afd72997fea12bd52d4ea6987401adf59cc6694d 100644 --- a/modules/core/www/cleardiscochoices.php +++ b/modules/core/www/cleardiscochoices.php @@ -26,12 +26,12 @@ foreach($_COOKIE as $cookieName => $value) { /* Find where we should go now. */ if(array_key_exists('ReturnTo', $_REQUEST)) { - $returnTo = $_REQUEST['ReturnTo']; + $returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']); } else { /* Return to the front page if no other destination is given. This is the same as the base cookie path. */ $returnTo = $cookiePath; } /* Redirect to destination. */ -SimpleSAML_Utilities::redirectUntrustedURL($returnTo); +SimpleSAML_Utilities::redirectTrustedURL($returnTo); diff --git a/modules/core/www/idp/logout-iframe-done.php b/modules/core/www/idp/logout-iframe-done.php index 72a1e26f78085e5b6ba7574b92188c91e470c36a..62539988b6f5d08a8d01f40e4077e13aa7f69799 100644 --- a/modules/core/www/idp/logout-iframe-done.php +++ b/modules/core/www/idp/logout-iframe-done.php @@ -5,6 +5,12 @@ if (!isset($_REQUEST['id'])) { } $id = (string)$_REQUEST['id']; +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'core:Logout-IFrame'); $idp = SimpleSAML_IdP::getByState($state); diff --git a/modules/core/www/idp/logout-iframe.php b/modules/core/www/idp/logout-iframe.php index 1b751e931b2ba112e6ae6dacad25c6297b5c3f5a..53cdcfc94f564062204dde3bab462c4cf6721f6f 100644 --- a/modules/core/www/idp/logout-iframe.php +++ b/modules/core/www/idp/logout-iframe.php @@ -19,6 +19,12 @@ if ($type !== 'embed' && $type !== 'async') { SimpleSAML_Stats::log('core:idp:logout-iframe:page', array('type' => $type)); } +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'core:Logout-IFrame'); $idp = SimpleSAML_IdP::getByState($state); diff --git a/modules/core/www/idp/resumelogout.php b/modules/core/www/idp/resumelogout.php index 37c3e60f5eaf936ae93ab479947b70cf13501206..f93c8e968365e40dac78e8650c19cab765e67f1e 100644 --- a/modules/core/www/idp/resumelogout.php +++ b/modules/core/www/idp/resumelogout.php @@ -5,6 +5,12 @@ if (!isset($_REQUEST['id'])) { } $id = (string)$_REQUEST['id']; +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'core:Logout:afterbridge'); $idp = SimpleSAML_IdP::getByState($state); diff --git a/modules/core/www/login-admin.php b/modules/core/www/login-admin.php index 83886a181a27edac1954710c04bdfe3b2ab5e5fd..3e6438f3ea10e3b2dea80fb3da1ea30d3c6a48c9 100644 --- a/modules/core/www/login-admin.php +++ b/modules/core/www/login-admin.php @@ -6,9 +6,8 @@ if (!array_key_exists('ReturnTo', $_REQUEST)) { throw new SimpleSAML_Error_BadRequest('Missing ReturnTo parameter.'); } -$returnTo = $_REQUEST['ReturnTo']; SimpleSAML_Utilities::requireAdmin(); -SimpleSAML_Utilities::redirectUntrustedURL($returnTo); +SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['ReturnTo']); diff --git a/modules/core/www/loginuserpass.php b/modules/core/www/loginuserpass.php index 71da3aeaee7481e25c881e23a4c4bbaf737f0d98..cda363b4015e35804d89cc55546b5c0d98919b41 100644 --- a/modules/core/www/loginuserpass.php +++ b/modules/core/www/loginuserpass.php @@ -15,6 +15,12 @@ if (!array_key_exists('AuthState', $_REQUEST)) { } $authStateId = $_REQUEST['AuthState']; +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_core_Auth_UserPassBase::STAGEID); diff --git a/modules/core/www/loginuserpassorg.php b/modules/core/www/loginuserpassorg.php index cda773bfc47fffca8aa66c1070dfbb1145baa61b..abd9a532e563c6bf30d2117ccb4682bf22a2ff77 100644 --- a/modules/core/www/loginuserpassorg.php +++ b/modules/core/www/loginuserpassorg.php @@ -15,6 +15,12 @@ if (!array_key_exists('AuthState', $_REQUEST)) { } $authStateId = $_REQUEST['AuthState']; +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_core_Auth_UserPassOrgBase::STAGEID); diff --git a/modules/core/www/short_sso_interval.php b/modules/core/www/short_sso_interval.php index 5a51470a338ed201d09cadf748498443bacd56e6..e9e5b159dd65fff01b4eabf2b86b4c8b3e9495a4 100644 --- a/modules/core/www/short_sso_interval.php +++ b/modules/core/www/short_sso_interval.php @@ -12,6 +12,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'core:short_sso_interval'); if (array_key_exists('continue', $_REQUEST)) { diff --git a/modules/discopower/lib/PowerIdPDisco.php b/modules/discopower/lib/PowerIdPDisco.php index 22459312b45df8850a1c794a770786a49be37c83..10aad002f4e8dc62106da0ba069cc58a4bc2d87e 100644 --- a/modules/discopower/lib/PowerIdPDisco.php +++ b/modules/discopower/lib/PowerIdPDisco.php @@ -203,7 +203,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco { } else { $this->log('Choice made [' . $idp . '] (Redirecting the user back. returnIDParam=' . $this->returnIdParam . ')'); - SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL, array($this->returnIdParam => $idp)); + SimpleSAML_Utilities::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idp)); } return; @@ -211,7 +211,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco { if ($this->isPassive) { $this->log('Choice not made. (Redirecting the user back without answer)'); - SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL); + SimpleSAML_Utilities::redirectTrustedURL($this->returnURL); return; } diff --git a/modules/exampleauth/lib/Auth/Source/External.php b/modules/exampleauth/lib/Auth/Source/External.php index d3b16f020c19ca4d64edac6971d2fcaaf169456d..282c6a46da301c5e61f54093b5bb7e6ff16e2491 100644 --- a/modules/exampleauth/lib/Auth/Source/External.php +++ b/modules/exampleauth/lib/Auth/Source/External.php @@ -186,6 +186,12 @@ class sspmod_exampleauth_Auth_Source_External extends SimpleSAML_Auth_Source { } $stateId = (string)$_REQUEST['State']; + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* * Once again, note the second parameter to the loadState function. This must * match the string we used in the saveState-call above. diff --git a/modules/exampleauth/www/authpage.php b/modules/exampleauth/www/authpage.php index 21a284b22f29c1e5c6aa19a60d846f11a0f603a5..bcd01b8d4126fa51b821a37ee7b4418469500cab 100644 --- a/modules/exampleauth/www/authpage.php +++ b/modules/exampleauth/www/authpage.php @@ -14,7 +14,7 @@ if (!isset($_REQUEST['ReturnTo'])) { die('Missing ReturnTo parameter.'); } -$returnTo = $_REQUEST['ReturnTo']; +$returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']); /* @@ -31,6 +31,13 @@ if (!preg_match('@State=(.*)@', $returnTo, $matches)) { die('Invalid ReturnTo URL for this example.'); } $stateId = urldecode($matches[1]); + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + SimpleSAML_Auth_State::loadState($stateId, 'exampleauth:External'); /* @@ -87,8 +94,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $_SESSION['mail'] = $user['mail']; $_SESSION['type'] = $user['type']; - header('Location: ' . $returnTo); - exit(); + SimpleSAML_Utilities::redirectTrustedURL($returnTo); } } diff --git a/modules/exampleauth/www/redirecttest.php b/modules/exampleauth/www/redirecttest.php index 39a1b5450b381dbc7c5976c3be4e18f27894e342..c6d4fb86e1aa94d0179f429607e39d9adb06d34b 100644 --- a/modules/exampleauth/www/redirecttest.php +++ b/modules/exampleauth/www/redirecttest.php @@ -13,6 +13,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'exampleauth:redirectfilter-test'); $state['Attributes']['RedirectTest2'] = array('OK'); diff --git a/modules/expirycheck/www/about2expire.php b/modules/expirycheck/www/about2expire.php index c69624723ac223fa571725031458ce2581eb1ba2..487b3f8dffc8679e396c7e2ad3d9a30f86f4a548 100644 --- a/modules/expirycheck/www/about2expire.php +++ b/modules/expirycheck/www/about2expire.php @@ -14,6 +14,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'expirywarning:about2expire'); diff --git a/modules/expirycheck/www/expired.php b/modules/expirycheck/www/expired.php index 9b94cadbcec3a7df15f5e88aed680b7539571e69..5ec7b93a10505faa1d8299ae99f0734ccb742f45 100644 --- a/modules/expirycheck/www/expired.php +++ b/modules/expirycheck/www/expired.php @@ -14,6 +14,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'expirywarning:expired'); $globalConfig = SimpleSAML_Configuration::getInstance(); diff --git a/modules/multiauth/www/selectsource.php b/modules/multiauth/www/selectsource.php index 329a1bf4909c26e82fedd3ee899da06d18ab12dd..afa28ed50d7a39acc49fa0f1288bfcf3328c75f3 100644 --- a/modules/multiauth/www/selectsource.php +++ b/modules/multiauth/www/selectsource.php @@ -16,6 +16,12 @@ if (!array_key_exists('AuthState', $_REQUEST)) { } $authStateId = $_REQUEST['AuthState']; +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + /* Retrieve the authentication state. */ $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_multiauth_Auth_Source_MultiAuth::STAGEID); diff --git a/modules/negotiate/www/backend.php b/modules/negotiate/www/backend.php index f9d3622296bcf95b3ac7fcd170ddc782a8c9e1b3..347ce8dc9689584df7c9b9c50778c4c0275c6315 100644 --- a/modules/negotiate/www/backend.php +++ b/modules/negotiate/www/backend.php @@ -10,6 +10,13 @@ */ $authStateId = $_REQUEST['AuthState']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_negotiate_Auth_Source_Negotiate::STAGEID); SimpleSAML_Logger::debug('backend - fallback: '.$state['LogoutState']['negotiate:backend']); diff --git a/modules/negotiate/www/retry.php b/modules/negotiate/www/retry.php index 2d12eab97ebe92777c8108b067a8aed5e1472a4b..858b8367875a3d4e8d317d3dc2128de69c520546 100644 --- a/modules/negotiate/www/retry.php +++ b/modules/negotiate/www/retry.php @@ -10,6 +10,13 @@ */ $authStateId = $_REQUEST['AuthState']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_negotiate_Auth_Source_Negotiate::STAGEID); $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); diff --git a/modules/oauth/www/authorize.php b/modules/oauth/www/authorize.php index 9b3e032e12bb4fe24347835b5fa8aa69f3b4d40c..583c86efc924ca084c73ff3e8021ca8fbe50b634 100644 --- a/modules/oauth/www/authorize.php +++ b/modules/oauth/www/authorize.php @@ -56,7 +56,7 @@ try { if ($url) { // If authorize() returns a URL, take user there (oauth1.0a) - SimpleSAML_Utilities::redirectUntrustedURL($url); + SimpleSAML_Utilities::redirectTrustedURL($url); } else if (isset($_REQUEST['oauth_callback'])) { // If callback was provided in the request (oauth1.0) diff --git a/modules/openid/www/consumer.php b/modules/openid/www/consumer.php index 889fbf59c158f56801437d8eb92d0500ad7a00f1..0f8067c0e95276c4353883f2cfa72ed1d009fb4b 100644 --- a/modules/openid/www/consumer.php +++ b/modules/openid/www/consumer.php @@ -6,6 +6,13 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState'])) } $authState = $_REQUEST['AuthState']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authState); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($authState, 'openid:init'); $sourceId = $state['openid:AuthId']; $authSource = SimpleSAML_Auth_Source::getById($sourceId); diff --git a/modules/openid/www/linkback.php b/modules/openid/www/linkback.php index 180f9e18e3e081b1d5e9a52f2ac1a0ba8440a7c5..6108ca73e3ff53268acad343eb2272de1738e0df 100644 --- a/modules/openid/www/linkback.php +++ b/modules/openid/www/linkback.php @@ -6,6 +6,13 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState'])) } $authState = $_REQUEST['AuthState']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($authState); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($authState, 'openid:auth'); $sourceId = $state['openid:AuthId']; $authSource = SimpleSAML_Auth_Source::getById($sourceId); diff --git a/modules/openidProvider/lib/Server.php b/modules/openidProvider/lib/Server.php index f0596d18fa1e5a0fd68add0ee9494ab1929d55aa..1382cd84dd72dd4c8b3135dbb70ba0b7d65fff48 100644 --- a/modules/openidProvider/lib/Server.php +++ b/modules/openidProvider/lib/Server.php @@ -329,6 +329,12 @@ class sspmod_openidProvider_Server { public function loadState($stateId) { assert('is_string($stateId)'); + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + return SimpleSAML_Auth_State::loadState($stateId, 'openidProvider:resumeState'); } diff --git a/modules/papi/lib/Auth/Source/PAPI.php b/modules/papi/lib/Auth/Source/PAPI.php index ead66c8832a1b69ec5e6adaa9864bf965d2d0437..c074093460763cee6db69cb07fdd343185f9b941 100644 --- a/modules/papi/lib/Auth/Source/PAPI.php +++ b/modules/papi/lib/Auth/Source/PAPI.php @@ -115,6 +115,13 @@ class sspmod_papi_Auth_Source_PAPI extends SimpleSAML_Auth_Source { if (isset($_REQUEST['SSPStateID'])) { // yes! restore original request $this->_stateId = (string)$_REQUEST['SSPStateID']; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($this->_stateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $state = SimpleSAML_Auth_State::loadState($this->_stateId, self::STAGE_INIT); } else if (!$this->_poa->isAuthenticated()) { // no! we have to save the request @@ -161,6 +168,13 @@ class sspmod_papi_Auth_Source_PAPI extends SimpleSAML_Auth_Source { $this->_poa->logout(true); } else if (isset($_REQUEST['SSPStateID'])) { $this->_stateId = (string)$_REQUEST['SSPStateID']; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($this->_stateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $state = SimpleSAML_Auth_State::loadState($this->_stateId, self::STAGE_INIT); } else { return; diff --git a/modules/preprodwarning/www/showwarning.php b/modules/preprodwarning/www/showwarning.php index d8db6456098bc8323af431fd49ab195f2c27292a..2c50860dd7a933d891115af6998751fe7c3f486d 100644 --- a/modules/preprodwarning/www/showwarning.php +++ b/modules/preprodwarning/www/showwarning.php @@ -15,6 +15,13 @@ if (!array_key_exists('StateId', $_REQUEST)) { } $id = $_REQUEST['StateId']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($id); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + $state = SimpleSAML_Auth_State::loadState($id, 'warning:request'); diff --git a/modules/saml/www/sp/discoresp.php b/modules/saml/www/sp/discoresp.php index 6d9af381ed1ac06bf985052aff6f67f527f57d2d..1479f8a42b8d7fb95e17c1255e6a7590e7f74401 100644 --- a/modules/saml/www/sp/discoresp.php +++ b/modules/saml/www/sp/discoresp.php @@ -12,7 +12,15 @@ if (!array_key_exists('idpentityid', $_REQUEST)) { throw new SimpleSAML_Error_BadRequest('Missing idpentityid to discovery service response handler'); } -$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthID'], 'saml:sp:sso'); +$stateID = $_REQUEST['AuthID']; + +// sanitize the input +$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID); +if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); +} + +$state = SimpleSAML_Auth_State::loadState($stateID, 'saml:sp:sso'); /* Find authentication source. */ assert('array_key_exists("saml:sp:AuthId", $state)'); diff --git a/modules/saml/www/sp/saml1-acs.php b/modules/saml/www/sp/saml1-acs.php index 28ba7114382ac2881dc0f766246b4bd5a97df7ba..d9a594c5ef90f8b2fec969074be8d90e41548183 100644 --- a/modules/saml/www/sp/saml1-acs.php +++ b/modules/saml/www/sp/saml1-acs.php @@ -19,17 +19,25 @@ $source = SimpleSAML_Auth_Source::getById($sourceId, 'sspmod_saml_Auth_Source_SP SimpleSAML_Logger::debug('Received SAML1 response'); - $target = (string)$_REQUEST['TARGET']; + if (preg_match('@^https?://@i', $target)) { /* Unsolicited response. */ $state = array( 'saml:sp:isUnsolicited' => TRUE, 'saml:sp:AuthId' => $sourceId, - 'saml:sp:RelayState' => $target, + 'saml:sp:RelayState' => SimpleSAML_Utilities::checkURLAllowed($target), ); } else { - $state = SimpleSAML_Auth_State::loadState($_REQUEST['TARGET'], 'saml:sp:sso'); + $stateID = $_REQUEST['TARGET']; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + + $state = SimpleSAML_Auth_State::loadState($stateID, 'saml:sp:sso'); /* Check that the authentication source is correct. */ assert('array_key_exists("saml:sp:AuthId", $state)'); @@ -80,4 +88,4 @@ $state['LogoutState'] = $logoutState; $source->handleResponse($state, $responseIssuer, $attributes); assert('FALSE'); -?> \ No newline at end of file +?> diff --git a/modules/saml/www/sp/saml2-acs.php b/modules/saml/www/sp/saml2-acs.php index a3c8200bcdc1033ed12537edaf282d7eacee527b..09723b64235cab45fbd49d67ea94b819de6d99f8 100644 --- a/modules/saml/www/sp/saml2-acs.php +++ b/modules/saml/www/sp/saml2-acs.php @@ -52,6 +52,13 @@ $idpMetadata = array(); $stateId = $response->getInResponseTo(); if (!empty($stateId)) { + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + /* This is a response to a request we sent earlier. */ $state = SimpleSAML_Auth_State::loadState($stateId, 'saml:sp:sso'); @@ -75,7 +82,7 @@ if (!empty($stateId)) { $state = array( 'saml:sp:isUnsolicited' => TRUE, 'saml:sp:AuthId' => $sourceId, - 'saml:sp:RelayState' => $response->getRelayState(), + 'saml:sp:RelayState' => SimpleSAML_Utilities::checkURLAllowed($response->getRelayState()), ); } diff --git a/modules/saml/www/sp/saml2-logout.php b/modules/saml/www/sp/saml2-logout.php index d2b26b06e9113e4198503b2b14635c1ea68caa68..5d360243338c93e0a45a2653a87ebe51c894e6a3 100644 --- a/modules/saml/www/sp/saml2-logout.php +++ b/modules/saml/www/sp/saml2-logout.php @@ -54,6 +54,12 @@ if ($message instanceof SAML2_LogoutResponse) { SimpleSAML_Logger::warning('Unsuccessful logout. Status was: ' . sspmod_saml_Message::getResponseError($message)); } + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($relayState); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $state = SimpleSAML_Auth_State::loadState($relayState, 'saml:slosent'); $state['saml:sp:LogoutStatus'] = $message->getStatus(); SimpleSAML_Auth_Source::completeLogout($state); diff --git a/www/auth/login-admin.php b/www/auth/login-admin.php index 42ac0ecf0b66d816353d7ce86051ecfb2d9bfe04..597b353aa1a097708679447373a8a4f61dd5278b 100644 --- a/www/auth/login-admin.php +++ b/www/auth/login-admin.php @@ -20,7 +20,7 @@ if (!array_key_exists('RelayState', $_REQUEST)) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } -$relaystate = $_REQUEST['RelayState']; +$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']); $correctpassword = $config->getString('auth.adminpassword', '123'); @@ -59,7 +59,7 @@ if (isset($_POST['password'])) { else SimpleSAML_Logger::stats('AUTH-login-admin OK'); - SimpleSAML_Utilities::redirectUntrustedURL($relaystate); + SimpleSAML_Utilities::redirectTrustedURL($relaystate); exit(0); } else { SimpleSAML_Logger::stats('AUTH-login-admin Failed'); @@ -82,6 +82,3 @@ if (isset($error)) { } $t->show(); - - -?> diff --git a/www/auth/login-cas-ldap.php b/www/auth/login-cas-ldap.php index 2ba907adee87641ea11519194a456fc3e4d737e7..281488d97c9e50d1119f484facd2b05db9f9fd90 100644 --- a/www/auth/login-cas-ldap.php +++ b/www/auth/login-cas-ldap.php @@ -30,8 +30,6 @@ try { $casconfig = $casldapconfig[$idpentityid]['cas']; $ldapconfig = $casldapconfig[$idpentityid]['ldap']; - - } catch (Exception $exception) { throw new SimpleSAML_Error_Error('METADATA', $exception); } @@ -44,8 +42,6 @@ if (!array_key_exists('RelayState', $_REQUEST)) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } - - function casValidate($cas) { $service = SimpleSAML_Utilities::selfURL(); @@ -110,12 +106,7 @@ function casValidate($cas) { } } - - try { - - $relaystate = $_REQUEST['RelayState']; - list($username, $casattributes) = casValidate($casconfig); SimpleSAML_Logger::info('AUTH - cas-ldap: '. $username . ' authenticated by ' . $casconfig['validate']); @@ -132,11 +123,9 @@ try { $session->setNameID(array( 'value' => SimpleSAML_Utilities::generateID(), 'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient')); - SimpleSAML_Utilities::redirectUntrustedURL($relaystate); + + SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['RelayState']); } catch(Exception $exception) { throw new SimpleSAML_Error_Error('CASERROR', $exception); } - - -?> \ No newline at end of file diff --git a/www/auth/login-ldapmulti.php b/www/auth/login-ldapmulti.php index aab198afc883877f6eecf1b1e197ad1739a7246f..169800bc3387361467ad7236efe893fd8b8d7164 100644 --- a/www/auth/login-ldapmulti.php +++ b/www/auth/login-ldapmulti.php @@ -10,7 +10,6 @@ $session = SimpleSAML_Session::getInstance(); $ldapconfigfile = $config->getBaseDir() . 'config/ldapmulti.php'; require_once($ldapconfigfile); - SimpleSAML_Logger::info('AUTH - ldap-multi: Accessing auth endpoint login-ldapmulti'); $error = null; @@ -23,6 +22,8 @@ if (!array_key_exists('RelayState', $_REQUEST)) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } +$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']); + if (isset($_POST['username'])) { try { @@ -50,8 +51,7 @@ if (isset($_POST['username'])) { $attributes = $ldap->getAttributes($dn, $ldapconfig['attributes']); SimpleSAML_Logger::info('AUTH - ldap-multi: '. $_POST['username'] . ' successfully authenticated'); - - + $session->doLogin('login-ldapmulti'); $session->setAttributes($attributes); @@ -64,19 +64,16 @@ if (isset($_POST['username'])) { * Also log a specific attribute as set in the config: statistics.authlogattr */ $authlogattr = $config->getValue('statistics.authlogattr', null); - if ($authlogattr && array_key_exists($authlogattr, $attributes)) + if ($authlogattr && array_key_exists($authlogattr, $attributes)) { SimpleSAML_Logger::stats('AUTH-login-ldapmulti OK ' . $attributes[$authlogattr][0]); - else + } else { SimpleSAML_Logger::stats('AUTH-login-ldapmulti OK'); - - - $returnto = $_REQUEST['RelayState']; - SimpleSAML_Utilities::redirectUntrustedURL($returnto); + } + + SimpleSAML_Utilities::redirectTrustedURL($relaystate); } catch (Exception $e) { - $error = $e->getMessage(); - } } @@ -84,7 +81,7 @@ if (isset($_POST['username'])) { $t = new SimpleSAML_XHTML_Template($config, 'login-ldapmulti.php', 'login'); $t->data['header'] = 'simpleSAMLphp: Enter username and password'; -$t->data['relaystate'] = $_REQUEST['RelayState']; +$t->data['relaystate'] = $relaystate; $t->data['ldapconfig'] = $ldapmulti; $t->data['org'] = $_REQUEST['org']; $t->data['error'] = $error; diff --git a/www/auth/login-radius.php b/www/auth/login-radius.php index b95c7ae92a304a4964937859c1db7344259566f8..5a80f49f0ebd1d32a1549ea3542d8629d41ec0ac 100644 --- a/www/auth/login-radius.php +++ b/www/auth/login-radius.php @@ -19,6 +19,8 @@ if (!array_key_exists('RelayState', $_REQUEST)) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } +$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']); + if (isset($_POST['username'])) { @@ -97,21 +99,18 @@ if (isset($_POST['username'])) { 'value' => SimpleSAML_Utilities::generateID(), 'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient')); - /** * Create a statistics log entry for every successfull login attempt. * Also log a specific attribute as set in the config: statistics.authlogattr */ $authlogattr = $config->getValue('statistics.authlogattr', null); - if ($authlogattr && array_key_exists($authlogattr, $attributes)) + if ($authlogattr && array_key_exists($authlogattr, $attributes)) { SimpleSAML_Logger::stats('AUTH-login-radius OK ' . $attributes[$authlogattr][0]); - else + } else { SimpleSAML_Logger::stats('AUTH-login-radius OK'); + } - - $returnto = $_REQUEST['RelayState']; - SimpleSAML_Utilities::redirectUntrustedURL($returnto); - + SimpleSAML_Utilities::redirectTrustedURL($relaystate); case RADIUS_ACCESS_REJECT: @@ -125,13 +124,10 @@ if (isset($_POST['username'])) { default: SimpleSAML_Logger::critical('AUTH -radius: General radius error: ' . radius_strerror($radius)); throw new Exception('Error during radius authentication: ' . radius_strerror($radius)); - } } catch (Exception $e) { - $error = $e->getMessage(); - } } @@ -139,13 +135,10 @@ if (isset($_POST['username'])) { $t = new SimpleSAML_XHTML_Template($config, 'login.php', 'login'); $t->data['header'] = 'simpleSAMLphp: Enter username and password'; -$t->data['relaystate'] = $_REQUEST['RelayState']; +$t->data['relaystate'] = $relaystate; $t->data['error'] = $error; if (isset($error)) { $t->data['username'] = $_POST['username']; } $t->show(); - - -?> diff --git a/www/auth/login-tlsclient.php b/www/auth/login-tlsclient.php index 42e2678ae679d6ab94f870cd9f405ee1601a9602..0fb6e93925ca83a4f067816b866da2d23eba3d6f 100644 --- a/www/auth/login-tlsclient.php +++ b/www/auth/login-tlsclient.php @@ -23,9 +23,6 @@ if (!array_key_exists('RelayState', $_REQUEST)) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } -$relaystate = $_REQUEST['RelayState']; - - try { $attributes = array(); @@ -55,21 +52,21 @@ try { $session->setNameID(array( 'value' => SimpleSAML_Utilities::generateID(), - 'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient')); + 'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient') + ); /** * Create a statistics log entry for every successfull login attempt. * Also log a specific attribute as set in the config: statistics.authlogattr */ $authlogattr = $config->getValue('statistics.authlogattr', null); - if ($authlogattr && array_key_exists($authlogattr, $attributes)) + if ($authlogattr && array_key_exists($authlogattr, $attributes)) { SimpleSAML_Logger::stats('AUTH-tlsclient OK ' . $attributes[$authlogattr][0]); - else + } else { SimpleSAML_Logger::stats('AUTH-tlsclient OK'); - + } - $returnto = $_REQUEST['RelayState']; - SimpleSAML_Utilities::redirectUntrustedURL($returnto); + SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['RelayState']); } catch (Exception $e) { diff --git a/www/auth/login-wayf-ldap.php b/www/auth/login-wayf-ldap.php index 73d5f57a4cf3b6dfc676922e82ecd732b7f44d69..9c8c25e52ea91cb9af03815fe36a83ad775665b6 100644 --- a/www/auth/login-wayf-ldap.php +++ b/www/auth/login-wayf-ldap.php @@ -42,7 +42,7 @@ if (!array_key_exists('RelayState', $_REQUEST)) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } -$relaystate = $_REQUEST['RelayState']; +$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']); if ($username = $_POST['username']) { try { @@ -59,7 +59,7 @@ if ($username = $_POST['username']) { $session->setNameID(array( 'value' => SimpleSAML_Utilities::generateID(), 'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient')); - SimpleSAML_Utilities::redirectUntrustedURL($relaystate); + SimpleSAML_Utilities::redirectTrustedURL($relaystate); } } catch(Exception $e) { throw new SimpleSAML_Error_Error('LDAPERROR', $e); diff --git a/www/saml2/idp/SingleLogoutService.php b/www/saml2/idp/SingleLogoutService.php index 618068cd88d3d413ba16cfc9494390598a5f6a36..45a1012a416e56665b2a6deedd11ad062f8905db 100644 --- a/www/saml2/idp/SingleLogoutService.php +++ b/www/saml2/idp/SingleLogoutService.php @@ -18,7 +18,7 @@ $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted'); $idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId); if (isset($_REQUEST['ReturnTo'])) { - $idp->doLogoutRedirect((string)$_REQUEST['ReturnTo']); + $idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed((string)$_REQUEST['ReturnTo'])); } else { sspmod_saml_IdP_SAML2::receiveLogoutMessage($idp); } diff --git a/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php b/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php index 24f89b013842c4198538f47b9b45ab85851a7972..977265932c688928987d2c654cf5a4608725bce0 100644 --- a/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php +++ b/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php @@ -16,5 +16,5 @@ if (!isset($_REQUEST['RelayState'])) { throw new SimpleSAML_Error_BadRequest('Missing required RelayState parameter.'); } -$idp->doLogoutRedirect((string)$_REQUEST['RelayState']); +$idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed((string)$_REQUEST['RelayState'])); assert('FALSE'); diff --git a/www/saml2/idp/initSLO.php b/www/saml2/idp/initSLO.php index d6b23adc351ac62e75e4c311dcc770f7d86fdb92..87191b7772776197e317132bc239fb526da994f4 100644 --- a/www/saml2/idp/initSLO.php +++ b/www/saml2/idp/initSLO.php @@ -11,6 +11,5 @@ if (!isset($_GET['RelayState'])) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } -$returnTo = (string)$_GET['RelayState']; -$idp->doLogoutRedirect($returnTo); +$idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed((string)$_GET['RelayState'])); assert('FALSE'); \ No newline at end of file diff --git a/www/saml2/sp/AssertionConsumerService.php b/www/saml2/sp/AssertionConsumerService.php index e024489bacacfeb7f4bf46d9336928789de8deee..c7dc96f29034204b7502c5e8b0558355d3806bcd 100644 --- a/www/saml2/sp/AssertionConsumerService.php +++ b/www/saml2/sp/AssertionConsumerService.php @@ -47,7 +47,7 @@ function finishLogin($authProcState) { global $session; $session->doLogin('saml2', $authData); - SimpleSAML_Utilities::redirectUntrustedURL($authProcState['core:saml20-sp:TargetURL']); + SimpleSAML_Utilities::redirectTrustedURL($authProcState['core:saml20-sp:TargetURL']); } SimpleSAML_Logger::info('SAML2.0 - SP.AssertionConsumerService: Accessing SAML 2.0 SP endpoint AssertionConsumerService'); @@ -59,6 +59,13 @@ if (array_key_exists(SimpleSAML_Auth_ProcessingChain::AUTHPARAM, $_REQUEST)) { /* We have returned from the authentication processing filters. */ $authProcId = $_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM]; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authProcId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId); finishLogin($authProcState); } @@ -93,7 +100,7 @@ try { if($info === NULL) { /* Fall back to RelayState. */ $info = array(); - $info['RelayState'] = $response->getRelayState(); + $info['RelayState'] = SimpleSAML_Utilities::checkURLAllowed($response->getRelayState()); if(empty($info['RelayState'])) { $info['RelayState'] = $spMetadata->getString('RelayState', NULL); } diff --git a/www/saml2/sp/SingleLogoutService.php b/www/saml2/sp/SingleLogoutService.php index 0bd8c731e412223cde8ff8aa11c8f76bd33c3ea2..cf9f94cd06e761b6486da833236206cc2a6aa581 100644 --- a/www/saml2/sp/SingleLogoutService.php +++ b/www/saml2/sp/SingleLogoutService.php @@ -83,12 +83,14 @@ if ($message instanceof SAML2_LogoutRequest) { $id = $message->getInResponseTo(); } + // 'spLogoutReturnTo' is checked before storing it in the + // session, so we trust it here. $returnTo = $session->getData('spLogoutReturnTo', $id); if (empty($returnTo)) { throw new SimpleSAML_Error_Error('LOGOUTINFOLOST'); } - SimpleSAML_Utilities::redirectUntrustedURL($returnTo); + SimpleSAML_Utilities::redirectTrustedURL($returnTo); } else { throw new SimpleSAML_Error_Error('SLOSERVICEPARAMS'); diff --git a/www/saml2/sp/initSLO.php b/www/saml2/sp/initSLO.php index 8402a36c0de27cc35fa4f3686f9d1f751bf32abc..85c13bbe0540698e5215e7f4ffbc39cc5aa9ea7c 100644 --- a/www/saml2/sp/initSLO.php +++ b/www/saml2/sp/initSLO.php @@ -13,7 +13,7 @@ if (!$config->getBoolean('enable.saml20-sp', TRUE)) if (isset($_REQUEST['RelayState'])) { - $returnTo = $_REQUEST['RelayState']; + $returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']); } else { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } @@ -25,7 +25,7 @@ try { $idpEntityId = $session->getAuthData('saml2', 'saml:sp:IdP'); if ($idpEntityId === NULL) { SimpleSAML_Logger::info('SAML2.0 - SP.initSLO: User not authenticated with an IdP.'); - SimpleSAML_Utilities::redirectUntrustedURL($returnTo); + SimpleSAML_Utilities::redirectTrustedURL($returnTo); } $idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-remote'); $SLOendpoint = $idpMetadata->getEndpointPrioritizedByBinding('SingleLogoutService', array( @@ -34,8 +34,8 @@ try { NULL); if ($SLOendpoint === NULL) { $session->doLogout('saml2'); - SimpleSAML_Logger::info('SAML2.0 - SP.initSLO: No supported SingleLogoutService endpoint in IdP.'); - SimpleSAML_Utilities::redirectUntrustedURL($returnTo); + SimpleSAML_Logger::info('SAML2.0 - SP.initSLO: No SingleLogoutService endpoint supported in the IdP.'); + SimpleSAML_Utilities::redirectTrustedURL($returnTo); } $spEntityId = isset($_GET['spentityid']) ? $_GET['spentityid'] : $metadata->getMetaDataCurrentEntityID(); diff --git a/www/saml2/sp/initSSO.php b/www/saml2/sp/initSSO.php index a9ee60fbe114ca143c4a5e4b835e92bafcd3ff7d..c6d17803688c9318dd1b4f983199f880732a9543 100644 --- a/www/saml2/sp/initSSO.php +++ b/www/saml2/sp/initSSO.php @@ -23,6 +23,7 @@ if (!$config->getBoolean('enable.saml20-sp', TRUE)) if (empty($_GET['RelayState'])) { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } +$returnTo = SimpleSAML_Utilities::checkURLAllowed($_GET['RelayState']); $reachableIDPs = array(); @@ -134,7 +135,7 @@ try { $assertionConsumerServiceURL = $metadata->getGenerated('AssertionConsumerService', 'saml20-sp-hosted'); $ar->setAssertionConsumerServiceURL($assertionConsumerServiceURL); - $ar->setRelayState($_REQUEST['RelayState']); + $ar->setRelayState($returnTo); if ($isPassive) { $ar->setIsPassive(TRUE); @@ -156,9 +157,9 @@ try { /* Save request information. */ $info = array(); - $info['RelayState'] = $_REQUEST['RelayState']; + $info['RelayState'] = $returnTo; if(array_key_exists('OnError', $_REQUEST)) { - $info['OnError'] = $_REQUEST['OnError']; + $info['OnError'] = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['OnError']); } $session->setData('SAML2:SP:SSO:Info', $ar->getId(), $info); diff --git a/www/shib13/sp/AssertionConsumerService.php b/www/shib13/sp/AssertionConsumerService.php index f523c28a47f08e0a84f90365be34c615521b7c40..bc5a4368ca3683205dd675c4286f71cfb867af67 100644 --- a/www/shib13/sp/AssertionConsumerService.php +++ b/www/shib13/sp/AssertionConsumerService.php @@ -47,6 +47,13 @@ if (array_key_exists(SimpleSAML_Auth_ProcessingChain::AUTHPARAM, $_REQUEST)) { /* We have returned from the authentication processing filters. */ $authProcId = $_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM]; + + // sanitize the input + $restartURL = SimpleSAML_Utilities::getURLFromStateID($authProcId); + if (!is_null($restartURL)) { + SimpleSAML_Utilities::checkURLAllowed($restartURL); + } + $authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId); finishLogin($authProcState); } @@ -86,7 +93,7 @@ try { $authProcState = array( 'core:shib13-sp:NameID' => $authnResponse->getNameID(), 'core:shib13-sp:SessionIndex' => $authnResponse->getSessionIndex(), - 'core:shib13-sp:TargetURL' => $relayState, + 'core:shib13-sp:TargetURL' => SimpleSAML_Utilities::checkURLAllowed($relayState), 'ReturnURL' => SimpleSAML_Utilities::selfURLNoQuery(), 'Attributes' => $authnResponse->getAttributes(), 'Destination' => $spmetadata, diff --git a/www/shib13/sp/initSSO.php b/www/shib13/sp/initSSO.php index d666b8b86901a11bb950a19d88f104c57d29de29..5d40daae2b1835216d1c5487ff68f60309783184 100644 --- a/www/shib13/sp/initSSO.php +++ b/www/shib13/sp/initSSO.php @@ -70,7 +70,7 @@ if (!isset($session) || !$session->isValid('shib13') ) { $ar = new SimpleSAML_XML_Shib13_AuthnRequest(); $ar->setIssuer($spentityid); if(isset($_GET['RelayState'])) - $ar->setRelayState($_GET['RelayState']); + $ar->setRelayState(SimpleSAML_Utilities::checkURLAllowed($_GET['RelayState'])); SimpleSAML_Logger::info('Shib1.3 - SP.initSSO: SP (' . $spentityid . ') is sending AuthNRequest to IdP (' . $idpentityid . ')'); diff --git a/www/wsfed/sp/initSLO.php b/www/wsfed/sp/initSLO.php index f31ebaaca2480ba1ed8720171fd2016d031030d3..318bfa2feb8d9e5cb81f7472172da253e0fe8551 100644 --- a/www/wsfed/sp/initSLO.php +++ b/www/wsfed/sp/initSLO.php @@ -13,7 +13,7 @@ if (!$config->getBoolean('enable.wsfed-sp', false)) if (isset($_REQUEST['RelayState'])) { - $returnTo = $_REQUEST['RelayState']; + $returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']); } else { throw new SimpleSAML_Error_Error('NORELAYSTATE'); } @@ -53,7 +53,7 @@ if (isset($session) ) { } else { SimpleSAML_Logger::info('WS-Fed - SP.initSLO: User is already logged out. Go back to relaystate'); - SimpleSAML_Utilities::redirectUntrustedURL($returnTo); + SimpleSAML_Utilities::redirectTrustedURL($returnTo); } diff --git a/www/wsfed/sp/initSSO.php b/www/wsfed/sp/initSSO.php index 0e0b8613fdb009514264ac60189aa44fd3b6a166..f3f1ec7d7d56420ae42930b9b74eff235f18ba3b 100644 --- a/www/wsfed/sp/initSSO.php +++ b/www/wsfed/sp/initSSO.php @@ -46,7 +46,7 @@ if ($idpentityid == null) { } try { - $relaystate = $_GET['RelayState']; + $relaystate = SimpleSAML_Utilities::checkURLAllowed($_GET['RelayState']); $idpmeta = $metadata->getMetaData($idpentityid, 'wsfed-idp-remote'); $spmeta = $metadata->getMetaData($spentityid, 'wsfed-sp-hosted');