From a7e38a70fa4ce0f9ebdea85d8cde422046b401d1 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Mon, 9 Aug 2010 08:51:02 +0000
Subject: [PATCH] Implement datastore API, for session storage and other data.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2490 44740490-163a-0410-bde0-09ae8108e29a
---
 config-templates/config.php               | 16 ++---
 lib/SimpleSAML/SessionHandler.php         | 26 ++-----
 lib/SimpleSAML/SessionHandlerMemcache.php | 73 --------------------
 lib/SimpleSAML/SessionHandlerStore.php    | 77 +++++++++++++++++++++
 lib/SimpleSAML/Store.php                  | 84 +++++++++++++++++++++++
 lib/SimpleSAML/Store/Memcache.php         | 63 +++++++++++++++++
 6 files changed, 237 insertions(+), 102 deletions(-)
 delete mode 100644 lib/SimpleSAML/SessionHandlerMemcache.php
 create mode 100644 lib/SimpleSAML/SessionHandlerStore.php
 create mode 100644 lib/SimpleSAML/Store.php
 create mode 100644 lib/SimpleSAML/Store/Memcache.php

diff --git a/config-templates/config.php b/config-templates/config.php
index d0f3dc454..0d3822152 100644
--- a/config-templates/config.php
+++ b/config-templates/config.php
@@ -381,16 +381,16 @@ $config = array (
 
 
 	/*
-	 * This configuration option allows you to select which session handler
-	 * SimpleSAMLPHP should use to store the session information. Currently
-	 * we have two session handlers:
-	 * - 'phpsession': The default PHP session handler.
-	 * - 'memcache': Stores the session information in one or more
-	 *   memcache servers by using the MemcacheStore class.
+	 * Configure the datastore for simpleSAMLphp.
 	 *
-	 * The default session handler is 'phpsession'.
+	 * - 'phpsession': Limited datastore, which uses the PHP session.
+	 * - 'memcache': Key-value datastore, based on memcache.
+	 *
+	 * The default datastore is 'phpsession'.
+	 *
+	 * (This option replaces the old 'session.handler'-option.)
 	 */
-	'session.handler'       => 'phpsession',
+	'store.type' => 'phpsession',
 
 
 	/*
diff --git a/lib/SimpleSAML/SessionHandler.php b/lib/SimpleSAML/SessionHandler.php
index b3dbfceb3..90eb51162 100644
--- a/lib/SimpleSAML/SessionHandler.php
+++ b/lib/SimpleSAML/SessionHandler.php
@@ -81,28 +81,12 @@ abstract class SimpleSAML_SessionHandler {
 	 */
 	private static function createSessionHandler() {
 
-		/* Get the configuration. */
-		$config = SimpleSAML_Configuration::getInstance();
-		assert($config instanceof SimpleSAML_Configuration);
-
-		/* Get the session handler option from the configuration. */
-		$handler = $config->getString('session.handler', 'phpsession');
-		$handler = strtolower($handler);
-
-		switch ($handler) {
-		case 'phpsession':
-			$sh = new SimpleSAML_SessionHandlerPHP();
-			break;
-		case 'memcache':
-			$sh = new SimpleSAML_SessionHandlerMemcache();
-			break;
-		default:
-			throw new SimpleSAML_Error_Exception(
-				'Invalid session handler specified in the \'session.handler\'-option.');
+		$store = SimpleSAML_Store::getInstance();
+		if ($store === FALSE) {
+			self::$sessionHandler = new SimpleSAML_SessionHandlerPHP();
+		} else {
+			self::$sessionHandler = new SimpleSAML_SessionHandlerStore($store);
 		}
-
-		/* Set the session handler. */
-		self::$sessionHandler = $sh;
 	}
 
 
diff --git a/lib/SimpleSAML/SessionHandlerMemcache.php b/lib/SimpleSAML/SessionHandlerMemcache.php
deleted file mode 100644
index 48a562267..000000000
--- a/lib/SimpleSAML/SessionHandlerMemcache.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-
-/**
- * This file is part of SimpleSAMLphp. See the file COPYING in the
- * root of the distribution for licence information.
- *
- * This file defines a session handler which uses the MemcacheStore
- * class to store data in memcache servers.
- *
- * @author Olav Morken, UNINETT AS. <andreas.solberg@uninett.no>
- * @package simpleSAMLphp
- * @version $Id$
- */
-class SimpleSAML_SessionHandlerMemcache
-extends SimpleSAML_SessionHandlerCookie {
-
-	/* Initialize the memcache session handling. This constructor is
-	 * protected because it should only be called from
-	 * SimpleSAML_SessionHandler::createSessionHandler(...).
-	 */
-	protected function __construct() {
-
-		/* Call parent constructor to allow it to configure the session
-		 * id.
-		 */
-		parent::__construct();
-	}
-
-
-	/**
-	 * Save the current session to memcache.
-	 *
-	 * @param SimpleSAML_Session $session  The session object we should save.
-	 */
-	public function saveSession(SimpleSAML_Session $session) {
-
-		SimpleSAML_Memcache::set('simpleSAMLphp.session.' . $this->session_id, $session);
-	}
-
-
-	/**
-	 * Load the session from memcache.
-	 *
-	 * @return SimpleSAML_Session|NULL  The session object, or NULL if it doesn't exist.
-	 */
-	public function loadSession() {
-
-		$session = SimpleSAML_Memcache::get('simpleSAMLphp.session.' . $this->session_id);
-		if ($session !== NULL) {
-			assert('$session instanceof SimpleSAML_Session');
-			return $session;
-		}
-
-		/* For backwards compatibility, check the MemcacheStore object. */
-		$store = SimpleSAML_MemcacheStore::find($this->session_id);
-		if ($store === NULL) {
-			return NULL;
-		}
-
-		$session = $store->get('SimpleSAMLphp_SESSION');
-		if ($session === NULL) {
-			return NULL;
-		}
-
-		assert('is_string($session)');
-
-		$session = unserialize($session);
-		assert('$session instanceof SimpleSAML_Session');
-
-		return $session;
-	}
-
-}
diff --git a/lib/SimpleSAML/SessionHandlerStore.php b/lib/SimpleSAML/SessionHandlerStore.php
new file mode 100644
index 000000000..d17b25be5
--- /dev/null
+++ b/lib/SimpleSAML/SessionHandlerStore.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Session storage in the datastore.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SimpleSAML_SessionHandlerStore extends SimpleSAML_SessionHandlerCookie {
+
+	/**
+	 * The datastore we save the session to.
+	 */
+	private $store;
+
+	/**
+	 * Initialize the session handlerstore.
+	 */
+	protected function __construct(SimpleSAML_Store $store) {
+		parent::__construct();
+
+		$this->store = $store;
+	}
+
+
+	/**
+	 * Load the session from the datastore.
+	 *
+	 * @return SimpleSAML_Session|NULL  The session object, or NULL if it doesn't exist.
+	 */
+	public function loadSession() {
+
+		$session = $this->store->get('session', $this->session_id);
+		if ($session !== NULL) {
+			assert('$session instanceof SimpleSAML_Session');
+			return $session;
+		}
+
+		if (!($this->store instanceof SimpleSAML_Store_Memcache)) {
+			return NULL;
+		}
+
+		/* For backwards compatibility, check the MemcacheStore object. */
+		$store = SimpleSAML_MemcacheStore::find($this->session_id);
+		if ($store === NULL) {
+			return NULL;
+		}
+
+		$session = $store->get('SimpleSAMLphp_SESSION');
+		if ($session === NULL) {
+			return NULL;
+		}
+
+		assert('is_string($session)');
+
+		$session = unserialize($session);
+		assert('$session instanceof SimpleSAML_Session');
+
+		return $session;
+	}
+
+
+	/**
+	 * Save the current session to the datastore.
+	 *
+	 * @param SimpleSAML_Session $session  The session object we should save.
+	 */
+	public function saveSession(SimpleSAML_Session $session) {
+
+		$config = SimpleSAML_Configuration::getInstance();
+		$sessionDuration = $config->getInteger('session.duration', 8*60*60);
+		$expire = time() + $sessionDuration;
+
+		$this->store->set('session', $this->session_id, $session, $expire);
+	}
+
+}
diff --git a/lib/SimpleSAML/Store.php b/lib/SimpleSAML/Store.php
new file mode 100644
index 000000000..db2046551
--- /dev/null
+++ b/lib/SimpleSAML/Store.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * Base class for datastores.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+abstract class SimpleSAML_Store {
+
+	/**
+	 * Our singleton instance.
+	 *
+	 * This is FALSE if the datastore isn't enabled, and NULL
+	 * if we haven't attempted to initialize it.
+	 *
+	 * @var SimpleSAML_Store|FALSE|NULL
+	 */
+	private static $instance;
+
+
+	/**
+	 * Retrieve our singleton instance.
+	 *
+	 * @return SimpleSAML_Store|FALSE  The datastore, or FALSE if it isn't enabled.
+	 */
+	public static function getInstance() {
+
+		if (self::$instance !== NULL) {
+			return self::$instance;
+		}
+
+		$config = SimpleSAML_Configuration::getInstance();
+		$storeType = $config->getString('store.type', NULL);
+		if ($storeType === NULL) {
+			$storeType = $config->getString('session.handler', 'phpsession');
+		}
+
+		switch ($storeType) {
+		case 'phpsession':
+			/* We cannot support advanced features with the PHP session store. */
+			self::$instance = FALSE;
+			break;
+		case 'memcache':
+			self::$instance = new SimpleSAML_Store_Memcache();
+			break;
+		default:
+			throw new SimpleSAML_Error_Exception('Unknown datastore type: ' . var_export($storeType, TRUE));
+		}
+
+		return self::$instance;
+	}
+
+
+	/**
+	 * Retrieve a value from the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 * @return mixed|NULL  The value.
+	 */
+	abstract public function get($type, $key);
+
+
+	/**
+	 * Save a value to the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 * @param mixed $value  The value.
+	 * @param int|NULL $expire  The expiration time (unix timestamp), or NULL if it never expires.
+	 */
+	abstract public function set($type, $key, $value, $expire = NULL);
+
+
+	/**
+	 * Delete a value from the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 */
+	abstract public function delete($type, $key);
+
+}
diff --git a/lib/SimpleSAML/Store/Memcache.php b/lib/SimpleSAML/Store/Memcache.php
new file mode 100644
index 000000000..b7a0181ea
--- /dev/null
+++ b/lib/SimpleSAML/Store/Memcache.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * A memcache based datastore.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SimpleSAML_Store_Memcache extends SimpleSAML_Store {
+
+	/**
+	 * Initialize the memcache datastore.
+	 */
+	protected function __construct() {
+	}
+
+
+	/**
+	 * Retrieve a value from the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 * @return mixed|NULL  The value.
+	 */
+	public function get($type, $key) {
+		assert('is_string($type)');
+		assert('is_string($key)');
+
+		return SimpleSAML_Memcache::get('simpleSAMLphp.' . $type . '.' . $key);
+	}
+
+
+	/**
+	 * Save a value to the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 * @param mixed $value  The value.
+	 * @param int|NULL $expire  The expiration time (unix timestamp), or NULL if it never expires.
+	 */
+	public function set($type, $key, $value, $expire = NULL) {
+		assert('is_string($type)');
+		assert('is_string($key)');
+		assert('is_null($expire) || (is_int($expire) && $expire > 2592000)');
+
+		SimpleSAML_Memcache::set('simpleSAMLphp.' . $type . '.' . $key, $value, $expire);
+	}
+
+
+	/**
+	 * Delete a value from the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 */
+	public function delete($type, $key) {
+		assert('is_string($type)');
+		assert('is_string($key)');
+
+		SimpleSAML_Memcache::delete('simpleSAMLphp.' . $type . '.' . $key, $value, $expire);
+	}
+
+}
-- 
GitLab