* @copyright 2008 JanRain, Inc. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache * Contributed by Open Web Technologies */ /** * 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 { /** @var int */ private $compress = 0; /** @var Memcache */ private $connection; /** * Initializes a new {@link Auth_OpenID_MemcachedStore} instance. * Just saves memcached object as property. * * @param Memcache $connection Memcache connection resource * @param bool $compress */ function __construct($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. * * @param string $server_url * @param Auth_OpenID_Association $association */ 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 * * @param string $server_url * @param null $handle * @return Auth_OpenID_Association|null */ 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. * * @param string $server_url * @param string $handle * @return bool|mixed */ 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. * * @param string $server_url * @param int $timestamp * @param string $salt * @return bool */ 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. * * @param string $server_url * @param null $handle * @return string */ function associationKey($server_url, $handle = null) { return 'openid_association_' . sha1($server_url) . '_' . sha1($handle); } /** * Memcache key is prefixed with 'openid_association_' string. * * @param string $server_url * @return string */ function associationServerKey($server_url) { return 'openid_association_server_' . sha1($server_url); } /** * Report that this storage doesn't support cleanup */ function supportsCleanup() { return false; } }