1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * Sample OAuth2 Library PDO DB Implementation. |
---|
6 | * |
---|
7 | * Simply pass in a configured PDO class, eg: |
---|
8 | * new OAuth2StoragePDO( new PDO('mysql:dbname=mydb;host=localhost', 'user', 'pass') ); |
---|
9 | */ |
---|
10 | session_start(); |
---|
11 | require __DIR__ . '/../../../../lib/OAuth2.php'; |
---|
12 | require __DIR__ . '/../../../../lib/IOAuth2Storage.php'; |
---|
13 | require __DIR__ . '/../../../../lib/IOAuth2GrantCode.php'; |
---|
14 | require __DIR__ . '/../../../../lib/IOAuth2RefreshTokens.php'; |
---|
15 | |
---|
16 | /** |
---|
17 | * PDO storage engine for the OAuth2 Library. |
---|
18 | * |
---|
19 | * IMPORTANT: This is provided as an example only. In production you may implement |
---|
20 | * a client-specific salt in the OAuth2StoragePDO::hash() and possibly other goodies. |
---|
21 | * |
---|
22 | *** The point is, use this as an EXAMPLE ONLY. *** |
---|
23 | */ |
---|
24 | class OAuth2StoragePDO implements IOAuth2GrantCode, IOAuth2RefreshTokens { |
---|
25 | |
---|
26 | /** |
---|
27 | * Change this to something unique for your system |
---|
28 | * @var string |
---|
29 | */ |
---|
30 | const SALT = 'CHANGE_ME!'; |
---|
31 | |
---|
32 | /**@#+ |
---|
33 | * Centralized table names |
---|
34 | * |
---|
35 | * @var string |
---|
36 | */ |
---|
37 | const TABLE_CLIENTS = 'clients'; |
---|
38 | const TABLE_CODES = 'auth_codes'; |
---|
39 | const TABLE_TOKENS = 'access_tokens'; |
---|
40 | const TABLE_REFRESH = 'refresh_tokens'; |
---|
41 | /**@#-*/ |
---|
42 | |
---|
43 | /** |
---|
44 | * @var PDO |
---|
45 | */ |
---|
46 | private $db; |
---|
47 | |
---|
48 | /** |
---|
49 | * Implements OAuth2::__construct(). |
---|
50 | */ |
---|
51 | public function __construct() { |
---|
52 | |
---|
53 | try { |
---|
54 | $this->db = new PDO('pgsql:dbname=oauth;host=/tmp', 'expressodev', 'prognus'); |
---|
55 | } catch (PDOException $e) { |
---|
56 | die('Connection failed: ' . $e->getMessage()); |
---|
57 | } |
---|
58 | } |
---|
59 | |
---|
60 | /** |
---|
61 | * Release DB connection during destruct. |
---|
62 | */ |
---|
63 | function __destruct() { |
---|
64 | $this->db = NULL; // Release db connection |
---|
65 | } |
---|
66 | |
---|
67 | /** |
---|
68 | * Handle PDO exceptional cases. |
---|
69 | */ |
---|
70 | private function handleException($e) { |
---|
71 | echo 'Database error: ' . $e->getMessage(); |
---|
72 | exit(); |
---|
73 | } |
---|
74 | |
---|
75 | /** |
---|
76 | * Little helper function to add a new client to the database. |
---|
77 | * |
---|
78 | * Do NOT use this in production! This sample code stores the secret |
---|
79 | * in plaintext! |
---|
80 | * |
---|
81 | * @param $client_id |
---|
82 | * Client identifier to be stored. |
---|
83 | * @param $client_secret |
---|
84 | * Client secret to be stored. |
---|
85 | * @param $redirect_uri |
---|
86 | * Redirect URI to be stored. |
---|
87 | */ |
---|
88 | public function addClient($client_id, $client_secret, $redirect_uri) { |
---|
89 | try { |
---|
90 | $client_secret = $this->hash($client_secret, $client_id); |
---|
91 | |
---|
92 | $sql = 'INSERT INTO ' . self::TABLE_CLIENTS . ' (client_id, client_secret, redirect_uri) VALUES (:client_id, :client_secret, :redirect_uri)'; |
---|
93 | $stmt = $this->db->prepare($sql); |
---|
94 | $stmt->bindParam(':client_id', $client_id, PDO::PARAM_STR); |
---|
95 | $stmt->bindParam(':client_secret', $client_secret, PDO::PARAM_STR); |
---|
96 | $stmt->bindParam(':redirect_uri', $redirect_uri, PDO::PARAM_STR); |
---|
97 | $stmt->execute(); |
---|
98 | } catch (PDOException $e) { |
---|
99 | $this->handleException($e); |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | /** |
---|
104 | * Implements IOAuth2Storage::checkClientCredentials(). |
---|
105 | * |
---|
106 | */ |
---|
107 | public function checkClientCredentials($client_id, $client_secret = NULL) { |
---|
108 | try { |
---|
109 | $sql = 'SELECT client_secret FROM ' . self::TABLE_CLIENTS . ' WHERE client_id = :client_id'; |
---|
110 | $stmt = $this->db->prepare($sql); |
---|
111 | $stmt->bindParam(':client_id', $client_id, PDO::PARAM_STR); |
---|
112 | $stmt->execute(); |
---|
113 | |
---|
114 | $result = $stmt->fetch(PDO::FETCH_ASSOC); |
---|
115 | |
---|
116 | if ($client_secret === NULL) { |
---|
117 | return $result !== FALSE; |
---|
118 | } |
---|
119 | |
---|
120 | return $this->checkPassword($client_secret, $result['client_secret'], $client_id); |
---|
121 | } catch (PDOException $e) { |
---|
122 | $this->handleException($e); |
---|
123 | } |
---|
124 | } |
---|
125 | |
---|
126 | /** |
---|
127 | * Implements IOAuth2Storage::getRedirectUri(). |
---|
128 | */ |
---|
129 | public function getClientDetails($client_id) { |
---|
130 | try { |
---|
131 | $sql = 'SELECT redirect_uri FROM ' . self::TABLE_CLIENTS . ' WHERE client_id = :client_id'; |
---|
132 | $stmt = $this->db->prepare($sql); |
---|
133 | $stmt->bindParam(':client_id', $client_id, PDO::PARAM_STR); |
---|
134 | $stmt->execute(); |
---|
135 | |
---|
136 | $result = $stmt->fetch(PDO::FETCH_ASSOC); |
---|
137 | |
---|
138 | if ($result === FALSE) { |
---|
139 | return FALSE; |
---|
140 | } |
---|
141 | |
---|
142 | return isset($result['redirect_uri']) && $result['redirect_uri'] ? $result : NULL; |
---|
143 | } catch (PDOException $e) { |
---|
144 | $this->handleException($e); |
---|
145 | } |
---|
146 | } |
---|
147 | |
---|
148 | /** |
---|
149 | * Implements IOAuth2Storage::getAccessToken(). |
---|
150 | */ |
---|
151 | public function getAccessToken($oauth_token) { |
---|
152 | return $this->getToken($oauth_token, FALSE); |
---|
153 | } |
---|
154 | |
---|
155 | /** |
---|
156 | * Implements IOAuth2Storage::setAccessToken(). |
---|
157 | */ |
---|
158 | public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = NULL) { |
---|
159 | $this->setToken($oauth_token, $client_id, $user_id, $expires, $scope, FALSE); |
---|
160 | } |
---|
161 | |
---|
162 | /** |
---|
163 | * @see IOAuth2Storage::getRefreshToken() |
---|
164 | */ |
---|
165 | public function getRefreshToken($refresh_token) { |
---|
166 | return $this->getToken($refresh_token, TRUE); |
---|
167 | } |
---|
168 | |
---|
169 | /** |
---|
170 | * @see IOAuth2Storage::setRefreshToken() |
---|
171 | */ |
---|
172 | public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = NULL) { |
---|
173 | return $this->setToken($refresh_token, $client_id, $user_id, $expires, $scope, TRUE); |
---|
174 | } |
---|
175 | |
---|
176 | /** |
---|
177 | * @see IOAuth2Storage::unsetRefreshToken() |
---|
178 | */ |
---|
179 | public function unsetRefreshToken($refresh_token) { |
---|
180 | try { |
---|
181 | $sql = 'DELETE FROM ' . self::TABLE_TOKENS . ' WHERE refresh_token = :refresh_token'; |
---|
182 | $stmt = $this->db->prepare($sql); |
---|
183 | $stmt->bindParam(':refresh_token', $refresh_token, PDO::PARAM_STR); |
---|
184 | $stmt->execute(); |
---|
185 | } catch (PDOException $e) { |
---|
186 | $this->handleException($e); |
---|
187 | } |
---|
188 | } |
---|
189 | |
---|
190 | /** |
---|
191 | * Implements IOAuth2Storage::getAuthCode(). |
---|
192 | */ |
---|
193 | public function getAuthCode($code) { |
---|
194 | try { |
---|
195 | $sql = 'SELECT code, client_id, user_id, redirect_uri, expires, scope FROM ' . self::TABLE_CODES . ' auth_codes WHERE code = :code'; |
---|
196 | $stmt = $this->db->prepare($sql); |
---|
197 | $stmt->bindParam(':code', $code, PDO::PARAM_STR); |
---|
198 | $stmt->execute(); |
---|
199 | |
---|
200 | $result = $stmt->fetch(PDO::FETCH_ASSOC); |
---|
201 | |
---|
202 | return $result !== FALSE ? $result : NULL; |
---|
203 | } catch (PDOException $e) { |
---|
204 | $this->handleException($e); |
---|
205 | } |
---|
206 | } |
---|
207 | |
---|
208 | /** |
---|
209 | * Implements IOAuth2Storage::setAuthCode(). |
---|
210 | */ |
---|
211 | public function setAuthCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = NULL) { |
---|
212 | try { |
---|
213 | $sql = 'INSERT INTO ' . self::TABLE_CODES . ' (code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)'; |
---|
214 | $stmt = $this->db->prepare($sql); |
---|
215 | $stmt->bindParam(':code', $code, PDO::PARAM_STR); |
---|
216 | $stmt->bindParam(':client_id', $client_id, PDO::PARAM_STR); |
---|
217 | $stmt->bindParam(':user_id', $user_id, PDO::PARAM_STR); |
---|
218 | $stmt->bindParam(':redirect_uri', $redirect_uri, PDO::PARAM_STR); |
---|
219 | $stmt->bindParam(':expires', $expires, PDO::PARAM_INT); |
---|
220 | $stmt->bindParam(':scope', $scope, PDO::PARAM_STR); |
---|
221 | |
---|
222 | $stmt->execute(); |
---|
223 | } catch (PDOException $e) { |
---|
224 | $this->handleException($e); |
---|
225 | } |
---|
226 | } |
---|
227 | |
---|
228 | /** |
---|
229 | * @see IOAuth2Storage::checkRestrictedGrantType() |
---|
230 | */ |
---|
231 | public function checkRestrictedGrantType($client_id, $grant_type) { |
---|
232 | return TRUE; // Not implemented |
---|
233 | } |
---|
234 | |
---|
235 | /** |
---|
236 | * Creates a refresh or access token |
---|
237 | * |
---|
238 | * @param string $token - Access or refresh token id |
---|
239 | * @param string $client_id |
---|
240 | * @param mixed $user_id |
---|
241 | * @param int $expires |
---|
242 | * @param string $scope |
---|
243 | * @param bool $isRefresh |
---|
244 | */ |
---|
245 | protected function setToken($token, $client_id, $user_id, $expires, $scope, $isRefresh = TRUE) { |
---|
246 | try { |
---|
247 | $tableName = $isRefresh ? self::TABLE_REFRESH : self::TABLE_TOKENS; |
---|
248 | $tokenName = $isRefresh ? 'refresh_token' : 'oauth_token'; |
---|
249 | |
---|
250 | $sql = "INSERT INTO $tableName ($tokenName, client_id, user_id, expires, scope) VALUES (:token, :client_id, :user_id, :expires, :scope)"; |
---|
251 | $stmt = $this->db->prepare($sql); |
---|
252 | $stmt->bindParam(':token', $token, PDO::PARAM_STR); |
---|
253 | $stmt->bindParam(':client_id', $client_id, PDO::PARAM_STR); |
---|
254 | $stmt->bindParam(':user_id', $user_id, PDO::PARAM_STR); |
---|
255 | $stmt->bindParam(':expires', $expires, PDO::PARAM_INT); |
---|
256 | $stmt->bindParam(':scope', $scope, PDO::PARAM_STR); |
---|
257 | |
---|
258 | $stmt->execute(); |
---|
259 | } catch (PDOException $e) { |
---|
260 | $this->handleException($e); |
---|
261 | } |
---|
262 | } |
---|
263 | |
---|
264 | /** |
---|
265 | * Retrieves an access or refresh token. |
---|
266 | * |
---|
267 | * @param string $token |
---|
268 | * @param bool $refresh |
---|
269 | */ |
---|
270 | protected function getToken($token, $isRefresh = true) { |
---|
271 | try { |
---|
272 | $tableName = $isRefresh ? self::TABLE_REFRESH : self::TABLE_TOKENS; |
---|
273 | $tokenName = $isRefresh ? 'refresh_token' : 'oauth_token'; |
---|
274 | |
---|
275 | $sql = "SELECT $tokenName, client_id, expires, scope, user_id FROM $tableName WHERE $tokenName = :token"; |
---|
276 | $stmt = $this->db->prepare($sql); |
---|
277 | $stmt->bindParam(':token', $token, PDO::PARAM_STR); |
---|
278 | $stmt->execute(); |
---|
279 | |
---|
280 | $result = $stmt->fetch(PDO::FETCH_ASSOC); |
---|
281 | |
---|
282 | return $result !== FALSE ? $result : NULL; |
---|
283 | } catch (PDOException $e) { |
---|
284 | $this->handleException($e); |
---|
285 | } |
---|
286 | } |
---|
287 | |
---|
288 | /** |
---|
289 | * Change/override this to whatever your own password hashing method is. |
---|
290 | * |
---|
291 | * In production you might want to a client-specific salt to this function. |
---|
292 | * |
---|
293 | * @param string $secret |
---|
294 | * @return string |
---|
295 | */ |
---|
296 | protected function hash($client_secret, $client_id) { |
---|
297 | return hash('md5', $client_id . $client_secret); |
---|
298 | } |
---|
299 | |
---|
300 | /** |
---|
301 | * Checks the password. |
---|
302 | * Override this if you need to |
---|
303 | * |
---|
304 | * @param string $client_id |
---|
305 | * @param string $client_secret |
---|
306 | * @param string $actualPassword |
---|
307 | */ |
---|
308 | protected function checkPassword($try, $client_secret, $client_id) { |
---|
309 | return ($client_secret == $this->hash($try, $client_id) )? TRUE : FALSE; |
---|
310 | } |
---|
311 | } |
---|