Index: branches/1.1dev/lib/AuthSQL.inc.php
===================================================================
--- branches/1.1dev/lib/AuthSQL.inc.php	(revision 203)
+++ branches/1.1dev/lib/AuthSQL.inc.php	(revision 204)
@@ -73,5 +73,5 @@
         // Specify usernames to exclude from the account abuse detection system. This is specified as a hardcoded array provided at 
         // class instantiation time, or can be saved in the user_tbl under the login_abuse_exempt field.
-        $this->_params['login_abuse_exempt_usernames'] = isset($params['login_abuse_exempt_usernames']) && is_array($params['login_abuse_exempt_usernames']) ? $params['login_abuse_exempt_usernames'] : array();
+        $this->_params['login_abuse_exempt_usernames'] = isset($params['login_abuse_exempt_usernames']) && is_array($params['login_abuse_exempt_usernames']) ? $params['login_abuse_exempt_usernames'] : $CFG->login_abuse_exempt_usernames;
         
         $this->_params['trusted_networks'] = isset($params['trusted_networks']) && is_array($params['trusted_networks']) ? $params['trusted_networks'] : $CFG->trusted_networks;
@@ -82,4 +82,10 @@
         // Feature: Use a login_tbl to detect excessive logins. This requires blocking to be enabled.
         $this->_params['features']['abuse_detection'] = isset($params['features']['abuse_detection']) ? $params['features']['abuse_detection'] : false;
+        
+        // Array of usernames which are exempt from remote_ip matching. Users behind proxy servers should be appended to this array so their shifting remote IP will not log them out.
+        $this->_params['match_remote_ip_exempt_usernames'] = isset($params['match_remote_ip_exempt_usernames']) && is_array($params['match_remote_ip_exempt_usernames']) ? $params['match_remote_ip_exempt_usernames'] : $CFG->match_remote_ip_exempt_usernames;
+
+        // Feature: Match the user's current remote IP against the one they logged in with.
+        $this->_params['features']['match_remote_ip'] = isset($params['features']['match_remote_ip']) ? $params['features']['match_remote_ip'] : true;
         
         $this->_auth_name = '_auth_' . $this->_params['auth_name'];
@@ -227,5 +233,6 @@
             'remote_ip'             => getRemoteAddr(),
             'abuse_warning_level'   => $user_data['abuse_warning_level'],
-            'login_abuse_exempt'    => isset($user_data['login_abuse_exempt']) ? !empty($user_data['login_abuse_exempt']) : in_array($username, $this->_params['login_abuse_exempt_usernames']),
+            'login_abuse_exempt'    => isset($user_data['login_abuse_exempt']) ? !empty($user_data['login_abuse_exempt']) : in_array(strtolower($username), $this->_params['login_abuse_exempt_usernames']),
+            'match_remote_ip_exempt'=> isset($user_data['match_remote_ip_exempt']) ? !empty($user_data['match_remote_ip_exempt']) : in_array(strtolower($username), $this->_params['match_remote_ip_exempt_usernames']),
             'user_data'             => $user_data
         );
@@ -364,4 +371,11 @@
         }
         
+        // Do we match the user's remote IP at all? Yes, if set in config and not disabled for specific user.
+        if ($this->getFeature('match_remote_ip') && !$this->getVal('match_remote_ip_exempt')) {
+            $remote_ip_is_matched = ($_SESSION[$this->_auth_name]['remote_ip'] == getRemoteAddr() || $user_in_trusted_network);
+        } else {
+            $remote_ip_is_matched = true;
+        }
+        
         // Test login with information stored in session. Skip IP matching for users from trusted networks.
         if (true === $_SESSION[$this->_auth_name]['authenticated']
@@ -369,5 +383,5 @@
             && strtotime($_SESSION[$this->_auth_name]['login_datetime']) > time() - $this->_params['login_timeout']
             && strtotime($_SESSION[$this->_auth_name]['last_access_datetime']) > time() - $this->_params['idle_timeout']
-            && ($_SESSION[$this->_auth_name]['remote_ip'] == getRemoteAddr() || $user_in_trusted_network)
+            && $remote_ip_is_matched
         ) {
             // User is authenticated!
@@ -403,5 +417,9 @@
             }
             if ($_SESSION[$this->_auth_name]['remote_ip'] != getRemoteAddr()) {
-                $expire_reasons[] = sprintf('remote_ip not matched (%s != %s)', $_SESSION[$this->_auth_name]['remote_ip'], getRemoteAddr());
+                if ($this->getFeature('match_remote_ip') && !$this->getVal('match_remote_ip_exempt')) {
+                    $expire_reasons[] = sprintf('remote_ip not matched (%s != %s)', $_SESSION[$this->_auth_name]['remote_ip'], getRemoteAddr());
+                } else {
+                    $expire_reasons[] = sprintf('remote_ip not matched but user was exempt from this check (%s != %s)', $_SESSION[$this->_auth_name]['remote_ip'], getRemoteAddr());
+                }
             }
             logMsg(sprintf('%s %s (%s) session expired: %s', ucfirst($this->_params['auth_name']), $this->getVal('user_id'), $this->getVal('username'), join(', ', $expire_reasons)), LOG_DEBUG, __FILE__, __LINE__);
