PageRenderTime 204ms CodeModel.GetById 81ms app.highlight 6ms RepoModel.GetById 114ms app.codeStats 0ms

/Auth/Adapter/Digest.php

https://bitbucket.org/goldie/zend-framework1
PHP | 252 lines | 104 code | 23 blank | 125 comment | 11 complexity | ed24998a8768f9730711f94a62737b2e MD5 | raw file
  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-2011 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 23775 2011-03-01 17:25:24Z ralph $
 21 */
 22
 23
 24/**
 25 * @see Zend_Auth_Adapter_Interface
 26 */
 27require_once 'Zend/Auth/Adapter/Interface.php';
 28
 29
 30/**
 31 * @category   Zend
 32 * @package    Zend_Auth
 33 * @subpackage Adapter
 34 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 35 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 36 */
 37class 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}