PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

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