File indexing completed on 2024-12-22 05:36:28
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Auth 0017 * @subpackage Adapter 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Auth_Adapter_Interface 0026 */ 0027 // require_once 'Zend/Auth/Adapter/Interface.php'; 0028 0029 0030 /** 0031 * @category Zend 0032 * @package Zend_Auth 0033 * @subpackage Adapter 0034 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0035 * @license http://framework.zend.com/license/new-bsd New BSD License 0036 */ 0037 class Zend_Auth_Adapter_Digest implements Zend_Auth_Adapter_Interface 0038 { 0039 /** 0040 * Filename against which authentication queries are performed 0041 * 0042 * @var string 0043 */ 0044 protected $_filename; 0045 0046 /** 0047 * Digest authentication realm 0048 * 0049 * @var string 0050 */ 0051 protected $_realm; 0052 0053 /** 0054 * Digest authentication user 0055 * 0056 * @var string 0057 */ 0058 protected $_username; 0059 0060 /** 0061 * Password for the user of the realm 0062 * 0063 * @var string 0064 */ 0065 protected $_password; 0066 0067 /** 0068 * Sets adapter options 0069 * 0070 * @param mixed $filename 0071 * @param mixed $realm 0072 * @param mixed $username 0073 * @param mixed $password 0074 */ 0075 public function __construct($filename = null, $realm = null, $username = null, $password = null) 0076 { 0077 $options = array('filename', 'realm', 'username', 'password'); 0078 foreach ($options as $option) { 0079 if (null !== $$option) { 0080 $methodName = 'set' . ucfirst($option); 0081 $this->$methodName($$option); 0082 } 0083 } 0084 } 0085 0086 /** 0087 * Returns the filename option value or null if it has not yet been set 0088 * 0089 * @return string|null 0090 */ 0091 public function getFilename() 0092 { 0093 return $this->_filename; 0094 } 0095 0096 /** 0097 * Sets the filename option value 0098 * 0099 * @param mixed $filename 0100 * @return Zend_Auth_Adapter_Digest Provides a fluent interface 0101 */ 0102 public function setFilename($filename) 0103 { 0104 $this->_filename = (string) $filename; 0105 return $this; 0106 } 0107 0108 /** 0109 * Returns the realm option value or null if it has not yet been set 0110 * 0111 * @return string|null 0112 */ 0113 public function getRealm() 0114 { 0115 return $this->_realm; 0116 } 0117 0118 /** 0119 * Sets the realm option value 0120 * 0121 * @param mixed $realm 0122 * @return Zend_Auth_Adapter_Digest Provides a fluent interface 0123 */ 0124 public function setRealm($realm) 0125 { 0126 $this->_realm = (string) $realm; 0127 return $this; 0128 } 0129 0130 /** 0131 * Returns the username option value or null if it has not yet been set 0132 * 0133 * @return string|null 0134 */ 0135 public function getUsername() 0136 { 0137 return $this->_username; 0138 } 0139 0140 /** 0141 * Sets the username option value 0142 * 0143 * @param mixed $username 0144 * @return Zend_Auth_Adapter_Digest Provides a fluent interface 0145 */ 0146 public function setUsername($username) 0147 { 0148 $this->_username = (string) $username; 0149 return $this; 0150 } 0151 0152 /** 0153 * Returns the password option value or null if it has not yet been set 0154 * 0155 * @return string|null 0156 */ 0157 public function getPassword() 0158 { 0159 return $this->_password; 0160 } 0161 0162 /** 0163 * Sets the password option value 0164 * 0165 * @param mixed $password 0166 * @return Zend_Auth_Adapter_Digest Provides a fluent interface 0167 */ 0168 public function setPassword($password) 0169 { 0170 $this->_password = (string) $password; 0171 return $this; 0172 } 0173 0174 /** 0175 * Defined by Zend_Auth_Adapter_Interface 0176 * 0177 * @throws Zend_Auth_Adapter_Exception 0178 * @return Zend_Auth_Result 0179 */ 0180 public function authenticate() 0181 { 0182 $optionsRequired = array('filename', 'realm', 'username', 'password'); 0183 foreach ($optionsRequired as $optionRequired) { 0184 if (null === $this->{"_$optionRequired"}) { 0185 /** 0186 * @see Zend_Auth_Adapter_Exception 0187 */ 0188 // require_once 'Zend/Auth/Adapter/Exception.php'; 0189 throw new Zend_Auth_Adapter_Exception("Option '$optionRequired' must be set before authentication"); 0190 } 0191 } 0192 0193 if (false === ($fileHandle = @fopen($this->_filename, 'r'))) { 0194 /** 0195 * @see Zend_Auth_Adapter_Exception 0196 */ 0197 // require_once 'Zend/Auth/Adapter/Exception.php'; 0198 throw new Zend_Auth_Adapter_Exception("Cannot open '$this->_filename' for reading"); 0199 } 0200 0201 $id = "$this->_username:$this->_realm"; 0202 $idLength = strlen($id); 0203 0204 $result = array( 0205 'code' => Zend_Auth_Result::FAILURE, 0206 'identity' => array( 0207 'realm' => $this->_realm, 0208 'username' => $this->_username, 0209 ), 0210 'messages' => array() 0211 ); 0212 0213 while ($line = trim(fgets($fileHandle))) { 0214 if (substr($line, 0, $idLength) === $id) { 0215 if ($this->_secureStringCompare(substr($line, -32), md5("$this->_username:$this->_realm:$this->_password"))) { 0216 $result['code'] = Zend_Auth_Result::SUCCESS; 0217 } else { 0218 $result['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; 0219 $result['messages'][] = 'Password incorrect'; 0220 } 0221 return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); 0222 } 0223 } 0224 0225 $result['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; 0226 $result['messages'][] = "Username '$this->_username' and realm '$this->_realm' combination not found"; 0227 return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); 0228 } 0229 0230 /** 0231 * Securely compare two strings for equality while avoided C level memcmp() 0232 * optimisations capable of leaking timing information useful to an attacker 0233 * attempting to iteratively guess the unknown string (e.g. password) being 0234 * compared against. 0235 * 0236 * @param string $a 0237 * @param string $b 0238 * @return bool 0239 */ 0240 protected function _secureStringCompare($a, $b) 0241 { 0242 if (strlen($a) !== strlen($b)) { 0243 return false; 0244 } 0245 $result = 0; 0246 for ($i = 0; $i < strlen($a); $i++) { 0247 $result |= ord($a[$i]) ^ ord($b[$i]); 0248 } 0249 return $result == 0; 0250 } 0251 }