web/lib/Zend/Auth/Adapter/Digest.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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_Auth
       
    17  * @subpackage Adapter
       
    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: Digest.php 23088 2010-10-11 19:53:24Z padraic $
       
    21  */
       
    22 
       
    23 
       
    24 /**
       
    25  * @see Zend_Auth_Adapter_Interface
       
    26  */
       
    27 require_once 'Zend/Auth/Adapter/Interface.php';
       
    28 
       
    29 
       
    30 /**
       
    31  * @category   Zend
       
    32  * @package    Zend_Auth
       
    33  * @subpackage Adapter
       
    34  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    35  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    36  */
       
    37 class Zend_Auth_Adapter_Digest implements Zend_Auth_Adapter_Interface
       
    38 {
       
    39     /**
       
    40      * Filename against which authentication queries are performed
       
    41      *
       
    42      * @var string
       
    43      */
       
    44     protected $_filename;
       
    45 
       
    46     /**
       
    47      * Digest authentication realm
       
    48      *
       
    49      * @var string
       
    50      */
       
    51     protected $_realm;
       
    52 
       
    53     /**
       
    54      * Digest authentication user
       
    55      *
       
    56      * @var string
       
    57      */
       
    58     protected $_username;
       
    59 
       
    60     /**
       
    61      * Password for the user of the realm
       
    62      *
       
    63      * @var string
       
    64      */
       
    65     protected $_password;
       
    66 
       
    67     /**
       
    68      * Sets adapter options
       
    69      *
       
    70      * @param  mixed $filename
       
    71      * @param  mixed $realm
       
    72      * @param  mixed $username
       
    73      * @param  mixed $password
       
    74      * @return void
       
    75      */
       
    76     public function __construct($filename = null, $realm = null, $username = null, $password = null)
       
    77     {
       
    78         $options = array('filename', 'realm', 'username', 'password');
       
    79         foreach ($options as $option) {
       
    80             if (null !== $$option) {
       
    81                 $methodName = 'set' . ucfirst($option);
       
    82                 $this->$methodName($$option);
       
    83             }
       
    84         }
       
    85     }
       
    86 
       
    87     /**
       
    88      * Returns the filename option value or null if it has not yet been set
       
    89      *
       
    90      * @return string|null
       
    91      */
       
    92     public function getFilename()
       
    93     {
       
    94         return $this->_filename;
       
    95     }
       
    96 
       
    97     /**
       
    98      * Sets the filename option value
       
    99      *
       
   100      * @param  mixed $filename
       
   101      * @return Zend_Auth_Adapter_Digest Provides a fluent interface
       
   102      */
       
   103     public function setFilename($filename)
       
   104     {
       
   105         $this->_filename = (string) $filename;
       
   106         return $this;
       
   107     }
       
   108 
       
   109     /**
       
   110      * Returns the realm option value or null if it has not yet been set
       
   111      *
       
   112      * @return string|null
       
   113      */
       
   114     public function getRealm()
       
   115     {
       
   116         return $this->_realm;
       
   117     }
       
   118 
       
   119     /**
       
   120      * Sets the realm option value
       
   121      *
       
   122      * @param  mixed $realm
       
   123      * @return Zend_Auth_Adapter_Digest Provides a fluent interface
       
   124      */
       
   125     public function setRealm($realm)
       
   126     {
       
   127         $this->_realm = (string) $realm;
       
   128         return $this;
       
   129     }
       
   130 
       
   131     /**
       
   132      * Returns the username option value or null if it has not yet been set
       
   133      *
       
   134      * @return string|null
       
   135      */
       
   136     public function getUsername()
       
   137     {
       
   138         return $this->_username;
       
   139     }
       
   140 
       
   141     /**
       
   142      * Sets the username option value
       
   143      *
       
   144      * @param  mixed $username
       
   145      * @return Zend_Auth_Adapter_Digest Provides a fluent interface
       
   146      */
       
   147     public function setUsername($username)
       
   148     {
       
   149         $this->_username = (string) $username;
       
   150         return $this;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Returns the password option value or null if it has not yet been set
       
   155      *
       
   156      * @return string|null
       
   157      */
       
   158     public function getPassword()
       
   159     {
       
   160         return $this->_password;
       
   161     }
       
   162 
       
   163     /**
       
   164      * Sets the password option value
       
   165      *
       
   166      * @param  mixed $password
       
   167      * @return Zend_Auth_Adapter_Digest Provides a fluent interface
       
   168      */
       
   169     public function setPassword($password)
       
   170     {
       
   171         $this->_password = (string) $password;
       
   172         return $this;
       
   173     }
       
   174 
       
   175     /**
       
   176      * Defined by Zend_Auth_Adapter_Interface
       
   177      *
       
   178      * @throws Zend_Auth_Adapter_Exception
       
   179      * @return Zend_Auth_Result
       
   180      */
       
   181     public function authenticate()
       
   182     {
       
   183         $optionsRequired = array('filename', 'realm', 'username', 'password');
       
   184         foreach ($optionsRequired as $optionRequired) {
       
   185             if (null === $this->{"_$optionRequired"}) {
       
   186                 /**
       
   187                  * @see Zend_Auth_Adapter_Exception
       
   188                  */
       
   189                 require_once 'Zend/Auth/Adapter/Exception.php';
       
   190                 throw new Zend_Auth_Adapter_Exception("Option '$optionRequired' must be set before authentication");
       
   191             }
       
   192         }
       
   193 
       
   194         if (false === ($fileHandle = @fopen($this->_filename, 'r'))) {
       
   195             /**
       
   196              * @see Zend_Auth_Adapter_Exception
       
   197              */
       
   198             require_once 'Zend/Auth/Adapter/Exception.php';
       
   199             throw new Zend_Auth_Adapter_Exception("Cannot open '$this->_filename' for reading");
       
   200         }
       
   201 
       
   202         $id       = "$this->_username:$this->_realm";
       
   203         $idLength = strlen($id);
       
   204 
       
   205         $result = array(
       
   206             'code'  => Zend_Auth_Result::FAILURE,
       
   207             'identity' => array(
       
   208                 'realm'    => $this->_realm,
       
   209                 'username' => $this->_username,
       
   210                 ),
       
   211             'messages' => array()
       
   212             );
       
   213 
       
   214         while ($line = trim(fgets($fileHandle))) {
       
   215             if (substr($line, 0, $idLength) === $id) {
       
   216                 if ($this->_secureStringCompare(substr($line, -32), md5("$this->_username:$this->_realm:$this->_password"))) {
       
   217                     $result['code'] = Zend_Auth_Result::SUCCESS;
       
   218                 } else {
       
   219                     $result['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
       
   220                     $result['messages'][] = 'Password incorrect';
       
   221                 }
       
   222                 return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']);
       
   223             }
       
   224         }
       
   225 
       
   226         $result['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
       
   227         $result['messages'][] = "Username '$this->_username' and realm '$this->_realm' combination not found";
       
   228         return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']);
       
   229     }
       
   230     
       
   231     /**
       
   232      * Securely compare two strings for equality while avoided C level memcmp()
       
   233      * optimisations capable of leaking timing information useful to an attacker
       
   234      * attempting to iteratively guess the unknown string (e.g. password) being
       
   235      * compared against.
       
   236      *
       
   237      * @param string $a
       
   238      * @param string $b
       
   239      * @return bool
       
   240      */
       
   241     protected function _secureStringCompare($a, $b)
       
   242     {
       
   243         if (strlen($a) !== strlen($b)) {
       
   244             return false;
       
   245         }
       
   246         $result = 0;
       
   247         for ($i = 0; $i < strlen($a); $i++) {
       
   248             $result |= ord($a[$i]) ^ ord($b[$i]);
       
   249         }
       
   250         return $result == 0;
       
   251     }
       
   252 }