[6351] | 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 | } |
---|