diff options
author | Marco Ceppi <marco@ceppi.net> | 2013-08-17 00:59:33 -0700 |
---|---|---|
committer | Marco Ceppi <marco@ceppi.net> | 2013-08-17 00:59:33 -0700 |
commit | 3fbd48beb68d75cc3ab3e8246f85018f9cf673e2 (patch) | |
tree | 9663acc142121ae36a394748ba1f45b328402e52 /Auth | |
parent | 625c16bb28bb120d262b3f19f89c2c06cb9b0da9 (diff) | |
parent | 0bc8cae924c79e93ca1c0b4daaa0d527d9d1c348 (diff) | |
download | php-openid-3fbd48beb68d75cc3ab3e8246f85018f9cf673e2.zip php-openid-3fbd48beb68d75cc3ab3e8246f85018f9cf673e2.tar.gz php-openid-3fbd48beb68d75cc3ab3e8246f85018f9cf673e2.tar.bz2 |
Merge pull request #103 from vmattila/predis-store
Implemented PredisStore to provide association store for Redis servers.
Diffstat (limited to 'Auth')
-rw-r--r-- | Auth/OpenID/PredisStore.php | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/Auth/OpenID/PredisStore.php b/Auth/OpenID/PredisStore.php new file mode 100644 index 0000000..595ecb6 --- /dev/null +++ b/Auth/OpenID/PredisStore.php @@ -0,0 +1,208 @@ +<?php + +/** + * Supplies Redis server store backend for OpenID servers and consumers. + * Uses Predis library {@see https://github.com/nrk/predis}. + * Requires PHP >= 5.3. + * + * LICENSE: See the COPYING file included in this distribution. + * + * @package OpenID + * @author Ville Mattila <ville@eventio.fi> + * @copyright 2008 JanRain Inc., 2013 Eventio Oy / Ville Mattila + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache + * Contributed by Eventio Oy <http://www.eventio.fi/> + */ + +/** + * Import the interface for creating a new store class. + */ +require_once 'Auth/OpenID/Interface.php'; + +/** + * Supplies Redis server store backend for OpenID servers and consumers. + * Uses Predis library {@see https://github.com/nrk/predis}. + * Requires PHP >= 5.3. + * + * @package OpenID + */ +class Auth_OpenID_PredisStore extends Auth_OpenID_OpenIDStore { + + /** + * @var \Predis\Client + */ + protected $redis; + + /** + * Prefix for Redis keys + * @var string + */ + protected $prefix; + + /** + * Initializes a new {@link Auth_OpenID_PredisStore} instance. + * + * @param \Predis\Client $redis Predis client object + * @param string $prefix Prefix for all keys stored to the Redis + */ + function Auth_OpenID_PredisStore(\Predis\Client $redis, $prefix = '') + { + $this->prefix = $prefix; + $this->redis = $redis; + } + + /** + * Store association until its expiration time in Redis server. + * Overwrites any existing association with same server_url and + * handle. Handles list of associations for every server. + */ + function storeAssociation($server_url, $association) + { + // create Redis keys for association itself + // and list of associations for this server + $associationKey = $this->associationKey($server_url, + $association->handle); + $serverKey = $this->associationServerKey($server_url); + + // save association to server's associations' keys list + $this->redis->lpush( + $serverKey, + $associationKey + ); + + // Will touch the association list expiration, to avoid filling up + $newExpiration = ($association->issued + $association->lifetime); + + $expirationKey = $serverKey.'_expires_at'; + $expiration = $this->redis->get($expirationKey); + if (!$expiration || $newExpiration > $expiration) { + $this->redis->set($expirationKey, $newExpiration); + $this->redis->expiresat($serverKey, $newExpiration); + $this->redis->expiresat($expirationKey, $newExpiration); + } + + // save association itself, will automatically expire + $this->redis->setex( + $associationKey, + $newExpiration - time(), + serialize($association) + ); + } + + /** + * Read association from Redis. If no handle given + * and multiple associations found, returns latest issued + */ + function getAssociation($server_url, $handle = null) + { + // simple case: handle given + if ($handle !== null) { + return $this->getAssociationFromServer( + $this->associationKey($server_url, $handle) + ); + } + + // no handle given, receiving the latest issued + $serverKey = $this->associationServerKey($server_url); + $lastKey = $this->redis->lpop($serverKey); + if (!$lastKey) { return null; } + + // get association, return null if failed + return $this->getAssociationFromServer($lastKey); + } + + /** + * Function to actually receive and unserialize the association + * from the server. + */ + private function getAssociationFromServer($associationKey) + { + $association = $this->redis->get($associationKey); + return $association ? unserialize($association) : null; + } + + /** + * Immediately delete association from Redis. + */ + function removeAssociation($server_url, $handle) + { + // create Redis keys + $serverKey = $this->associationServerKey($server_url); + $associationKey = $this->associationKey($server_url, + $handle); + + // Removing the association from the server's association list + $removed = $this->redis->lrem($serverKey, 0, $associationKey); + if ($removed < 1) { + return false; + } + + // Delete the association itself + return $this->redis->del($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; + } + + // SETNX will set the value only of the key doesn't exist yet. + $nonceKey = $this->nonceKey($server_url, $salt); + $added = $this->predis->setnx($nonceKey); + if ($added) { + // Will set expiration + $this->predis->expire($nonceKey, $Auth_OpenID_SKEW); + return true; + } else { + return false; + } + } + + /** + * Build up nonce key + */ + private function nonceKey($server_url, $salt) + { + return $this->prefix . + 'openid_nonce_' . + sha1($server_url) . '_' . sha1($salt); + } + + /** + * Key is prefixed with $prefix and 'openid_association_' string + */ + function associationKey($server_url, $handle = null) + { + return $this->prefix . + 'openid_association_' . + sha1($server_url) . '_' . sha1($handle); + } + + /** + * Key is prefixed with $prefix and 'openid_association_server_' string + */ + function associationServerKey($server_url) + { + return $this->prefix . + 'openid_association_server_' . + sha1($server_url); + } + + /** + * Report that this storage doesn't support cleanup + */ + function supportsCleanup() + { + return false; + } + +} + |