PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

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

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