From f71b08f32dd3ef8c6427a1d741081d49a6a47357 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Mon, 10 Nov 2008 13:01:32 +0000
Subject: [PATCH] Auth/{Source,Default}: add support for logout callbacks, for
 receiving external logout notifications.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@984 44740490-163a-0410-bde0-09ae8108e29a
---
 lib/SimpleSAML/Auth/Default.php | 29 +++++++++++++
 lib/SimpleSAML/Auth/Source.php  | 75 +++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php
index 5f620a341..2f35a96a3 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 c76951852..f0a0c948b 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
-- 
GitLab