]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/Auth/OpenID/PredisStore.php
7108c2faf99cf2b0e793365f40ddd565be2ce2fd
[quix0rs-gnu-social.git] / extlib / Auth / OpenID / PredisStore.php
1 <?php
2
3 /**
4  * Supplies Redis server store backend for OpenID servers and consumers.
5  * Uses Predis library {@see https://github.com/nrk/predis}.
6  * Requires PHP >= 5.3.
7  *
8  * LICENSE: See the COPYING file included in this distribution.
9  *
10  * @package OpenID
11  * @author Ville Mattila <ville@eventio.fi>
12  * @copyright 2008 JanRain Inc., 2013 Eventio Oy / Ville Mattila
13  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
14  * Contributed by Eventio Oy <http://www.eventio.fi/>
15  */
16
17 /**
18  * Import the interface for creating a new store class.
19  */
20 require_once 'Auth/OpenID/Interface.php';
21
22 /**
23  * Supplies Redis server store backend for OpenID servers and consumers.
24  * Uses Predis library {@see https://github.com/nrk/predis}.
25  * Requires PHP >= 5.3.
26  * 
27  * @package OpenID
28  */
29 class Auth_OpenID_PredisStore extends Auth_OpenID_OpenIDStore {
30
31     /**
32      * @var \Predis\Client
33      */
34     protected $redis;
35
36     /**
37      * Prefix for Redis keys
38      * @var string
39      */
40     protected $prefix;
41
42     /**
43      * Initializes a new {@link Auth_OpenID_PredisStore} instance.
44      *
45      * @param \Predis\Client $redis  Predis client object
46      * @param string         $prefix Prefix for all keys stored to the Redis
47      */
48     function Auth_OpenID_PredisStore(\Predis\Client $redis, $prefix = '')
49     {
50         $this->prefix = $prefix;
51         $this->redis = $redis;
52     }
53
54     /**
55      * Store association until its expiration time in Redis server. 
56      * Overwrites any existing association with same server_url and 
57      * handle. Handles list of associations for every server. 
58      */
59     function storeAssociation($server_url, $association)
60     {
61         // create Redis keys for association itself 
62         // and list of associations for this server
63         $associationKey = $this->associationKey($server_url, 
64             $association->handle);
65         $serverKey = $this->associationServerKey($server_url);
66         
67         // save association to server's associations' keys list
68         $this->redis->lpush(
69             $serverKey,
70             $associationKey
71         );
72
73         // Will touch the association list expiration, to avoid filling up
74         $newExpiration = ($association->issued + $association->lifetime);
75
76         $expirationKey = $serverKey.'_expires_at';
77         $expiration = $this->redis->get($expirationKey);
78         if (!$expiration || $newExpiration > $expiration) {
79             $this->redis->set($expirationKey, $newExpiration);
80             $this->redis->expireat($serverKey, $newExpiration);
81             $this->redis->expireat($expirationKey, $newExpiration);
82         }
83
84         // save association itself, will automatically expire
85         $this->redis->setex(
86             $associationKey,
87             $newExpiration - time(),
88             serialize($association)
89         );
90     }
91
92     /**
93      * Read association from Redis. If no handle given 
94      * and multiple associations found, returns latest issued
95      */
96     function getAssociation($server_url, $handle = null)
97     {
98         // simple case: handle given
99         if ($handle !== null) {
100             return $this->getAssociationFromServer(
101                 $this->associationKey($server_url, $handle)
102             );
103         }
104         
105         // no handle given, receiving the latest issued
106         $serverKey = $this->associationServerKey($server_url);
107         $lastKey = $this->redis->lpop($serverKey);
108         if (!$lastKey) { return null; }
109
110         // get association, return null if failed
111         return $this->getAssociationFromServer($lastKey);
112     }
113     
114     /**
115      * Function to actually receive and unserialize the association
116      * from the server.
117      */
118     private function getAssociationFromServer($associationKey)
119     {
120         $association = $this->redis->get($associationKey);
121         return $association ? unserialize($association) : null;
122     }
123
124     /**
125      * Immediately delete association from Redis.
126      */
127     function removeAssociation($server_url, $handle)
128     {
129         // create Redis keys
130         $serverKey = $this->associationServerKey($server_url);
131         $associationKey = $this->associationKey($server_url, 
132             $handle);
133         
134         // Removing the association from the server's association list
135         $removed = $this->redis->lrem($serverKey, 0, $associationKey);
136         if ($removed < 1) {
137             return false;
138         }
139
140         // Delete the association itself
141         return $this->redis->del($associationKey);
142     }
143
144     /**
145      * Create nonce for server and salt, expiring after 
146      * $Auth_OpenID_SKEW seconds.
147      */
148     function useNonce($server_url, $timestamp, $salt)
149     {
150         global $Auth_OpenID_SKEW;
151         
152         // save one request to memcache when nonce obviously expired 
153         if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
154             return false;
155         }
156         
157         // SETNX will set the value only of the key doesn't exist yet.
158         $nonceKey = $this->nonceKey($server_url, $salt);
159         $added = $this->predis->setnx($nonceKey);
160         if ($added) {
161             // Will set expiration
162             $this->predis->expire($nonceKey, $Auth_OpenID_SKEW);
163             return true;
164         } else {
165             return false;
166         }
167     }
168     
169     /**
170      * Build up nonce key
171      */
172     private function nonceKey($server_url, $salt)
173     {
174         return $this->prefix .
175                'openid_nonce_' .
176                sha1($server_url) . '_' . sha1($salt);
177     }
178     
179     /**
180      * Key is prefixed with $prefix and 'openid_association_' string
181      */
182     function associationKey($server_url, $handle = null) 
183     {
184         return $this->prefix .
185                'openid_association_' .
186                sha1($server_url) . '_' . sha1($handle);
187     }
188     
189     /**
190      * Key is prefixed with $prefix and 'openid_association_server_' string
191      */
192     function associationServerKey($server_url) 
193     {
194         return $this->prefix .
195                'openid_association_server_' .
196                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