]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/Auth/OpenID/PredisStore.php
Merge remote-tracking branch 'upstream/master'
[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->lindex($serverKey, -1);
108         if (!$lastKey) { 
109             // no previous association with this server
110             return null; 
111         }
112
113         // get association, return null if failed
114         return $this->getAssociationFromServer($lastKey);
115     }
116     
117     /**
118      * Function to actually receive and unserialize the association
119      * from the server.
120      */
121     private function getAssociationFromServer($associationKey)
122     {
123         $association = $this->redis->get($associationKey);
124         return $association ? unserialize($association) : null;
125     }
126
127     /**
128      * Immediately delete association from Redis.
129      */
130     function removeAssociation($server_url, $handle)
131     {
132         // create Redis keys
133         $serverKey = $this->associationServerKey($server_url);
134         $associationKey = $this->associationKey($server_url, 
135             $handle);
136         
137         // Removing the association from the server's association list
138         $removed = $this->redis->lrem($serverKey, 0, $associationKey);
139         if ($removed < 1) {
140             return false;
141         }
142
143         // Delete the association itself
144         return $this->redis->del($associationKey);
145     }
146
147     /**
148      * Create nonce for server and salt, expiring after 
149      * $Auth_OpenID_SKEW seconds.
150      */
151     function useNonce($server_url, $timestamp, $salt)
152     {
153         global $Auth_OpenID_SKEW;
154         
155         // save one request to memcache when nonce obviously expired 
156         if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
157             return false;
158         }
159         
160         // SETNX will set the value only of the key doesn't exist yet.
161         $nonceKey = $this->nonceKey($server_url, $salt);
162         $added = $this->redis->setnx($nonceKey, "1");
163         if ($added) {
164             // Will set expiration
165             $this->redis->expire($nonceKey, $Auth_OpenID_SKEW);
166             return true;
167         } else {
168             return false;
169         }
170     }
171     
172     /**
173      * Build up nonce key
174      */
175     private function nonceKey($server_url, $salt)
176     {
177         return $this->prefix .
178                'openid_nonce_' .
179                sha1($server_url) . '_' . sha1($salt);
180     }
181     
182     /**
183      * Key is prefixed with $prefix and 'openid_association_' string
184      */
185     function associationKey($server_url, $handle = null) 
186     {
187         return $this->prefix .
188                'openid_association_' .
189                sha1($server_url) . '_' . sha1($handle);
190     }
191     
192     /**
193      * Key is prefixed with $prefix and 'openid_association_server_' string
194      */
195     function associationServerKey($server_url) 
196     {
197         return $this->prefix .
198                'openid_association_server_' .
199                sha1($server_url);
200     }
201     
202     /**
203      * Report that this storage doesn't support cleanup
204      */
205     function supportsCleanup()
206     {
207         return false;
208     }
209
210 }
211