Ignore:
Timestamp:
Apr 19, 2006 3:14:28 AM (18 years ago)
Author:
scdev
Message:

Q - Cleaned up Auth_File to work more like Auth_SQL, and fixed a few bugs here and there.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/Auth_File.inc.php

    r102 r103  
    55 *
    66 * @author  Quinn Comendant <quinn@strangecode.com>
    7  * @version 1.1
     7 * @version 1.2
    88 */
     9 
     10// Usage example:
     11// $auth = new Auth_File();
     12// $auth->setParam(array(
     13//     'htpasswd_file' => COMMON_BASE . '/global/site_users.htpasswd',
     14//     'login_timeout' => 21600,
     15//     'idle_timeout' => 3600,
     16//     'login_url' => '/login.php'
     17// ));
    918
    1019// Available encryption types for class Auth_SQL.
     
    1625class Auth_File {
    1726
    18     var $_params = array(
     27    var $_auth = '';
     28    var $_sess = '_auth_';
     29    var $_params = array();
     30    var $_default_params = array(
     31       
     32        // Full path to htpasswd file.
     33        'htpasswd_file' => null,
     34
     35        // The type of encryption to use for passwords stored in the db_table. Use one of the AUTH_ENCRYPT_* types specified above.
    1936        'encryption_type' => AUTH_ENCRYPT_CRYPT,
    20         'htpasswd_file' => null,
    21         'login_timeout' => 21600, // 6 hours.
    22         'idle_timeout' => 3600, // 1 hour.
    23         'login_url' => '/login.php',
     37
     38        // The URL to the login script.
     39        'login_url' => '/',
     40
     41        // The maximum amount of time a user is allowed to be logged in. They will be forced to login again if they expire.
     42        // This applies to admins and users. In seconds. 21600 seconds = 6 hours.
     43        'login_timeout' => 21600,
     44
     45        // The maximum amount of time a user is allowed to be idle before their session expires. They will be forced to login again if they expire.
     46        // This applies to admins and users. In seconds. 3600 seconds = 1 hour.
     47        'idle_timeout' => 3600,
     48
     49        // An array of IP blocks that are bypass the remote_ip comparison check. Useful for dynamic IPs or those behind proxy servers.
     50        'trusted_networks' => array(),
    2451    );
     52
     53    // Associative array of usernames to hashed passwords.
    2554    var $_users = array();
    2655
     
    3261     * @param optional array $params  A hash containing parameters.
    3362     */
    34     function Auth_File($params = array())
    35     {
    36         $this->_params = array_merge($this->_params, $params);
    37 
    38         if (!empty($this->_params['htpasswd_file'])) {
    39             if (false === ($users = file($this->_params['htpasswd_file']))) {
    40                 App::logMsg(sprintf(_("Could not read htpasswd file: %s"), $this->_params['htpasswd_file']), LOG_ERR, __FILE__, __LINE__);
    41             }
    42             if (is_array($users)) {
    43                 foreach ($users as $line) {
    44                     list($user, $pass) = explode(':', $line, 2);
    45                     $this->_users[trim($user)] = trim($pass);
    46                 }
    47             }
    48         }
     63    function Auth_File($auth_name=null)
     64    {
     65        if (isset($auth_name)) {
     66            $this->_auth = $auth_name;
     67            $this->_sess .= $auth_name;
     68        }
     69
     70        // Initialize default parameters.
     71        $this->setParam($this->_default_params);
    4972    }
    5073
     
    87110    function clearAuth()
    88111    {
    89         $_SESSION['_auth_file'] = array('authenticated' => false);
    90     }
    91 
     112        $_SESSION[$this->_sess] = array('authenticated' => false);
     113    }
     114
     115
     116    /**
     117     * Sets a variable into a registered auth session.
     118     *
     119     * @access public
     120     * @param mixed $key      Which value to set.
     121     * @param mixed $val      Value to set variable to.
     122     */
     123    function setVal($key, $val)
     124    {
     125        if (!isset($_SESSION[$this->_sess]['user_data'])) {
     126            $_SESSION[$this->_sess]['user_data'] = array();
     127        }
     128        $_SESSION[$this->_sess]['user_data'][$key] = $val;
     129    }
     130
     131    /**
     132     * Returns a specified value from a registered auth session.
     133     *
     134     * @access public
     135     * @param mixed $key      Which value to return.
     136     * @param mixed $default  Value to return if key not found in user_data.
     137     * @return mixed          Value stored in session.
     138     */
     139    function getVal($key, $default='')
     140    {
     141        if (isset($_SESSION[$this->_sess][$key])) {
     142            return $_SESSION[$this->_sess][$key];
     143        } else if (isset($_SESSION[$this->_sess]['user_data'][$key])) {
     144            return $_SESSION[$this->_sess]['user_data'][$key];
     145        } else {
     146            return $default;
     147        }
     148    }
    92149    /**
    93150     * Find out if a set of login credentials are valid. Only supports
     
    104161    {
    105162        if ('' == trim($password)) {
    106             App::logMsg(_("No password provided for htpasswd authentication."), LOG_INFO, __FILE__, __LINE__);
    107             return false;
    108         }
     163            App::logMsg(_("No password provided for authentication."), LOG_INFO, __FILE__, __LINE__);
     164            return false;
     165        }
     166       
     167        // Load users file.
     168        $this->_loadHTPasswdFile();
    109169
    110170        if (!isset($this->_users[$username])) {
     
    113173        }
    114174
    115         if ($this->_encrypt($password, $this->_users[$username]) == $this->_users[$username]) {
    116             return true;
    117         } else {
     175        if ($this->_encrypt($password, $this->_users[$username]) != $this->_users[$username]) {
    118176            App::logMsg(sprintf('Authentication failed for user %s', $username), LOG_INFO, __FILE__, __LINE__);
    119177            return false;
    120178        }
     179       
     180        // Authentication successful!
     181        return true;
    121182    }
    122183
     
    137198        $this->clearAuth();
    138199
    139         if ($this->authenticate($username, $password)) {
    140             $_SESSION['_auth_file'] = array(
    141                 'authenticated' => true,
    142                 'username' => $username,
    143                 'login_datetime' => date('Y-m-d H:i:s'),
    144                 'last_access_datetime' => date('Y-m-d H:i:s'),
    145                 'remote_addr' => getRemoteAddr()
    146             );
    147             return true;
    148         }
    149         return false;
     200        if (!$this->authenticate($username, $password)) {
     201            // No login: failed authentication!
     202            return false;
     203        }
     204       
     205        $_SESSION[$this->_sess] = array(
     206            'authenticated' => true,
     207            'username' => $username,
     208            'login_datetime' => date('Y-m-d H:i:s'),
     209            'last_access_datetime' => date('Y-m-d H:i:s'),
     210            'remote_ip' => getRemoteAddr()
     211        );
     212
     213        // We're logged-in!
     214        return true;
    150215    }
    151216
     
    162227    function isLoggedIn()
    163228    {
    164         if (isset($_SESSION['_auth_file'])) {
    165             if (true === $_SESSION['_auth_file']['authenticated']
    166             && !empty($_SESSION['_auth_file']['username'])
    167             && strtotime($_SESSION['_auth_file']['login_datetime']) > time() - $this->_params['login_timeout']
    168             && strtotime($_SESSION['_auth_file']['last_access_datetime']) > time() - $this->_params['idle_timeout']
    169             && $_SESSION['_auth_file']['remote_addr'] == getRemoteAddr()
    170             ) {
    171                 $_SESSION['_auth_file']['last_access_datetime'] = date('Y-m-d H:i:s');
    172                 return true;
    173             } else if (true === $_SESSION['_auth_file']['authenticated']) {
     229        // Some users will access from networks with a changing IP number (i.e. behind a proxy server). These users must be allowed entry by adding their IP to the list of trusted_networks.
     230        if ($trusted_net = ipInRange(getRemoteAddr(), $this->_params['trusted_networks'])) {
     231            $user_in_trusted_network = true;
     232            App::logMsg(sprintf('User %s accessing from trusted network %s', $_SESSION[$this->_sess]['username'], $trusted_net), LOG_DEBUG, __FILE__, __LINE__);
     233        } else if (preg_match('/proxy.aol.com$/i', getRemoteAddr(true))) {
     234            $user_in_trusted_network = true;
     235            App::logMsg(sprintf('User %s accessing from trusted network proxy.aol.com', $_SESSION[$this->_sess]['username']), LOG_DEBUG, __FILE__, __LINE__);
     236        } else {
     237            $user_in_trusted_network = false;
     238        }
     239
     240        // Test login with information stored in session. Skip IP matching for users from trusted networks.
     241        if (isset($_SESSION[$this->_sess])
     242            && true === $_SESSION[$this->_sess]['authenticated']
     243            && !empty($_SESSION[$this->_sess]['username'])
     244            && strtotime($_SESSION[$this->_sess]['login_datetime']) > time() - $this->_params['login_timeout']
     245            && strtotime($_SESSION[$this->_sess]['last_access_datetime']) > time() - $this->_params['idle_timeout']
     246            && ($_SESSION[$this->_sess]['remote_ip'] == getRemoteAddr() || $user_in_trusted_network)
     247        ) {
     248            // User is authenticated!
     249            $_SESSION[$this->_sess]['last_access_datetime'] = date('Y-m-d H:i:s');
     250            return true;
     251        } else if (isset($_SESSION[$this->_sess]) && true === $_SESSION[$this->_sess]['authenticated']) {
     252            if (strtotime($_SESSION[$this->_sess]['last_access_datetime']) > time() - 43200) {
     253                // Only raise message if last session is less than 12 hours old.
    174254                App::raiseMsg(_("Your session has closed. You need to log-in again."), MSG_NOTICE, __FILE__, __LINE__);
    175                 $this->clearAuth();
    176                 return false;
    177             }
    178         }
     255            }
     256
     257            // Log the reason for login expiration.
     258            $expire_reasons = array();
     259            if (empty($_SESSION[$this->_sess]['username'])) {
     260                $expire_reasons[] = 'username not found';
     261            }
     262            if (strtotime($_SESSION[$this->_sess]['login_datetime']) <= time() - $this->_params['login_timeout']) {
     263                $expire_reasons[] = 'login_timeout expired';
     264            }
     265            if (strtotime($_SESSION[$this->_sess]['last_access_datetime']) <= time() - $this->_params['idle_timeout']) {
     266                $expire_reasons[] = 'idle_timeout expired';
     267            }
     268            if ($_SESSION[$this->_sess]['remote_ip'] != getRemoteAddr() && !$user_in_trusted_network) {
     269                $expire_reasons[] = sprintf('remote_ip not matched (%s != %s)', $_SESSION[$this->_sess]['remote_ip'], getRemoteAddr());
     270            }
     271            App::logMsg(sprintf('User %s session expired: %s', $_SESSION[$this->_sess]['username'], join(', ', $expire_reasons)), LOG_INFO, __FILE__, __LINE__);
     272        }
     273
    179274        return false;
    180275    }
     
    193288    {
    194289        if (!$this->isLoggedIn()) {
    195             // Display message for requiring login.
     290            // Display message for requiring login. (RaiseMsg will ignore empty strings.)
    196291            App::raiseMsg($message, $type, $file, $line);
    197292
     
    200295            App::dieURL($this->_params['login_url']);
    201296        }
     297    }
     298   
     299    /*
     300    * Reads the configured htpasswd file into the _users array.
     301    *
     302    * @access   public
     303    * @return   false on error, true on success.
     304    * @author   Quinn Comendant <quinn@strangecode.com>
     305    * @version  1.0
     306    * @since    18 Apr 2006 18:17:48
     307    */
     308    function _loadHTPasswdFile()
     309    {
     310        static $users = null;
     311       
     312        if (!file_exists($this->_params['htpasswd_file'])) {
     313            App::logMsg(sprintf('htpasswd file missing or not specified: %s', $this->_params['htpasswd_file']), LOG_ERR, __FILE__, __LINE__);
     314            return false;
     315        }
     316       
     317        if (!isset($users)) {
     318            if (false === ($users = file($this->_params['htpasswd_file']))) {
     319                App::logMsg(sprintf(_("Could not read htpasswd file: %s"), $this->_params['htpasswd_file']), LOG_ERR, __FILE__, __LINE__);
     320                return false;
     321            }
     322        }
     323
     324        if (is_array($users)) {
     325            foreach ($users as $u) {
     326                list($user, $pass) = explode(':', $u, 2);
     327                $this->_users[trim($user)] = trim($pass);
     328            }
     329            return true;
     330        }
     331        return false;
    202332    }
    203333
Note: See TracChangeset for help on using the changeset viewer.