diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php index 5f620a341e69261e2c697188f38ea88b8c16456d..2f35a96a34b1c3f31922e9245120da569b6a1f22 100644 --- a/lib/SimpleSAML/Auth/Default.php +++ b/lib/SimpleSAML/Auth/Default.php @@ -37,6 +37,10 @@ class SimpleSAML_Auth_Default { 'SimpleSAML_Auth_Default.ErrorURL' => $errorURL, 'LoginCompletedHandler' => array(get_class(), 'loginCompleted'), 'LoginFailedHandler' => array(get_class(), 'loginFailed'), + 'LogoutCallback' => array(get_class(), 'logoutCallback'), + 'LogoutCallbackState' => array( + 'SimpleSAML_Auth_Default.logoutSource' => $authId, + ), ); if (array_key_exists('SPMetadata', $hints)) { @@ -163,6 +167,31 @@ class SimpleSAML_Auth_Default { SimpleSAML_Utilities::redirect($returnURL); } + + /** + * Called when the authentication source receives an external logout request. + * + * @param array $state State array for the logout operation. + */ + public static function logoutCallback($state) { + assert('is_array($state)'); + assert('array_key_exists("SimpleSAML_Auth_Default.logoutSource", $state)'); + + $source = $state['SimpleSAML_Auth_Default.logoutSource']; + + $session = SimpleSAML_Session::getInstance(); + $authId = $session->getAuthority(); + + if ($authId !== $source) { + SimpleSAML_Logger::warning('Received logout from different authentication source ' . + 'than the current. Current is ' . var_export($authId, TRUE) . + '. Logout source is ' . var_export($source, TRUE) . '.'); + return; + } + + $session->doLogout(); + } + } ?> \ No newline at end of file diff --git a/lib/SimpleSAML/Auth/Source.php b/lib/SimpleSAML/Auth/Source.php index c7695185279b175cc3981507a45c0afaf11eadc2..f0a0c948b691c0c7c31c4b3d9fa6d11b024c8712 100644 --- a/lib/SimpleSAML/Auth/Source.php +++ b/lib/SimpleSAML/Auth/Source.php @@ -178,6 +178,81 @@ abstract class SimpleSAML_Auth_Source { return self::parseAuthSource($authId, $authConfig); } + + /** + * Add a logout callback association. + * + * This function adds a logout callback association, which allows us to initiate + * a logout later based on the $assoc-value. + * + * Note that logout-associations exists per authentication source. A logout association + * from one authentication source cannot be called from a different authentication source. + * + * @param string $assoc The identifier for this logout association. + * @param array $state The state array passed to the authenticate-function. + */ + protected function addLogoutCallback($assoc, $state) { + assert('is_string($assoc)'); + assert('is_array($state)'); + + if (!array_key_exists('LogoutCallback', $state)) { + /* The authentication requester doesn't have a logout callback. */ + return; + } + $callback = $state['LogoutCallback']; + + if (array_key_exists('LogoutCallbackState', $state)) { + $callbackState = $state['LogoutCallbackState']; + } else { + $callbackState = array(); + } + + $id = strlen($this->authId) . ':' . $this->authId . $assoc; + + $data = array( + 'callback' => $callback, + 'state' => $callbackState, + ); + + + $session = SimpleSAML_Session::getInstance(); + $session->setData('SimpleSAML_Auth_Source.LogoutCallbacks', $id, $data, + SimpleSAML_Session::DATA_TIMEOUT_LOGOUT); + } + + + /** + * Call a logout callback based on association. + * + * This function calls a logout callback based on an association saved with + * addLogoutCallback(...). + * + * This function always returns. + * + * @param string $assoc The logout association which should be called. + */ + protected function callLogoutCallback($assoc) { + assert('is_string($assoc)'); + + $id = strlen($this->authId) . ':' . $this->authId . $assoc; + + $session = SimpleSAML_Session::getInstance(); + + $data = $session->getData('SimpleSAML_Auth_Source.LogoutCallbacks', $id); + if ($data === NULL) { + return; + } + + assert('is_array($data)'); + assert('array_key_exists("callback", $data)'); + assert('array_key_exists("state", $data)'); + + $callback = $data['callback']; + $callbackState = $data['state']; + + call_user_func($callback, $callbackState); + } + } ?> \ No newline at end of file