TYPO3 API  SVNRelease
MemcachedStore.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /**
00004  * This file supplies a memcached store backend for OpenID servers and
00005  * consumers.
00006  *
00007  * PHP versions 4 and 5
00008  *
00009  * LICENSE: See the COPYING file included in this distribution.
00010  *
00011  * @package OpenID
00012  * @author Artemy Tregubenko <me@arty.name>
00013  * @copyright 2008 JanRain, Inc.
00014  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
00015  * Contributed by Open Web Technologies <http://openwebtech.ru/>
00016  */
00017 
00018 /**
00019  * Import the interface for creating a new store class.
00020  */
00021 require_once 'Auth/OpenID/Interface.php';
00022 
00023 /**
00024  * This is a memcached-based store for OpenID associations and
00025  * nonces.
00026  *
00027  * As memcache has limit of 250 chars for key length,
00028  * server_url, handle and salt are hashed with sha1().
00029  *
00030  * Most of the methods of this class are implementation details.
00031  * People wishing to just use this store need only pay attention to
00032  * the constructor.
00033  *
00034  * @package OpenID
00035  */
00036 class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {
00037 
00038     /**
00039      * Initializes a new {@link Auth_OpenID_MemcachedStore} instance.
00040      * Just saves memcached object as property.
00041      *
00042      * @param resource connection Memcache connection resourse
00043      */
00044     function Auth_OpenID_MemcachedStore($connection, $compress = false)
00045     {
00046         $this->connection = $connection;
00047         $this->compress = $compress ? MEMCACHE_COMPRESSED : 0;
00048     }
00049 
00050     /**
00051      * Store association until its expiration time in memcached.
00052      * Overwrites any existing association with same server_url and
00053      * handle. Handles list of associations for every server.
00054      */
00055     function storeAssociation($server_url, $association)
00056     {
00057         // create memcached keys for association itself
00058         // and list of associations for this server
00059         $associationKey = $this->associationKey($server_url,
00060             $association->handle);
00061         $serverKey = $this->associationServerKey($server_url);
00062 
00063         // get list of associations
00064         $serverAssociations = $this->connection->get($serverKey);
00065 
00066         // if no such list, initialize it with empty array
00067         if (!$serverAssociations) {
00068             $serverAssociations = array();
00069         }
00070         // and store given association key in it
00071         $serverAssociations[$association->issued] = $associationKey;
00072 
00073         // save associations' keys list
00074         $this->connection->set(
00075             $serverKey,
00076             $serverAssociations,
00077             $this->compress
00078         );
00079         // save association itself
00080         $this->connection->set(
00081             $associationKey,
00082             $association,
00083             $this->compress,
00084             $association->issued + $association->lifetime);
00085     }
00086 
00087     /**
00088      * Read association from memcached. If no handle given
00089      * and multiple associations found, returns latest issued
00090      */
00091     function getAssociation($server_url, $handle = null)
00092     {
00093         // simple case: handle given
00094         if ($handle !== null) {
00095             // get association, return null if failed
00096             $association = $this->connection->get(
00097                 $this->associationKey($server_url, $handle));
00098             return $association ? $association : null;
00099         }
00100 
00101         // no handle given, working with list
00102         // create key for list of associations
00103         $serverKey = $this->associationServerKey($server_url);
00104 
00105         // get list of associations
00106         $serverAssociations = $this->connection->get($serverKey);
00107         // return null if failed or got empty list
00108         if (!$serverAssociations) {
00109             return null;
00110         }
00111 
00112         // get key of most recently issued association
00113         $keys = array_keys($serverAssociations);
00114         sort($keys);
00115         $lastKey = $serverAssociations[array_pop($keys)];
00116 
00117         // get association, return null if failed
00118         $association = $this->connection->get($lastKey);
00119         return $association ? $association : null;
00120     }
00121 
00122     /**
00123      * Immediately delete association from memcache.
00124      */
00125     function removeAssociation($server_url, $handle)
00126     {
00127         // create memcached keys for association itself
00128         // and list of associations for this server
00129         $serverKey = $this->associationServerKey($server_url);
00130         $associationKey = $this->associationKey($server_url,
00131             $handle);
00132 
00133         // get list of associations
00134         $serverAssociations = $this->connection->get($serverKey);
00135         // return null if failed or got empty list
00136         if (!$serverAssociations) {
00137             return false;
00138         }
00139 
00140         // ensure that given association key exists in list
00141         $serverAssociations = array_flip($serverAssociations);
00142         if (!array_key_exists($associationKey, $serverAssociations)) {
00143             return false;
00144         }
00145 
00146         // remove given association key from list
00147         unset($serverAssociations[$associationKey]);
00148         $serverAssociations = array_flip($serverAssociations);
00149 
00150         // save updated list
00151         $this->connection->set(
00152             $serverKey,
00153             $serverAssociations,
00154             $this->compress
00155         );
00156 
00157         // delete association
00158         return $this->connection->delete($associationKey);
00159     }
00160 
00161     /**
00162      * Create nonce for server and salt, expiring after
00163      * $Auth_OpenID_SKEW seconds.
00164      */
00165     function useNonce($server_url, $timestamp, $salt)
00166     {
00167         global $Auth_OpenID_SKEW;
00168 
00169         // save one request to memcache when nonce obviously expired
00170         if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
00171             return false;
00172         }
00173 
00174         // returns false when nonce already exists
00175         // otherwise adds nonce
00176         return $this->connection->add(
00177             'openid_nonce_' . sha1($server_url) . '_' . sha1($salt),
00178             1, // any value here
00179             $this->compress,
00180             $Auth_OpenID_SKEW);
00181     }
00182 
00183     /**
00184      * Memcache key is prefixed with 'openid_association_' string.
00185      */
00186     function associationKey($server_url, $handle = null)
00187     {
00188         return 'openid_association_' . sha1($server_url) . '_' . sha1($handle);
00189     }
00190 
00191     /**
00192      * Memcache key is prefixed with 'openid_association_' string.
00193      */
00194     function associationServerKey($server_url)
00195     {
00196         return 'openid_association_server_' . sha1($server_url);
00197     }
00198 
00199     /**
00200      * Report that this storage doesn't support cleanup
00201      */
00202     function supportsCleanup()
00203     {
00204         return false;
00205     }
00206 }
00207 
00208 ?>