final move of files
[web.mtrack] / Auth / OpenID / MemcachedStore.php
1 <?php
2
3 /**
4  * This file supplies a memcached store backend for OpenID servers and
5  * consumers.
6  *
7  * PHP versions 4 and 5
8  *
9  * LICENSE: See the COPYING file included in this distribution.
10  *
11  * @package OpenID
12  * @author Artemy Tregubenko <me@arty.name>
13  * @copyright 2008 JanRain, Inc.
14  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
15  * Contributed by Open Web Technologies <http://openwebtech.ru/>
16  */
17
18 /**
19  * Import the interface for creating a new store class.
20  */
21 require_once 'Auth/OpenID/Interface.php';
22
23 /**
24  * This is a memcached-based store for OpenID associations and
25  * nonces. 
26  * 
27  * As memcache has limit of 250 chars for key length, 
28  * server_url, handle and salt are hashed with sha1(). 
29  *
30  * Most of the methods of this class are implementation details.
31  * People wishing to just use this store need only pay attention to
32  * the constructor.
33  *
34  * @package OpenID
35  */
36 class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {
37
38     /**
39      * Initializes a new {@link Auth_OpenID_MemcachedStore} instance.
40      * Just saves memcached object as property.
41      *
42      * @param resource connection Memcache connection resourse
43      */
44     function Auth_OpenID_MemcachedStore($connection, $compress = false)
45     {
46         $this->connection = $connection;
47         $this->compress = $compress ? MEMCACHE_COMPRESSED : 0;
48     }
49
50     /**
51      * Store association until its expiration time in memcached. 
52      * Overwrites any existing association with same server_url and 
53      * handle. Handles list of associations for every server. 
54      */
55     function storeAssociation($server_url, $association)
56     {
57         // create memcached keys for association itself 
58         // and list of associations for this server
59         $associationKey = $this->associationKey($server_url, 
60             $association->handle);
61         $serverKey = $this->associationServerKey($server_url);
62         
63         // get list of associations 
64         $serverAssociations = $this->connection->get($serverKey);
65         
66         // if no such list, initialize it with empty array
67         if (!$serverAssociations) {
68             $serverAssociations = array();
69         }
70         // and store given association key in it
71         $serverAssociations[$association->issued] = $associationKey;
72         
73         // save associations' keys list 
74         $this->connection->set(
75             $serverKey,
76             $serverAssociations,
77             $this->compress
78         );
79         // save association itself
80         $this->connection->set(
81             $associationKey,
82             $association, 
83             $this->compress, 
84             $association->issued + $association->lifetime);
85     }
86
87     /**
88      * Read association from memcached. If no handle given 
89      * and multiple associations found, returns latest issued
90      */
91     function getAssociation($server_url, $handle = null)
92     {
93         // simple case: handle given
94         if ($handle !== null) {
95             // get association, return null if failed
96             $association = $this->connection->get(
97                 $this->associationKey($server_url, $handle));
98             return $association ? $association : null;
99         }
100         
101         // no handle given, working with list
102         // create key for list of associations
103         $serverKey = $this->associationServerKey($server_url);
104         
105         // get list of associations
106         $serverAssociations = $this->connection->get($serverKey);
107         // return null if failed or got empty list
108         if (!$serverAssociations) {
109             return null;
110         }
111         
112         // get key of most recently issued association
113         $keys = array_keys($serverAssociations);
114         sort($keys);
115         $lastKey = $serverAssociations[array_pop($keys)];
116         
117         // get association, return null if failed
118         $association = $this->connection->get($lastKey);
119         return $association ? $association : null;
120     }
121
122     /**
123      * Immediately delete association from memcache.
124      */
125     function removeAssociation($server_url, $handle)
126     {
127         // create memcached keys for association itself 
128         // and list of associations for this server
129         $serverKey = $this->associationServerKey($server_url);
130         $associationKey = $this->associationKey($server_url, 
131             $handle);
132         
133         // get list of associations
134         $serverAssociations = $this->connection->get($serverKey);
135         // return null if failed or got empty list
136         if (!$serverAssociations) {
137             return false;
138         }
139         
140         // ensure that given association key exists in list
141         $serverAssociations = array_flip($serverAssociations);
142         if (!array_key_exists($associationKey, $serverAssociations)) {
143             return false;
144         }
145         
146         // remove given association key from list
147         unset($serverAssociations[$associationKey]);
148         $serverAssociations = array_flip($serverAssociations);
149         
150         // save updated list
151         $this->connection->set(
152             $serverKey,
153             $serverAssociations,
154             $this->compress
155         );
156
157         // delete association 
158         return $this->connection->delete($associationKey);
159     }
160
161     /**
162      * Create nonce for server and salt, expiring after 
163      * $Auth_OpenID_SKEW seconds.
164      */
165     function useNonce($server_url, $timestamp, $salt)
166     {
167         global $Auth_OpenID_SKEW;
168         
169         // save one request to memcache when nonce obviously expired 
170         if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
171             return false;
172         }
173         
174         // returns false when nonce already exists
175         // otherwise adds nonce
176         return $this->connection->add(
177             'openid_nonce_' . sha1($server_url) . '_' . sha1($salt), 
178             1, // any value here 
179             $this->compress, 
180             $Auth_OpenID_SKEW);
181     }
182     
183     /**
184      * Memcache key is prefixed with 'openid_association_' string. 
185      */
186     function associationKey($server_url, $handle = null) 
187     {
188         return 'openid_association_' . sha1($server_url) . '_' . sha1($handle);
189     }
190     
191     /**
192      * Memcache key is prefixed with 'openid_association_' string. 
193      */
194     function associationServerKey($server_url) 
195     {
196         return 'openid_association_server_' . sha1($server_url);
197     }
198     
199     /**
200      * Report that this storage doesn't support cleanup
201      */
202     function supportsCleanup()
203     {
204         return false;
205     }
206 }
207
208 ?>