File indexing completed on 2025-01-19 05:21:20
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-web at this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_OpenId 0018 * @subpackage Zend_OpenId_Consumer 0019 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0020 * @license http://framework.zend.com/license/new-bsd New BSD License 0021 * @version $Id$ 0022 */ 0023 0024 /** 0025 * @see Zend_OpenId_Consumer_Storage 0026 */ 0027 // require_once "Zend/OpenId/Consumer/Storage.php"; 0028 0029 /** 0030 * External storage implemmentation using serialized files 0031 * 0032 * @category Zend 0033 * @package Zend_OpenId 0034 * @subpackage Zend_OpenId_Consumer 0035 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0036 * @license http://framework.zend.com/license/new-bsd New BSD License 0037 */ 0038 class Zend_OpenId_Consumer_Storage_File extends Zend_OpenId_Consumer_Storage 0039 { 0040 0041 /** 0042 * Directory name to store data files in 0043 * 0044 * @var string $_dir 0045 */ 0046 private $_dir; 0047 0048 /** 0049 * Constructs storage object and creates storage directory 0050 * 0051 * @param string $dir directory name to store data files in 0052 * @throws Zend_OpenId_Exception 0053 */ 0054 public function __construct($dir = null) 0055 { 0056 if ($dir === null) { 0057 $tmp = getenv('TMP'); 0058 if (empty($tmp)) { 0059 $tmp = getenv('TEMP'); 0060 if (empty($tmp)) { 0061 $tmp = "/tmp"; 0062 } 0063 } 0064 $user = get_current_user(); 0065 if (is_string($user) && !empty($user)) { 0066 $tmp .= '/' . $user; 0067 } 0068 $dir = $tmp . '/openid/consumer'; 0069 } 0070 $this->_dir = $dir; 0071 if (!is_dir($this->_dir)) { 0072 if (!@mkdir($this->_dir, 0700, 1)) { 0073 /** 0074 * @see Zend_OpenId_Exception 0075 */ 0076 // require_once 'Zend/OpenId/Exception.php'; 0077 throw new Zend_OpenId_Exception( 0078 'Cannot access storage directory ' . $dir, 0079 Zend_OpenId_Exception::ERROR_STORAGE); 0080 } 0081 } 0082 if (($f = fopen($this->_dir.'/assoc.lock', 'w+')) === null) { 0083 /** 0084 * @see Zend_OpenId_Exception 0085 */ 0086 // require_once 'Zend/OpenId/Exception.php'; 0087 throw new Zend_OpenId_Exception( 0088 'Cannot create a lock file in the directory ' . $dir, 0089 Zend_OpenId_Exception::ERROR_STORAGE); 0090 } 0091 fclose($f); 0092 if (($f = fopen($this->_dir.'/discovery.lock', 'w+')) === null) { 0093 /** 0094 * @see Zend_OpenId_Exception 0095 */ 0096 // require_once 'Zend/OpenId/Exception.php'; 0097 throw new Zend_OpenId_Exception( 0098 'Cannot create a lock file in the directory ' . $dir, 0099 Zend_OpenId_Exception::ERROR_STORAGE); 0100 } 0101 fclose($f); 0102 if (($f = fopen($this->_dir.'/nonce.lock', 'w+')) === null) { 0103 /** 0104 * @see Zend_OpenId_Exception 0105 */ 0106 // require_once 'Zend/OpenId/Exception.php'; 0107 throw new Zend_OpenId_Exception( 0108 'Cannot create a lock file in the directory ' . $dir, 0109 Zend_OpenId_Exception::ERROR_STORAGE); 0110 } 0111 fclose($f); 0112 } 0113 0114 /** 0115 * Stores information about association identified by $url/$handle 0116 * 0117 * @param string $url OpenID server URL 0118 * @param string $handle assiciation handle 0119 * @param string $macFunc HMAC function (sha1 or sha256) 0120 * @param string $secret shared secret 0121 * @param long $expires expiration UNIX time 0122 * @return bool 0123 */ 0124 public function addAssociation($url, $handle, $macFunc, $secret, $expires) 0125 { 0126 $name1 = $this->_dir . '/assoc_url_' . md5($url); 0127 $name2 = $this->_dir . '/assoc_handle_' . md5($handle); 0128 $lock = @fopen($this->_dir . '/assoc.lock', 'w+'); 0129 if ($lock === false) { 0130 return false; 0131 } 0132 if (!flock($lock, LOCK_EX)) { 0133 fclose($lock); 0134 return false; 0135 } 0136 try { 0137 $f = @fopen($name1, 'w+'); 0138 if ($f === false) { 0139 fclose($lock); 0140 return false; 0141 } 0142 $data = serialize(array($url, $handle, $macFunc, $secret, $expires)); 0143 fwrite($f, $data); 0144 if (function_exists('symlink')) { 0145 @unlink($name2); 0146 if (symlink($name1, $name2)) { 0147 fclose($f); 0148 fclose($lock); 0149 return true; 0150 } 0151 } 0152 $f2 = @fopen($name2, 'w+'); 0153 if ($f2) { 0154 fwrite($f2, $data); 0155 fclose($f2); 0156 @unlink($name1); 0157 $ret = true; 0158 } else { 0159 $ret = false; 0160 } 0161 fclose($f); 0162 fclose($lock); 0163 return $ret; 0164 } catch (Exception $e) { 0165 fclose($lock); 0166 throw $e; 0167 } 0168 } 0169 0170 /** 0171 * Gets information about association identified by $url 0172 * Returns true if given association found and not expired and false 0173 * otherwise 0174 * 0175 * @param string $url OpenID server URL 0176 * @param string &$handle assiciation handle 0177 * @param string &$macFunc HMAC function (sha1 or sha256) 0178 * @param string &$secret shared secret 0179 * @param long &$expires expiration UNIX time 0180 * @return bool 0181 */ 0182 public function getAssociation($url, &$handle, &$macFunc, &$secret, &$expires) 0183 { 0184 $name1 = $this->_dir . '/assoc_url_' . md5($url); 0185 $lock = @fopen($this->_dir . '/assoc.lock', 'w+'); 0186 if ($lock === false) { 0187 return false; 0188 } 0189 if (!flock($lock, LOCK_EX)) { 0190 fclose($lock); 0191 return false; 0192 } 0193 try { 0194 $f = @fopen($name1, 'r'); 0195 if ($f === false) { 0196 fclose($lock); 0197 return false; 0198 } 0199 $ret = false; 0200 $data = stream_get_contents($f); 0201 if (!empty($data)) { 0202 list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data); 0203 if ($url === $storedUrl && $expires > time()) { 0204 $ret = true; 0205 } else { 0206 $name2 = $this->_dir . '/assoc_handle_' . md5($handle); 0207 fclose($f); 0208 @unlink($name2); 0209 @unlink($name1); 0210 fclose($lock); 0211 return false; 0212 } 0213 } 0214 fclose($f); 0215 fclose($lock); 0216 return $ret; 0217 } catch (Exception $e) { 0218 fclose($lock); 0219 throw $e; 0220 } 0221 } 0222 0223 /** 0224 * Gets information about association identified by $handle 0225 * Returns true if given association found and not expired and false 0226 * otherwise 0227 * 0228 * @param string $handle assiciation handle 0229 * @param string &$url OpenID server URL 0230 * @param string &$macFunc HMAC function (sha1 or sha256) 0231 * @param string &$secret shared secret 0232 * @param long &$expires expiration UNIX time 0233 * @return bool 0234 */ 0235 public function getAssociationByHandle($handle, &$url, &$macFunc, &$secret, &$expires) 0236 { 0237 $name2 = $this->_dir . '/assoc_handle_' . md5($handle); 0238 $lock = @fopen($this->_dir . '/assoc.lock', 'w+'); 0239 if ($lock === false) { 0240 return false; 0241 } 0242 if (!flock($lock, LOCK_EX)) { 0243 fclose($lock); 0244 return false; 0245 } 0246 try { 0247 $f = @fopen($name2, 'r'); 0248 if ($f === false) { 0249 fclose($lock); 0250 return false; 0251 } 0252 $ret = false; 0253 $data = stream_get_contents($f); 0254 if (!empty($data)) { 0255 list($url, $storedHandle, $macFunc, $secret, $expires) = unserialize($data); 0256 if ($handle === $storedHandle && $expires > time()) { 0257 $ret = true; 0258 } else { 0259 fclose($f); 0260 @unlink($name2); 0261 $name1 = $this->_dir . '/assoc_url_' . md5($url); 0262 @unlink($name1); 0263 fclose($lock); 0264 return false; 0265 } 0266 } 0267 fclose($f); 0268 fclose($lock); 0269 return $ret; 0270 } catch (Exception $e) { 0271 fclose($lock); 0272 throw $e; 0273 } 0274 } 0275 0276 /** 0277 * Deletes association identified by $url 0278 * 0279 * @param string $url OpenID server URL 0280 * @return bool 0281 */ 0282 public function delAssociation($url) 0283 { 0284 $name1 = $this->_dir . '/assoc_url_' . md5($url); 0285 $lock = @fopen($this->_dir . '/assoc.lock', 'w+'); 0286 if ($lock === false) { 0287 return false; 0288 } 0289 if (!flock($lock, LOCK_EX)) { 0290 fclose($lock); 0291 return false; 0292 } 0293 try { 0294 $f = @fopen($name1, 'r'); 0295 if ($f === false) { 0296 fclose($lock); 0297 return false; 0298 } 0299 $data = stream_get_contents($f); 0300 if (!empty($data)) { 0301 list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data); 0302 if ($url === $storedUrl) { 0303 $name2 = $this->_dir . '/assoc_handle_' . md5($handle); 0304 fclose($f); 0305 @unlink($name2); 0306 @unlink($name1); 0307 fclose($lock); 0308 return true; 0309 } 0310 } 0311 fclose($f); 0312 fclose($lock); 0313 return true; 0314 } catch (Exception $e) { 0315 fclose($lock); 0316 throw $e; 0317 } 0318 } 0319 0320 /** 0321 * Stores information discovered from identity $id 0322 * 0323 * @param string $id identity 0324 * @param string $realId discovered real identity URL 0325 * @param string $server discovered OpenID server URL 0326 * @param float $version discovered OpenID protocol version 0327 * @param long $expires expiration UNIX time 0328 * @return bool 0329 */ 0330 public function addDiscoveryInfo($id, $realId, $server, $version, $expires) 0331 { 0332 $name = $this->_dir . '/discovery_' . md5($id); 0333 $lock = @fopen($this->_dir . '/discovery.lock', 'w+'); 0334 if ($lock === false) { 0335 return false; 0336 } 0337 if (!flock($lock, LOCK_EX)) { 0338 fclose($lock); 0339 return false; 0340 } 0341 try { 0342 $f = @fopen($name, 'w+'); 0343 if ($f === false) { 0344 fclose($lock); 0345 return false; 0346 } 0347 $data = serialize(array($id, $realId, $server, $version, $expires)); 0348 fwrite($f, $data); 0349 fclose($f); 0350 fclose($lock); 0351 return true; 0352 } catch (Exception $e) { 0353 fclose($lock); 0354 throw $e; 0355 } 0356 } 0357 0358 /** 0359 * Gets information discovered from identity $id 0360 * Returns true if such information exists and false otherwise 0361 * 0362 * @param string $id identity 0363 * @param string &$realId discovered real identity URL 0364 * @param string &$server discovered OpenID server URL 0365 * @param float &$version discovered OpenID protocol version 0366 * @param long &$expires expiration UNIX time 0367 * @return bool 0368 */ 0369 public function getDiscoveryInfo($id, &$realId, &$server, &$version, &$expires) 0370 { 0371 $name = $this->_dir . '/discovery_' . md5($id); 0372 $lock = @fopen($this->_dir . '/discovery.lock', 'w+'); 0373 if ($lock === false) { 0374 return false; 0375 } 0376 if (!flock($lock, LOCK_EX)) { 0377 fclose($lock); 0378 return false; 0379 } 0380 try { 0381 $f = @fopen($name, 'r'); 0382 if ($f === false) { 0383 fclose($lock); 0384 return false; 0385 } 0386 $ret = false; 0387 $data = stream_get_contents($f); 0388 if (!empty($data)) { 0389 list($storedId, $realId, $server, $version, $expires) = unserialize($data); 0390 if ($id === $storedId && $expires > time()) { 0391 $ret = true; 0392 } else { 0393 fclose($f); 0394 @unlink($name); 0395 fclose($lock); 0396 return false; 0397 } 0398 } 0399 fclose($f); 0400 fclose($lock); 0401 return $ret; 0402 } catch (Exception $e) { 0403 fclose($lock); 0404 throw $e; 0405 } 0406 } 0407 0408 /** 0409 * Removes cached information discovered from identity $id 0410 * 0411 * @param string $id identity 0412 * @return bool 0413 */ 0414 public function delDiscoveryInfo($id) 0415 { 0416 $name = $this->_dir . '/discovery_' . md5($id); 0417 $lock = @fopen($this->_dir . '/discovery.lock', 'w+'); 0418 if ($lock === false) { 0419 return false; 0420 } 0421 if (!flock($lock, LOCK_EX)) { 0422 fclose($lock); 0423 return false; 0424 } 0425 try { 0426 @unlink($name); 0427 fclose($lock); 0428 return true; 0429 } catch (Exception $e) { 0430 fclose($lock); 0431 throw $e; 0432 } 0433 } 0434 0435 /** 0436 * The function checks the uniqueness of openid.response_nonce 0437 * 0438 * @param string $provider openid.openid_op_endpoint field from authentication response 0439 * @param string $nonce openid.response_nonce field from authentication response 0440 * @return bool 0441 */ 0442 public function isUniqueNonce($provider, $nonce) 0443 { 0444 $name = $this->_dir . '/nonce_' . md5($provider.';'.$nonce); 0445 $lock = @fopen($this->_dir . '/nonce.lock', 'w+'); 0446 if ($lock === false) { 0447 return false; 0448 } 0449 if (!flock($lock, LOCK_EX)) { 0450 fclose($lock); 0451 return false; 0452 } 0453 try { 0454 $f = @fopen($name, 'x'); 0455 if ($f === false) { 0456 fclose($lock); 0457 return false; 0458 } 0459 fwrite($f, $provider.';'.$nonce); 0460 fclose($f); 0461 fclose($lock); 0462 return true; 0463 } catch (Exception $e) { 0464 fclose($lock); 0465 throw $e; 0466 } 0467 } 0468 0469 /** 0470 * Removes data from the uniqueness database that is older then given date 0471 * 0472 * @param mixed $date date of expired data 0473 */ 0474 public function purgeNonces($date=null) 0475 { 0476 $lock = @fopen($this->_dir . '/nonce.lock', 'w+'); 0477 if ($lock !== false) { 0478 flock($lock, LOCK_EX); 0479 } 0480 try { 0481 if (!is_int($date) && !is_string($date)) { 0482 $nonceFiles = glob($this->_dir . '/nonce_*'); 0483 foreach ((array) $nonceFiles as $name) { 0484 @unlink($name); 0485 } 0486 unset($nonceFiles); 0487 } else { 0488 if (is_string($date)) { 0489 $time = time($date); 0490 } else { 0491 $time = $date; 0492 } 0493 $nonceFiles = glob($this->_dir . '/nonce_*'); 0494 foreach ((array) $nonceFiles as $name) { 0495 if (filemtime($name) < $time) { 0496 @unlink($name); 0497 } 0498 } 0499 unset($nonceFiles); 0500 } 0501 if ($lock !== false) { 0502 fclose($lock); 0503 } 0504 } catch (Exception $e) { 0505 if ($lock !== false) { 0506 fclose($lock); 0507 } 0508 throw $e; 0509 } 0510 } 0511 }