123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- <?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->expireat($serverKey, $newExpiration);
- $this->redis->expireat($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->lindex($serverKey, -1);
- if (!$lastKey) {
- // no previous association with this server
- 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->redis->setnx($nonceKey, "1");
- if ($added) {
- // Will set expiration
- $this->redis->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;
- }
- }
|