00001 <?php
00002
00023 global $__Auth_OpenID_PEAR_AVAILABLE;
00024 $__Auth_OpenID_PEAR_AVAILABLE = @include_once 'DB.php';
00025
00029 require_once 'Auth/OpenID/Interface.php';
00030 require_once 'Auth/OpenID/Nonce.php';
00031
00035 require_once 'Auth/OpenID.php';
00036
00040 require_once 'Auth/OpenID/Nonce.php';
00041
00067 class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
00068
00088 function Auth_OpenID_SQLStore($connection,
00089 $associations_table = null,
00090 $nonces_table = null)
00091 {
00092 global $__Auth_OpenID_PEAR_AVAILABLE;
00093
00094 $this->associations_table_name = "oid_associations";
00095 $this->nonces_table_name = "oid_nonces";
00096
00097
00098
00099 if (!(is_object($connection) &&
00100 (is_subclass_of($connection, 'db_common') ||
00101 is_subclass_of($connection,
00102 'auth_openid_databaseconnection')))) {
00103 trigger_error("Auth_OpenID_SQLStore expected PEAR connection " .
00104 "object (got ".get_class($connection).")",
00105 E_USER_ERROR);
00106 return;
00107 }
00108
00109 $this->connection = $connection;
00110
00111
00112
00113
00114
00115
00116 if ($__Auth_OpenID_PEAR_AVAILABLE) {
00117 $this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
00118 }
00119
00120 if ($associations_table) {
00121 $this->associations_table_name = $associations_table;
00122 }
00123
00124 if ($nonces_table) {
00125 $this->nonces_table_name = $nonces_table;
00126 }
00127
00128 $this->max_nonce_age = 6 * 60 * 60;
00129
00130
00131
00132
00133
00134
00135 $this->connection->autoCommit(false);
00136
00137
00138 $this->sql = array();
00139
00140
00141
00142 $this->setSQL();
00143
00144
00145
00146
00147 list($missing, $empty) = $this->_verifySQL();
00148
00149 if ($missing) {
00150 trigger_error("Expected keys in SQL query list: " .
00151 implode(", ", $missing),
00152 E_USER_ERROR);
00153 return;
00154 }
00155
00156 if ($empty) {
00157 trigger_error("SQL list keys have no SQL strings: " .
00158 implode(", ", $empty),
00159 E_USER_ERROR);
00160 return;
00161 }
00162
00163
00164 $this->_fixSQL();
00165 }
00166
00167 function tableExists($table_name)
00168 {
00169 return !$this->isError(
00170 $this->connection->query(
00171 sprintf("SELECT * FROM %s LIMIT 0",
00172 $table_name)));
00173 }
00174
00179 function isError($value)
00180 {
00181 return PEAR::isError($value);
00182 }
00183
00189 function resultToBool($obj)
00190 {
00191 if ($this->isError($obj)) {
00192 return false;
00193 } else {
00194 return true;
00195 }
00196 }
00197
00203 function setSQL()
00204 {
00205 }
00206
00211 function reset()
00212 {
00213 $this->connection->query(sprintf("DELETE FROM %s",
00214 $this->associations_table_name));
00215
00216 $this->connection->query(sprintf("DELETE FROM %s",
00217 $this->nonces_table_name));
00218 }
00219
00223 function _verifySQL()
00224 {
00225 $missing = array();
00226 $empty = array();
00227
00228 $required_sql_keys = array(
00229 'nonce_table',
00230 'assoc_table',
00231 'set_assoc',
00232 'get_assoc',
00233 'get_assocs',
00234 'remove_assoc'
00235 );
00236
00237 foreach ($required_sql_keys as $key) {
00238 if (!array_key_exists($key, $this->sql)) {
00239 $missing[] = $key;
00240 } else if (!$this->sql[$key]) {
00241 $empty[] = $key;
00242 }
00243 }
00244
00245 return array($missing, $empty);
00246 }
00247
00251 function _fixSQL()
00252 {
00253 $replacements = array(
00254 array(
00255 'value' => $this->nonces_table_name,
00256 'keys' => array('nonce_table',
00257 'add_nonce',
00258 'clean_nonce')
00259 ),
00260 array(
00261 'value' => $this->associations_table_name,
00262 'keys' => array('assoc_table',
00263 'set_assoc',
00264 'get_assoc',
00265 'get_assocs',
00266 'remove_assoc',
00267 'clean_assoc')
00268 )
00269 );
00270
00271 foreach ($replacements as $item) {
00272 $value = $item['value'];
00273 $keys = $item['keys'];
00274
00275 foreach ($keys as $k) {
00276 if (is_array($this->sql[$k])) {
00277 foreach ($this->sql[$k] as $part_key => $part_value) {
00278 $this->sql[$k][$part_key] = sprintf($part_value,
00279 $value);
00280 }
00281 } else {
00282 $this->sql[$k] = sprintf($this->sql[$k], $value);
00283 }
00284 }
00285 }
00286 }
00287
00288 function blobDecode($blob)
00289 {
00290 return $blob;
00291 }
00292
00293 function blobEncode($str)
00294 {
00295 return $str;
00296 }
00297
00298 function createTables()
00299 {
00300 $this->connection->autoCommit(true);
00301 $n = $this->create_nonce_table();
00302 $a = $this->create_assoc_table();
00303 $this->connection->autoCommit(false);
00304
00305 if ($n && $a) {
00306 return true;
00307 } else {
00308 return false;
00309 }
00310 }
00311
00312 function create_nonce_table()
00313 {
00314 if (!$this->tableExists($this->nonces_table_name)) {
00315 $r = $this->connection->query($this->sql['nonce_table']);
00316 return $this->resultToBool($r);
00317 }
00318 return true;
00319 }
00320
00321 function create_assoc_table()
00322 {
00323 if (!$this->tableExists($this->associations_table_name)) {
00324 $r = $this->connection->query($this->sql['assoc_table']);
00325 return $this->resultToBool($r);
00326 }
00327 return true;
00328 }
00329
00333 function _set_assoc($server_url, $handle, $secret, $issued,
00334 $lifetime, $assoc_type)
00335 {
00336 return $this->connection->query($this->sql['set_assoc'],
00337 array(
00338 $server_url,
00339 $handle,
00340 $secret,
00341 $issued,
00342 $lifetime,
00343 $assoc_type));
00344 }
00345
00346 function storeAssociation($server_url, $association)
00347 {
00348 if ($this->resultToBool($this->_set_assoc(
00349 $server_url,
00350 $association->handle,
00351 $this->blobEncode(
00352 $association->secret),
00353 $association->issued,
00354 $association->lifetime,
00355 $association->assoc_type
00356 ))) {
00357 $this->connection->commit();
00358 } else {
00359 $this->connection->rollback();
00360 }
00361 }
00362
00366 function _get_assoc($server_url, $handle)
00367 {
00368 $result = $this->connection->getRow($this->sql['get_assoc'],
00369 array($server_url, $handle));
00370 if ($this->isError($result)) {
00371 return null;
00372 } else {
00373 return $result;
00374 }
00375 }
00376
00380 function _get_assocs($server_url)
00381 {
00382 $result = $this->connection->getAll($this->sql['get_assocs'],
00383 array($server_url));
00384
00385 if ($this->isError($result)) {
00386 return array();
00387 } else {
00388 return $result;
00389 }
00390 }
00391
00392 function removeAssociation($server_url, $handle)
00393 {
00394 if ($this->_get_assoc($server_url, $handle) == null) {
00395 return false;
00396 }
00397
00398 if ($this->resultToBool($this->connection->query(
00399 $this->sql['remove_assoc'],
00400 array($server_url, $handle)))) {
00401 $this->connection->commit();
00402 } else {
00403 $this->connection->rollback();
00404 }
00405
00406 return true;
00407 }
00408
00409 function getAssociation($server_url, $handle = null)
00410 {
00411 if ($handle !== null) {
00412 $assoc = $this->_get_assoc($server_url, $handle);
00413
00414 $assocs = array();
00415 if ($assoc) {
00416 $assocs[] = $assoc;
00417 }
00418 } else {
00419 $assocs = $this->_get_assocs($server_url);
00420 }
00421
00422 if (!$assocs || (count($assocs) == 0)) {
00423 return null;
00424 } else {
00425 $associations = array();
00426
00427 foreach ($assocs as $assoc_row) {
00428 $assoc = new Auth_OpenID_Association($assoc_row['handle'],
00429 $assoc_row['secret'],
00430 $assoc_row['issued'],
00431 $assoc_row['lifetime'],
00432 $assoc_row['assoc_type']);
00433
00434 $assoc->secret = $this->blobDecode($assoc->secret);
00435
00436 if ($assoc->getExpiresIn() == 0) {
00437 $this->removeAssociation($server_url, $assoc->handle);
00438 } else {
00439 $associations[] = array($assoc->issued, $assoc);
00440 }
00441 }
00442
00443 if ($associations) {
00444 $issued = array();
00445 $assocs = array();
00446 foreach ($associations as $key => $assoc) {
00447 $issued[$key] = $assoc[0];
00448 $assocs[$key] = $assoc[1];
00449 }
00450
00451 array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
00452 $associations);
00453
00454
00455 list($issued, $assoc) = $associations[0];
00456 return $assoc;
00457 } else {
00458 return null;
00459 }
00460 }
00461 }
00462
00466 function _add_nonce($server_url, $timestamp, $salt)
00467 {
00468 $sql = $this->sql['add_nonce'];
00469 $result = $this->connection->query($sql, array($server_url,
00470 $timestamp,
00471 $salt));
00472 if ($this->isError($result)) {
00473 $this->connection->rollback();
00474 } else {
00475 $this->connection->commit();
00476 }
00477 return $this->resultToBool($result);
00478 }
00479
00480 function useNonce($server_url, $timestamp, $salt)
00481 {
00482 global $Auth_OpenID_SKEW;
00483
00484 if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
00485 return False;
00486 }
00487
00488 return $this->_add_nonce($server_url, $timestamp, $salt);
00489 }
00490
00498 function _octify($str)
00499 {
00500 $result = "";
00501 for ($i = 0; $i < Auth_OpenID::bytes($str); $i++) {
00502 $ch = substr($str, $i, 1);
00503 if ($ch == "\\") {
00504 $result .= "\\\\\\\\";
00505 } else if (ord($ch) == 0) {
00506 $result .= "\\\\000";
00507 } else {
00508 $result .= "\\" . strval(decoct(ord($ch)));
00509 }
00510 }
00511 return $result;
00512 }
00513
00520 function _unoctify($str)
00521 {
00522 $result = "";
00523 $i = 0;
00524 while ($i < strlen($str)) {
00525 $char = $str[$i];
00526 if ($char == "\\") {
00527
00528
00529 if ($str[$i + 1] != "\\") {
00530 $octal_digits = substr($str, $i + 1, 3);
00531 $dec = octdec($octal_digits);
00532 $char = chr($dec);
00533 $i += 4;
00534 } else {
00535 $char = "\\";
00536 $i += 2;
00537 }
00538 } else {
00539 $i += 1;
00540 }
00541
00542 $result .= $char;
00543 }
00544
00545 return $result;
00546 }
00547
00548 function cleanupNonces()
00549 {
00550 global $Auth_OpenID_SKEW;
00551 $v = time() - $Auth_OpenID_SKEW;
00552
00553 $this->connection->query($this->sql['clean_nonce'], array($v));
00554 $num = $this->connection->affectedRows();
00555 $this->connection->commit();
00556 return $num;
00557 }
00558
00559 function cleanupAssociations()
00560 {
00561 $this->connection->query($this->sql['clean_assoc'],
00562 array(time()));
00563 $num = $this->connection->affectedRows();
00564 $this->connection->commit();
00565 return $num;
00566 }
00567 }
00568
00569 ?>