diff --git a/docs/simplesamlphp-sp-api.txt b/docs/simplesamlphp-sp-api.txt index 54cd65a895db1c8bdf7af068e8a88b5c494c4524..07c5a35c364913e0efa79e19f3262fc0239c00c5 100644 --- a/docs/simplesamlphp-sp-api.txt +++ b/docs/simplesamlphp-sp-api.txt @@ -117,22 +117,55 @@ The [`saml:SP`](./saml:sp) authentication source also defines some parameters. `logout` -------- - void logout(string $url = NULL) + void logout(mixed $params = NULL) -Log the user out, and return to the given URL. -If the user isn't authenticated, the user will be redirected to the URL. -If the user is authenticated with an IdP, the user will be sent to the IdP for logout. +Log the user out. +After logging out, the user will either be redirected to another page, or a function will be called. This function never returns. ### Parameters -`$url` -: The URL the user should be sent to after logout. - The default is the URL of the current page. +`$params` +: Parameters for the logout operation. + This can either be a simple string, in which case it is interpreted as the URL the user should be redirected to after logout, or an associative array with logout parameters. + If this parameter isn't specified, we will redirect the user to the current URL after logout. -### Example + If the parameter is an an array, it can have the following options: + + - `ReturnTo`: The URL the user should be returned to after logout. + - `ReturnCallback`: The function that should be called after logout. + - `ReturnStateParam`: The parameter we should return the state in when redirecting. + - `ReturnStateStage`: The stage the state array should be saved with. + + The `ReturnState` parameters allow access to the result of the logout operation after it completes. + +### Example 1 + +Logout, and redirect to the specified URL. + + $auth->logout('https://sp.example.org/logged_out.php'); - $auth->logout('https://sp.example.org/'); +### Example 2 + +Same as the previous, but check the result of the logout operation afterwards. + + $auth->logout(array( + 'ReturnTo' => 'https://sp.example.org/logged_out.php', + 'ReturnStateParam' => 'LogoutState', + 'ReturnStateStage' => 'MyLogoutState', + )); + +And in logged_out.php: + + $state = SimpleSAML_Auth_State::loadState((string)$_REQUEST['LogoutState'], 'MyLogoutState'); + $ls = $state['saml:sp:LogoutStatus']; /* Only works for SAML SP */ + if ($ls['Code'] === 'urn:oasis:names:tc:SAML:2.0:status:Success' && !isset($ls['SubCode'])) { + /* Successful logout. */ + echo("You have been logged out."); + } else { + /* Logout failed. Tell the user to close the browser. */ + echo("We were unable to log you out of all your sessions. To be completely sure that you are logged out, you need to close your web browser."); + } `getAttributes` diff --git a/lib/SimpleSAML/Auth/Simple.php b/lib/SimpleSAML/Auth/Simple.php index f5d36fb4c9e5139e362cd17355e1c1f62ca8444c..ec08f29d680386ae9e54c4ac3c794844d18acdab 100644 --- a/lib/SimpleSAML/Auth/Simple.php +++ b/lib/SimpleSAML/Auth/Simple.php @@ -134,26 +134,83 @@ class SimpleSAML_Auth_Simple { * * This function logs the user out. It will never return. By default, * it will cause a redirect to the current page after logging the user - * out, but a different URL can be given with the $url parameter. + * out, but a different URL can be given with the $params parameter. * - * @param string|NULL $url The url the user should be redirected to after logging out. - * Defaults to the current page. + * Generic parameters are: + * - 'ReturnTo': The URL the user should be returned to after logout. + * - 'ReturnCallback': The function that should be called after logout. + * - 'ReturnStateParam': The parameter we should return the state in when redirecting. + * - 'ReturnStateStage': The stage the state array should be saved with. + * + * @param string|array|NULL $params Either the url the user should be redirected to after logging out, + * or an array with parameters for the logout. If this parameter is + * NULL, we will return to the current page. */ - public function logout($url = NULL) { - assert('is_string($url) || is_null($url)'); + public function logout($params = NULL) { + assert('is_array($params) || is_string($params) || is_null($params)'); + + if ($params === NULL) { + $params = SimpleSAML_Utilities::selfURL(); + } + + if (is_string($params)) { + $params = array( + 'ReturnTo' => $params, + ); + } + + assert('is_array($params)'); + assert('isset($params["ReturnTo"]) || isset($params["ReturnCallback"])'); - if ($url === NULL) { - $url = SimpleSAML_Utilities::selfURL(); + if (isset($params['ReturnStateParam']) || isset($params['ReturnStateStage'])) { + assert('isset($params["ReturnStateParam"]) && isset($params["ReturnStateStage"])'); } $session = SimpleSAML_Session::getInstance(); - if (!$session->isValid($this->authSource)) { - /* Not authenticated to this authentication source. */ - SimpleSAML_Utilities::redirect($url); - assert('FALSE'); + if ($session->isValid($this->authSource)) { + $state = $session->getAuthData($this->authSource, 'LogoutState'); + if ($state !== NULL) { + $params = array_merge($state, $params); + } + + $session->doLogout($this->authSource); + + $params['LogoutCompletedHandler'] = array(get_class(), 'logoutCompleted'); + + $as = SimpleSAML_Auth_Source::getById($this->authSource); + if ($as !== NULL) { + $as->logout($params); + } } - SimpleSAML_Auth_Default::initLogout($url, $this->authSource); + self::logoutCompleted($params); + } + + + /** + * Called when logout operation completes. + * + * This function never returns. + * + * @param array $state The state after the logout. + */ + public static function logoutCompleted($state) { + assert('is_array($state)'); + assert('isset($state["ReturnTo"]) || isset($state["ReturnCallback"])'); + + if (isset($state['ReturnCallback'])) { + call_user_func($state['ReturnCallback'], $state); + assert('FALSE'); + } else { + $params = array(); + if (isset($state['ReturnStateParam']) || isset($state['ReturnStateStage'])) { + assert('isset($state["ReturnStateParam"]) && isset($state["ReturnStateStage"])'); + $stateID = SimpleSAML_Auth_State::saveState($state, $state['ReturnStateStage']); + $params[$state['ReturnStateParam']] = $stateID; + } + + SimpleSAML_Utilities::redirect($state['ReturnTo'], $params); + } }