diff options
author | tailor <me@arty.name> | 2008-02-02 19:47:09 +0000 |
---|---|---|
committer | tailor <me@arty.name> | 2008-02-02 19:47:09 +0000 |
commit | ae4e3f1cf0c475373faef7fc9df5cf2c865affcd (patch) | |
tree | 860e7ff1806c8a74410cb8ed100ebd8ad1e8afc0 /Auth | |
parent | 20ab579497a3df8f81a0bfb2607238a31b0b2b1b (diff) | |
download | php-openid-ae4e3f1cf0c475373faef7fc9df5cf2c865affcd.zip php-openid-ae4e3f1cf0c475373faef7fc9df5cf2c865affcd.tar.gz php-openid-ae4e3f1cf0c475373faef7fc9df5cf2c865affcd.tar.bz2 |
[project @ Implementation of Memcached storage in PHP. This patch also includes supportsCleanup() function for OpenIDStore interface, as memcache doesn't allow ]
enumeration of all keys used (and cleans itself).
Also included test for memcached storage and support for supportsCleanup() in test functions.
Diffstat (limited to 'Auth')
-rw-r--r-- | Auth/OpenID/Interface.php | 8 | ||||
-rw-r--r-- | Auth/OpenID/MemcachedStore.php | 207 |
2 files changed, 215 insertions, 0 deletions
diff --git a/Auth/OpenID/Interface.php b/Auth/OpenID/Interface.php index eeb130a..38fe369 100644 --- a/Auth/OpenID/Interface.php +++ b/Auth/OpenID/Interface.php @@ -94,6 +94,14 @@ class Auth_OpenID_OpenIDStore { } /** + * Report whether this storage supports cleanup + */ + function supportsCleanup() + { + return true; + } + + /** * This method returns an Association object from storage that * matches the server URL and, if specified, handle. It returns * null if no such association is found or if the matching diff --git a/Auth/OpenID/MemcachedStore.php b/Auth/OpenID/MemcachedStore.php new file mode 100644 index 0000000..7f9b180 --- /dev/null +++ b/Auth/OpenID/MemcachedStore.php @@ -0,0 +1,207 @@ +<?php + +/** + * This file supplies a memcached store backend for OpenID servers and + * consumers. + * + * PHP versions 4 and 5 + * + * LICENSE: See the COPYING file included in this distribution. + * + * @package OpenID + * @author Artemy Tregubenko <me@arty.name> + * @copyright Open Web Technologies <http://openwebtech.ru/> + * @license http://www.gnu.org/copyleft/lesser.html LGPL + */ + +/** + * Import the interface for creating a new store class. + */ +require_once 'Auth/OpenID/Interface.php'; + +/** + * This is a memcached-based store for OpenID associations and + * nonces. + * + * As memcache has limit of 250 chars for key length, + * server_url, handle and salt are hashed with sha1(). + * + * Most of the methods of this class are implementation details. + * People wishing to just use this store need only pay attention to + * the constructor. + * + * @package OpenID + */ +class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore { + + /** + * Initializes a new {@link Auth_OpenID_MemcachedStore} instance. + * Just saves memcached object as property. + * + * @param resource connection Memcache connection resourse + */ + function Auth_OpenID_MemcachedStore($connection, $compress = false) + { + $this->connection = $connection; + $this->compress = $compress ? MEMCACHE_COMPRESSED : 0; + } + + /** + * Store association until its expiration time in memcached. + * Overwrites any existing association with same server_url and + * handle. Handles list of associations for every server. + */ + function storeAssociation($server_url, $association) + { + // create memcached keys for association itself + // and list of associations for this server + $associationKey = $this->associationKey($server_url, + $association->handle); + $serverKey = $this->associationServerKey($server_url); + + // get list of associations + $serverAssociations = $this->connection->get($serverKey); + + // if no such list, initialize it with empty array + if (!$serverAssociations) { + $serverAssociations = array(); + } + // and store given association key in it + $serverAssociations[$association->issued] = $associationKey; + + // save associations' keys list + $this->connection->set( + $serverKey, + $serverAssociations, + $this->compress + ); + // save association itself + $this->connection->set( + $associationKey, + $association, + $this->compress, + $association->issued + $association->lifetime); + } + + /** + * Read association from memcached. If no handle given + * and multiple associations found, returns latest issued + */ + function getAssociation($server_url, $handle = null) + { + // simple case: handle given + if ($handle !== null) { + // get association, return null if failed + $association = $this->connection->get( + $this->associationKey($server_url, $handle)); + return $association ? $association : null; + } + + // no handle given, working with list + // create key for list of associations + $serverKey = $this->associationServerKey($server_url); + + // get list of associations + $serverAssociations = $this->connection->get($serverKey); + // return null if failed or got empty list + if (!$serverAssociations) { + return null; + } + + // get key of most recently issued association + $keys = array_keys($serverAssociations); + sort($keys); + $lastKey = $serverAssociations[array_pop($keys)]; + + // get association, return null if failed + $association = $this->connection->get($lastKey); + return $association ? $association : null; + } + + /** + * Immediately delete association from memcache. + */ + function removeAssociation($server_url, $handle) + { + // create memcached keys for association itself + // and list of associations for this server + $serverKey = $this->associationServerKey($server_url); + $associationKey = $this->associationKey($server_url, + $handle); + + // get list of associations + $serverAssociations = $this->connection->get($serverKey); + // return null if failed or got empty list + if (!$serverAssociations) { + return false; + } + + // ensure that given association key exists in list + $serverAssociations = array_flip($serverAssociations); + if (!array_key_exists($associationKey, $serverAssociations)) { + return false; + } + + // remove given association key from list + unset($serverAssociations[$associationKey]); + $serverAssociations = array_flip($serverAssociations); + + // save updated list + $this->connection->set( + $serverKey, + $serverAssociations, + $this->compress + ); + + // delete association + return $this->connection->delete($associationKey); + } + + /** + * Create nonce for server and salt, expiring after + * $Auth_OpenID_SKEW seconds. + */ + function useNonce($server_url, $timestamp, $salt) + { + global $Auth_OpenID_SKEW; + + // save one request to memcache when nonce obviously expired + if (abs($timestamp - time()) > $Auth_OpenID_SKEW) { + return false; + } + + // returns false when nonce already exists + // otherwise adds nonce + return $this->connection->add( + 'openid_nonce_' . sha1($server_url) . '_' . sha1($salt), + 1, // any value here + $this->compress, + $Auth_OpenID_SKEW); + } + + /** + * Memcache key is prefixed with 'openid_association_' string. + */ + function associationKey($server_url, $handle = null) + { + return 'openid_association_' . sha1($server_url) . '_' . sha1($handle); + } + + /** + * Memcache key is prefixed with 'openid_association_' string. + */ + function associationServerKey($server_url) + { + return 'openid_association_server_' . sha1($server_url); + } + + /** + * Report that this storage doesn't support cleanup + */ + function supportsCleanup() + { + return false; + } +} + +?>
\ No newline at end of file |