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