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 }