/Zend/OpenId/Consumer/Storage/File.php

https://github.com/ftaiolivista/Zend-Framework-Namespaced- · PHP · 517 lines · 365 code · 15 blank · 137 comment · 60 complexity · c889df72463e8964c22b2bd3ca457d57 MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_OpenId
  17. * @subpackage Zend_OpenId_Consumer
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: File.php 23161 2010-10-19 16:08:36Z matthew $
  21. */
  22. /**
  23. * @namespace
  24. */
  25. namespace Zend\OpenId\Consumer\Storage;
  26. use Zend\OpenId;
  27. /**
  28. * @see Zend_OpenId_Consumer_Storage
  29. */
  30. require_once "Zend/OpenId/Consumer/Storage.php";
  31. /**
  32. * External storage implemmentation using serialized files
  33. *
  34. * @category Zend
  35. * @package Zend_OpenId
  36. * @subpackage Zend_OpenId_Consumer
  37. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class File extends Storage
  41. {
  42. /**
  43. * Directory name to store data files in
  44. *
  45. * @var string $_dir
  46. */
  47. private $_dir;
  48. /**
  49. * Constructs storage object and creates storage directory
  50. *
  51. * @param string $dir directory name to store data files in
  52. * @throws Zend_OpenId_Exception
  53. */
  54. public function __construct($dir = null)
  55. {
  56. if ($dir === null) {
  57. $tmp = getenv('TMP');
  58. if (empty($tmp)) {
  59. $tmp = getenv('TEMP');
  60. if (empty($tmp)) {
  61. $tmp = "/tmp";
  62. }
  63. }
  64. $user = get_current_user();
  65. if (is_string($user) && !empty($user)) {
  66. $tmp .= '/' . $user;
  67. }
  68. $dir = $tmp . '/openid/consumer';
  69. }
  70. $this->_dir = $dir;
  71. if (!is_dir($this->_dir)) {
  72. if (!@mkdir($this->_dir, 0700, 1)) {
  73. /**
  74. * @see Zend_OpenId_Exception
  75. */
  76. require_once 'Zend/OpenId/Exception.php';
  77. throw new OpenId\Exception(
  78. 'Cannot access storage directory ' . $dir,
  79. OpenId\Exception::ERROR_STORAGE);
  80. }
  81. }
  82. if (($f = fopen($this->_dir.'/assoc.lock', 'w+')) === null) {
  83. /**
  84. * @see Zend_OpenId_Exception
  85. */
  86. require_once 'Zend/OpenId/Exception.php';
  87. throw new OpenId\Exception(
  88. 'Cannot create a lock file in the directory ' . $dir,
  89. OpenId\Exception::ERROR_STORAGE);
  90. }
  91. fclose($f);
  92. if (($f = fopen($this->_dir.'/discovery.lock', 'w+')) === null) {
  93. /**
  94. * @see Zend_OpenId_Exception
  95. */
  96. require_once 'Zend/OpenId/Exception.php';
  97. throw new OpenId\Exception(
  98. 'Cannot create a lock file in the directory ' . $dir,
  99. OpenId\Exception::ERROR_STORAGE);
  100. }
  101. fclose($f);
  102. if (($f = fopen($this->_dir.'/nonce.lock', 'w+')) === null) {
  103. /**
  104. * @see Zend_OpenId_Exception
  105. */
  106. require_once 'Zend/OpenId/Exception.php';
  107. throw new OpenId\Exception(
  108. 'Cannot create a lock file in the directory ' . $dir,
  109. OpenId\Exception::ERROR_STORAGE);
  110. }
  111. fclose($f);
  112. }
  113. /**
  114. * Stores information about association identified by $url/$handle
  115. *
  116. * @param string $url OpenID server URL
  117. * @param string $handle assiciation handle
  118. * @param string $macFunc HMAC function (sha1 or sha256)
  119. * @param string $secret shared secret
  120. * @param long $expires expiration UNIX time
  121. * @return bool
  122. */
  123. public function addAssociation($url, $handle, $macFunc, $secret, $expires)
  124. {
  125. $name1 = $this->_dir . '/assoc_url_' . md5($url);
  126. $name2 = $this->_dir . '/assoc_handle_' . md5($handle);
  127. $lock = @fopen($this->_dir . '/assoc.lock', 'w+');
  128. if ($lock === false) {
  129. return false;
  130. }
  131. if (!flock($lock, LOCK_EX)) {
  132. fclose($lock);
  133. return false;
  134. }
  135. try {
  136. $f = @fopen($name1, 'w+');
  137. if ($f === false) {
  138. fclose($lock);
  139. return false;
  140. }
  141. $data = serialize(array($url, $handle, $macFunc, $secret, $expires));
  142. fwrite($f, $data);
  143. if (function_exists('symlink')) {
  144. @unlink($name2);
  145. if (symlink($name1, $name2)) {
  146. fclose($f);
  147. fclose($lock);
  148. return true;
  149. }
  150. }
  151. $f2 = @fopen($name2, 'w+');
  152. if ($f2) {
  153. fwrite($f2, $data);
  154. fclose($f2);
  155. @unlink($name1);
  156. $ret = true;
  157. } else {
  158. $ret = false;
  159. }
  160. fclose($f);
  161. fclose($lock);
  162. return $ret;
  163. } catch (\Exception $e) {
  164. fclose($lock);
  165. throw $e;
  166. }
  167. }
  168. /**
  169. * Gets information about association identified by $url
  170. * Returns true if given association found and not expired and false
  171. * otherwise
  172. *
  173. * @param string $url OpenID server URL
  174. * @param string &$handle assiciation handle
  175. * @param string &$macFunc HMAC function (sha1 or sha256)
  176. * @param string &$secret shared secret
  177. * @param long &$expires expiration UNIX time
  178. * @return bool
  179. */
  180. public function getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
  181. {
  182. $name1 = $this->_dir . '/assoc_url_' . md5($url);
  183. $lock = @fopen($this->_dir . '/assoc.lock', 'w+');
  184. if ($lock === false) {
  185. return false;
  186. }
  187. if (!flock($lock, LOCK_EX)) {
  188. fclose($lock);
  189. return false;
  190. }
  191. try {
  192. $f = @fopen($name1, 'r');
  193. if ($f === false) {
  194. fclose($lock);
  195. return false;
  196. }
  197. $ret = false;
  198. $data = stream_get_contents($f);
  199. if (!empty($data)) {
  200. list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data);
  201. if ($url === $storedUrl && $expires > time()) {
  202. $ret = true;
  203. } else {
  204. $name2 = $this->_dir . '/assoc_handle_' . md5($handle);
  205. fclose($f);
  206. @unlink($name2);
  207. @unlink($name1);
  208. fclose($lock);
  209. return false;
  210. }
  211. }
  212. fclose($f);
  213. fclose($lock);
  214. return $ret;
  215. } catch (\Exception $e) {
  216. fclose($lock);
  217. throw $e;
  218. }
  219. }
  220. /**
  221. * Gets information about association identified by $handle
  222. * Returns true if given association found and not expired and false
  223. * otherwise
  224. *
  225. * @param string $handle assiciation handle
  226. * @param string &$url OpenID server URL
  227. * @param string &$macFunc HMAC function (sha1 or sha256)
  228. * @param string &$secret shared secret
  229. * @param long &$expires expiration UNIX time
  230. * @return bool
  231. */
  232. public function getAssociationByHandle($handle, &$url, &$macFunc, &$secret, &$expires)
  233. {
  234. $name2 = $this->_dir . '/assoc_handle_' . md5($handle);
  235. $lock = @fopen($this->_dir . '/assoc.lock', 'w+');
  236. if ($lock === false) {
  237. return false;
  238. }
  239. if (!flock($lock, LOCK_EX)) {
  240. fclose($lock);
  241. return false;
  242. }
  243. try {
  244. $f = @fopen($name2, 'r');
  245. if ($f === false) {
  246. fclose($lock);
  247. return false;
  248. }
  249. $ret = false;
  250. $data = stream_get_contents($f);
  251. if (!empty($data)) {
  252. list($url, $storedHandle, $macFunc, $secret, $expires) = unserialize($data);
  253. if ($handle === $storedHandle && $expires > time()) {
  254. $ret = true;
  255. } else {
  256. fclose($f);
  257. @unlink($name2);
  258. $name1 = $this->_dir . '/assoc_url_' . md5($url);
  259. @unlink($name1);
  260. fclose($lock);
  261. return false;
  262. }
  263. }
  264. fclose($f);
  265. fclose($lock);
  266. return $ret;
  267. } catch (\Exception $e) {
  268. fclose($lock);
  269. throw $e;
  270. }
  271. }
  272. /**
  273. * Deletes association identified by $url
  274. *
  275. * @param string $url OpenID server URL
  276. * @return bool
  277. */
  278. public function delAssociation($url)
  279. {
  280. $name1 = $this->_dir . '/assoc_url_' . md5($url);
  281. $lock = @fopen($this->_dir . '/assoc.lock', 'w+');
  282. if ($lock === false) {
  283. return false;
  284. }
  285. if (!flock($lock, LOCK_EX)) {
  286. fclose($lock);
  287. return false;
  288. }
  289. try {
  290. $f = @fopen($name1, 'r');
  291. if ($f === false) {
  292. fclose($lock);
  293. return false;
  294. }
  295. $data = stream_get_contents($f);
  296. if (!empty($data)) {
  297. list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data);
  298. if ($url === $storedUrl) {
  299. $name2 = $this->_dir . '/assoc_handle_' . md5($handle);
  300. fclose($f);
  301. @unlink($name2);
  302. @unlink($name1);
  303. fclose($lock);
  304. return true;
  305. }
  306. }
  307. fclose($f);
  308. fclose($lock);
  309. return true;
  310. } catch (\Exception $e) {
  311. fclose($lock);
  312. throw $e;
  313. }
  314. }
  315. /**
  316. * Stores information discovered from identity $id
  317. *
  318. * @param string $id identity
  319. * @param string $realId discovered real identity URL
  320. * @param string $server discovered OpenID server URL
  321. * @param float $version discovered OpenID protocol version
  322. * @param long $expires expiration UNIX time
  323. * @return bool
  324. */
  325. public function addDiscoveryInfo($id, $realId, $server, $version, $expires)
  326. {
  327. $name = $this->_dir . '/discovery_' . md5($id);
  328. $lock = @fopen($this->_dir . '/discovery.lock', 'w+');
  329. if ($lock === false) {
  330. return false;
  331. }
  332. if (!flock($lock, LOCK_EX)) {
  333. fclose($lock);
  334. return false;
  335. }
  336. try {
  337. $f = @fopen($name, 'w+');
  338. if ($f === false) {
  339. fclose($lock);
  340. return false;
  341. }
  342. $data = serialize(array($id, $realId, $server, $version, $expires));
  343. fwrite($f, $data);
  344. fclose($f);
  345. fclose($lock);
  346. return true;
  347. } catch (\Exception $e) {
  348. fclose($lock);
  349. throw $e;
  350. }
  351. }
  352. /**
  353. * Gets information discovered from identity $id
  354. * Returns true if such information exists and false otherwise
  355. *
  356. * @param string $id identity
  357. * @param string &$realId discovered real identity URL
  358. * @param string &$server discovered OpenID server URL
  359. * @param float &$version discovered OpenID protocol version
  360. * @param long &$expires expiration UNIX time
  361. * @return bool
  362. */
  363. public function getDiscoveryInfo($id, &$realId, &$server, &$version, &$expires)
  364. {
  365. $name = $this->_dir . '/discovery_' . md5($id);
  366. $lock = @fopen($this->_dir . '/discovery.lock', 'w+');
  367. if ($lock === false) {
  368. return false;
  369. }
  370. if (!flock($lock, LOCK_EX)) {
  371. fclose($lock);
  372. return false;
  373. }
  374. try {
  375. $f = @fopen($name, 'r');
  376. if ($f === false) {
  377. fclose($lock);
  378. return false;
  379. }
  380. $ret = false;
  381. $data = stream_get_contents($f);
  382. if (!empty($data)) {
  383. list($storedId, $realId, $server, $version, $expires) = unserialize($data);
  384. if ($id === $storedId && $expires > time()) {
  385. $ret = true;
  386. } else {
  387. fclose($f);
  388. @unlink($name);
  389. fclose($lock);
  390. return false;
  391. }
  392. }
  393. fclose($f);
  394. fclose($lock);
  395. return $ret;
  396. } catch (\Exception $e) {
  397. fclose($lock);
  398. throw $e;
  399. }
  400. }
  401. /**
  402. * Removes cached information discovered from identity $id
  403. *
  404. * @param string $id identity
  405. * @return bool
  406. */
  407. public function delDiscoveryInfo($id)
  408. {
  409. $name = $this->_dir . '/discovery_' . md5($id);
  410. $lock = @fopen($this->_dir . '/discovery.lock', 'w+');
  411. if ($lock === false) {
  412. return false;
  413. }
  414. if (!flock($lock, LOCK_EX)) {
  415. fclose($lock);
  416. return false;
  417. }
  418. try {
  419. @unlink($name);
  420. fclose($lock);
  421. return true;
  422. } catch (\Exception $e) {
  423. fclose($lock);
  424. throw $e;
  425. }
  426. }
  427. /**
  428. * The function checks the uniqueness of openid.response_nonce
  429. *
  430. * @param string $provider openid.openid_op_endpoint field from authentication response
  431. * @param string $nonce openid.response_nonce field from authentication response
  432. * @return bool
  433. */
  434. public function isUniqueNonce($provider, $nonce)
  435. {
  436. $name = $this->_dir . '/nonce_' . md5($provider.';'.$nonce);
  437. $lock = @fopen($this->_dir . '/nonce.lock', 'w+');
  438. if ($lock === false) {
  439. return false;
  440. }
  441. if (!flock($lock, LOCK_EX)) {
  442. fclose($lock);
  443. return false;
  444. }
  445. try {
  446. $f = @fopen($name, 'x');
  447. if ($f === false) {
  448. fclose($lock);
  449. return false;
  450. }
  451. fwrite($f, $provider.';'.$nonce);
  452. fclose($f);
  453. fclose($lock);
  454. return true;
  455. } catch (\Exception $e) {
  456. fclose($lock);
  457. throw $e;
  458. }
  459. }
  460. /**
  461. * Removes data from the uniqueness database that is older then given date
  462. *
  463. * @param mixed $date date of expired data
  464. */
  465. public function purgeNonces($date=null)
  466. {
  467. $lock = @fopen($this->_dir . '/nonce.lock', 'w+');
  468. if ($lock !== false) {
  469. flock($lock, LOCK_EX);
  470. }
  471. try {
  472. if (!is_int($date) && !is_string($date)) {
  473. $nonceFiles = glob($this->_dir . '/nonce_*');
  474. foreach ((array) $nonceFiles as $name) {
  475. @unlink($name);
  476. }
  477. unset($nonceFiles);
  478. } else {
  479. if (is_string($date)) {
  480. $time = time($date);
  481. } else {
  482. $time = $date;
  483. }
  484. $nonceFiles = glob($this->_dir . '/nonce_*');
  485. foreach ((array) $nonceFiles as $name) {
  486. if (filemtime($name) < $time) {
  487. @unlink($name);
  488. }
  489. }
  490. unset($nonceFiles);
  491. }
  492. if ($lock !== false) {
  493. fclose($lock);
  494. }
  495. } catch (\Exception $e) {
  496. if ($lock !== false) {
  497. fclose($lock);
  498. }
  499. throw $e;
  500. }
  501. }
  502. }