summaryrefslogtreecommitdiff
path: root/includes/pear/Auth.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/pear/Auth.php')
-rw-r--r--includes/pear/Auth.php1330
1 files changed, 1330 insertions, 0 deletions
diff --git a/includes/pear/Auth.php b/includes/pear/Auth.php
new file mode 100644
index 0000000..f34b8f6
--- /dev/null
+++ b/includes/pear/Auth.php
@@ -0,0 +1,1330 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+
+/**
+ * The main include file for Auth package
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.01 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_01.txt. If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category Authentication
+ * @package Auth
+ * @author Martin Jansen <mj@php.net>
+ * @author Adam Ashley <aashley@php.net>
+ * @copyright 2001-2006 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License 3.01
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/Auth
+ */
+
+/**
+ * Returned if session exceeds idle time
+ */
+define('AUTH_IDLED', -1);
+/**
+ * Returned if session has expired
+ */
+define('AUTH_EXPIRED', -2);
+/**
+ * Returned if container is unable to authenticate user/password pair
+ */
+define('AUTH_WRONG_LOGIN', -3);
+/**
+ * Returned if a container method is not supported.
+ */
+define('AUTH_METHOD_NOT_SUPPORTED', -4);
+/**
+ * Returned if new Advanced security system detects a breach
+ */
+define('AUTH_SECURITY_BREACH', -5);
+/**
+ * Returned if checkAuthCallback says session should not continue.
+ */
+define('AUTH_CALLBACK_ABORT', -6);
+
+/**
+ * Auth Log level - INFO
+ */
+define('AUTH_LOG_INFO', 6);
+/**
+ * Auth Log level - DEBUG
+ */
+define('AUTH_LOG_DEBUG', 7);
+
+/**
+ * Auth Advanced Security - IP Checks
+ */
+define('AUTH_ADV_IPCHECK', 1);
+/**
+ * Auth Advanced Security - User Agent Checks
+ */
+define('AUTH_ADV_USERAGENT', 2);
+/**
+ * Auth Advanced Security - Challenge Response
+ */
+define('AUTH_ADV_CHALLENGE', 3);
+
+
+/**
+ * PEAR::Auth
+ *
+ * The PEAR::Auth class provides methods for creating an
+ * authentication system using PHP.
+ *
+ * @category Authentication
+ * @package Auth
+ * @author Martin Jansen <mj@php.net>
+ * @author Adam Ashley <aashley@php.net>
+ * @copyright 2001-2006 The PHP Group
+ * @license http://www.php.net/license/3_01.txt PHP License 3.01
+ * @version Release: @package_version@ File: $Revision$
+ * @link http://pear.php.net/package/Auth
+ */
+class Auth {
+
+ // {{{ properties
+
+ /**
+ * Auth lifetime in seconds
+ *
+ * If this variable is set to 0, auth never expires
+ *
+ * @var integer
+ * @see setExpire(), checkAuth()
+ */
+ private $expire = 0;
+
+ /**
+ * Has the auth session expired?
+ *
+ * @var bool
+ * @see checkAuth()
+ */
+ private $expired = false;
+
+ /**
+ * Maximum idletime in seconds
+ *
+ * The difference to $expire is, that the idletime gets
+ * refreshed each time checkAuth() is called. If this
+ * variable is set to 0, idletime is never checked.
+ *
+ * @var integer
+ * @see setIdle(), checkAuth()
+ */
+ private $idle = 0;
+
+ /**
+ * Is the maximum idletime over?
+ *
+ * @var boolean
+ * @see checkAuth()
+ */
+ private $idled = false;
+
+ /**
+ * Storage object
+ *
+ * @var object
+ * @see Auth(), validateLogin()
+ */
+ private $storage = '';
+
+ /**
+ * User-defined function that creates the login screen
+ *
+ * @var string
+ */
+ private $loginFunction = '';
+
+ /**
+ * Should the login form be displayed
+ *
+ * @var bool
+ * @see setShowlogin()
+ */
+ private $showLogin = true;
+
+ /**
+ * Is Login Allowed from this page
+ *
+ * @var bool
+ * @see setAllowLogin
+ */
+ private $allowLogin = true;
+
+ /**
+ * Current authentication status
+ *
+ * @var string
+ */
+ private $status = '';
+
+ /**
+ * Username
+ *
+ * @var string
+ */
+ private $username = '';
+
+ /**
+ * Password
+ *
+ * @var string
+ */
+ private $password = '';
+
+ /**
+ * checkAuth callback function name
+ *
+ * @var string
+ * @see setCheckAuthCallback()
+ */
+ private $checkAuthCallback = '';
+
+ /**
+ * Login callback function name
+ *
+ * @var string
+ * @see setLoginCallback()
+ */
+ private $loginCallback = '';
+
+ /**
+ * Failed Login callback function name
+ *
+ * @var string
+ * @see setFailedLoginCallback()
+ */
+ private $loginFailedCallback = '';
+
+ /**
+ * Logout callback function name
+ *
+ * @var string
+ * @see setLogoutCallback()
+ */
+ private $logoutCallback = '';
+
+ /**
+ * Auth session-array name
+ *
+ * @var string
+ */
+ private $_sessionName = '_authsession';
+
+ /**
+ * Package Version
+ *
+ * @var string
+ */
+ private $version = "@version@";
+
+ /**
+ * Flag to use advanced security
+ * When set extra checks will be made to see if the
+ * user's IP or useragent have changed across requests.
+ * Turned off by default to preserve BC.
+ *
+ * @var mixed Boolean to turn all advanced security options on or off
+ * Array containing named values turning specific advanced
+ * security features on or off individually
+ * array(
+ * AUTH_ADV_IPCHECK => true,
+ * AUTH_ADV_USERAGENT => true,
+ * AUTH_ADV_CHALLENGE => true,
+ * );
+ */
+ private $advancedsecurity = false;
+
+ /**
+ * Username key in POST array
+ *
+ * @var string
+ */
+ private $_postUsername = 'username';
+
+ /**
+ * Password key in POST array
+ *
+ * @var string
+ */
+ private $_postPassword = 'password';
+
+ /**
+ * Holds a reference to the session auth variable
+ * @var array
+ */
+ private $session;
+
+ /**
+ * Holds a reference to the global server variable
+ * @var array
+ */
+ private $server;
+
+ /**
+ * Holds a reference to the global post variable
+ * @var array
+ */
+ private $post;
+
+ /**
+ * Holds a reference to the global cookie variable
+ * @var array
+ */
+ private $cookie;
+
+ /**
+ * A hash to hold various superglobals as reference
+ * @var array
+ */
+ private $authdata;
+
+ /**
+ * How many times has checkAuth been called
+ * @var int
+ */
+ private $authChecks = 0;
+
+ /**
+ * PEAR::Log object
+ *
+ * @var object Log
+ */
+ private $logger = null;
+
+ /**
+ * Whether to enable logging of behaviour
+ *
+ * @var boolean
+ */
+ private $enableLogging = false;
+
+ /**
+ * Whether to regenerate session id everytime start is called
+ *
+ * @var boolean
+ */
+ private $regenerateSessionId = false;
+
+ // }}}
+ // {{{ Auth() [constructor]
+
+ /**
+ * Constructor
+ *
+ * Set up the storage driver.
+ *
+ * @param string Type of the storage driver
+ * @param mixed Additional options for the storage driver
+ * (example: if you are using DB as the storage
+ * driver, you have to pass the dsn string here)
+ *
+ * @param string Name of the function that creates the login form
+ * @param boolean Should the login form be displayed if necessary?
+ * @return void
+ */
+ function Auth($storageDriver, $options = '', $loginFunction = '', $showLogin = true)
+ {
+ $this->applyAuthOptions($options);
+
+ // Start the session suppress error if already started
+ if(!session_id()){
+ @session_start();
+ if(!session_id()) {
+ // Throw error
+ include_once 'PEAR.php';
+ PEAR::throwError('Session could not be started by Auth, '
+ .'possibly headers are already sent, try putting '
+ .'ob_start in the beginning of your script');
+ }
+ }
+
+ // Make Sure Auth session variable is there
+ if(!isset($_SESSION[$this->_sessionName])) {
+ $_SESSION[$this->_sessionName] = array();
+ }
+
+ // Assign Some globals to internal references, this will replace _importGlobalVariable
+ $this->session =& $_SESSION[$this->_sessionName];
+ $this->server =& $_SERVER;
+ $this->post =& $_POST;
+ $this->cookie =& $_COOKIE;
+
+ if ($loginFunction != '' && is_callable($loginFunction)) {
+ $this->loginFunction = $loginFunction;
+ }
+
+ if (is_bool($showLogin)) {
+ $this->showLogin = $showLogin;
+ }
+
+ if (is_object($storageDriver)) {
+ $this->storage =& $storageDriver;
+ // Pass a reference to auth to the container, ugly but works
+ // this is used by the DB container to use method setAuthData not staticaly.
+ $this->storage->_auth_obj =& $this;
+ } else {
+ // $this->storage = $this->_factory($storageDriver, $options);
+ //
+ $this->storage_driver = $storageDriver;
+ $this->storage_options =& $options;
+ }
+ }
+
+ // }}}
+ // {{{ applyAuthOptions()
+
+ /**
+ * Set the Auth options
+ *
+ * Some options which are Auth specific will be applied
+ * the rest will be left for usage by the container
+ *
+ * @param array An array of Auth options
+ * @return array The options which were not applied
+ */
+ private function &applyAuthOptions(&$options)
+ {
+ if(is_array($options)){
+ if (!empty($options['sessionName'])) {
+ $this->_sessionName = $options['sessionName'];
+ unset($options['sessionName']);
+ }
+ if (isset($options['allowLogin'])) {
+ $this->allowLogin = $options['allowLogin'];
+ unset($options['allowLogin']);
+ }
+ if (!empty($options['postUsername'])) {
+ $this->_postUsername = $options['postUsername'];
+ unset($options['postUsername']);
+ }
+ if (!empty($options['postPassword'])) {
+ $this->_postPassword = $options['postPassword'];
+ unset($options['postPassword']);
+ }
+ if (isset($options['advancedsecurity'])) {
+ $this->advancedsecurity = $options['advancedsecurity'];
+ unset($options['advancedsecurity']);
+ }
+ if (isset($options['enableLogging'])) {
+ $this->enableLogging = $options['enableLogging'];
+ unset($options['enableLogging']);
+ }
+ if (isset($options['regenerateSessionId']) && is_bool($options['regenerateSessionId'])) {
+ $this->regenerateSessionId = $options['regenerateSessionId'];
+ }
+ }
+ return($options);
+ }
+
+ // }}}
+ // {{{ _loadStorage()
+
+ /**
+ * Load Storage Driver if not already loaded
+ *
+ * Suspend storage instantiation to make Auth lighter to use
+ * for calls which do not require login
+ *
+ * @return bool True if the conainer is loaded, false if the container
+ * is already loaded
+ */
+ private function _loadStorage()
+ {
+ if(!is_object($this->storage)) {
+ $this->storage =& $this->_factory($this->storage_driver,
+ $this->storage_options);
+ $this->storage->_auth_obj =& $this;
+ $this->log('Loaded storage container ('.$this->storage_driver.')', AUTH_LOG_DEBUG);
+ return(true);
+ }
+ return(false);
+ }
+
+ // }}}
+ // {{{ _factory()
+
+ /**
+ * Return a storage driver based on $driver and $options
+ *
+ * @static
+ * @param string $driver Type of storage class to return
+ * @param string $options Optional parameters for the storage class
+ * @return object Object Storage object
+ */
+ private function &_factory($driver, $options = '')
+ {
+ $storage_class = 'Auth_Container_' . $driver;
+ include_once 'Auth/Container/' . $driver . '.php';
+ $obj = new $storage_class($options);
+ return $obj;
+ }
+
+ // }}}
+ // {{{ assignData()
+
+ /**
+ * Assign data from login form to internal values
+ *
+ * This function takes the values for username and password
+ * from $HTTP_POST_VARS/$_POST and assigns them to internal variables.
+ * If you wish to use another source apart from $HTTP_POST_VARS/$_POST,
+ * you have to derive this function.
+ *
+ * @global $HTTP_POST_VARS, $_POST
+ * @see Auth
+ * @return void
+ */
+ private function assignData()
+ {
+ $this->log('Auth::assignData() called.', AUTH_LOG_DEBUG);
+
+ if ( isset($this->post[$this->_postUsername])
+ && $this->post[$this->_postUsername] != '') {
+ $this->username = (get_magic_quotes_gpc() == 1
+ ? stripslashes($this->post[$this->_postUsername])
+ : $this->post[$this->_postUsername]);
+ }
+ if ( isset($this->post[$this->_postPassword])
+ && $this->post[$this->_postPassword] != '') {
+ $this->password = (get_magic_quotes_gpc() == 1
+ ? stripslashes($this->post[$this->_postPassword])
+ : $this->post[$this->_postPassword] );
+ }
+ }
+
+ // }}}
+ // {{{ start()
+
+ /**
+ * Start new auth session
+ *
+ * @return void
+ */
+ public function start()
+ {
+ $this->log('Auth::start() called.', AUTH_LOG_DEBUG);
+
+ // #10729 - Regenerate session id here if we are generating it on every
+ // page load.
+ if ($this->regenerateSessionId) {
+ session_regenerate_id(true);
+ }
+
+ $this->assignData();
+ if (!$this->checkAuth() && $this->allowLogin) {
+ $this->login();
+ }
+ }
+
+ // }}}
+ // {{{ login()
+
+ /**
+ * Login function
+ *
+ * @return void
+ */
+ private function login()
+ {
+ $this->log('Auth::login() called.', AUTH_LOG_DEBUG);
+
+ $login_ok = false;
+ $this->_loadStorage();
+
+ // Check if using challenge response
+ (isset($this->post['authsecret']) && $this->post['authsecret'] == 1)
+ ? $usingChap = true
+ : $usingChap = false;
+
+
+ // When the user has already entered a username, we have to validate it.
+ if (!empty($this->username)) {
+ if (true === $this->storage->fetchData($this->username, $this->password, $usingChap)) {
+ $this->session['challengekey'] = md5($this->username.$this->password);
+ $login_ok = true;
+ $this->log('Successful login.', AUTH_LOG_INFO);
+ }
+ }
+
+ if (!empty($this->username) && $login_ok) {
+ $this->setAuth($this->username);
+ if (is_callable($this->loginCallback)) {
+ $this->log('Calling loginCallback ('.$this->loginCallback.').', AUTH_LOG_DEBUG);
+ call_user_func_array($this->loginCallback, array($this->username, &$this));
+ }
+ }
+
+ // If the login failed or the user entered no username,
+ // output the login screen again.
+ if (!empty($this->username) && !$login_ok) {
+ $this->log('Incorrect login.', AUTH_LOG_INFO);
+ $this->status = AUTH_WRONG_LOGIN;
+ if (is_callable($this->loginFailedCallback)) {
+ $this->log('Calling loginFailedCallback ('.$this->loginFailedCallback.').', AUTH_LOG_DEBUG);
+ call_user_func_array($this->loginFailedCallback, array($this->username, &$this));
+ }
+ }
+
+ if ((empty($this->username) || !$login_ok) && $this->showLogin) {
+ $this->log('Rendering Login Form.', AUTH_LOG_INFO);
+ if (is_callable($this->loginFunction)) {
+ $this->log('Calling loginFunction ('.$this->loginFunction.').', AUTH_LOG_DEBUG);
+ call_user_func_array($this->loginFunction, array($this->username, $this->status, &$this));
+ } else {
+ // BC fix Auth used to use drawLogin for this
+ // call is sub classes implement this
+ if (is_callable(array($this, 'drawLogin'))) {
+ $this->log('Calling Auth::drawLogin()', AUTH_LOG_DEBUG);
+ return $this->drawLogin($this->username, $this);
+ }
+
+ $this->log('Using default Auth_Frontend_Html', AUTH_LOG_DEBUG);
+
+ // New Login form
+ include_once 'Auth/Frontend/Html.php';
+ return Auth_Frontend_Html::render($this, $this->username);
+ }
+ } else {
+ return;
+ }
+ }
+
+ // }}}
+ // {{{ setExpire()
+
+ /**
+ * Set the maximum expire time
+ *
+ * @param integer time in seconds
+ * @param bool add time to current expire time or not
+ * @return void
+ */
+ public function setExpire($time, $add = false)
+ {
+ $add ? $this->expire += $time : $this->expire = $time;
+ }
+
+ // }}}
+ // {{{ setIdle()
+
+ /**
+ * Set the maximum idle time
+ *
+ * @param integer time in seconds
+ * @param bool add time to current maximum idle time or not
+ * @return void
+ */
+ public function setIdle($time, $add = false)
+ {
+ $add ? $this->idle += $time : $this->idle = $time;
+ }
+
+ // }}}
+ // {{{ setSessionName()
+
+ /**
+ * Set name of the session to a customized value.
+ *
+ * If you are using multiple instances of PEAR::Auth
+ * on the same domain, you can change the name of
+ * session per application via this function.
+ * This will chnage the name of the session variable
+ * auth uses to store it's data in the session
+ *
+ * @param string New name for the session
+ * @return void
+ */
+ public function setSessionName($name = 'session')
+ {
+ $this->_sessionName = '_auth_'.$name;
+ // Make Sure Auth session variable is there
+ if(!isset($_SESSION[$this->_sessionName])) {
+ $_SESSION[$this->_sessionName] = array();
+ }
+ $this->session =& $_SESSION[$this->_sessionName];
+ }
+
+ // }}}
+ // {{{ setShowLogin()
+
+ /**
+ * Should the login form be displayed if necessary?
+ *
+ * @param bool show login form or not
+ * @return void
+ */
+ public function setShowLogin($showLogin = true)
+ {
+ $this->showLogin = $showLogin;
+ }
+
+ // }}}
+ // {{{ setAllowLogin()
+
+ /**
+ * Is Login Allowed from this page?
+ *
+ * @param bool allow login from this page or not
+ * @return void
+ */
+ public function setAllowLogin($allowLogin = true)
+ {
+ $this->allowLogin = $allowLogin;
+ }
+
+ // }}}
+ // {{{ setCheckAuthCallback()
+
+ /**
+ * Register a callback function to be called whenever the validity of the login is checked
+ * The function will receive two parameters, the username and a reference to the auth object.
+ *
+ * @param string callback function name
+ * @return void
+ * @since Method available since Release 1.4.3
+ */
+ public function setCheckAuthCallback($checkAuthCallback)
+ {
+ $this->checkAuthCallback = $checkAuthCallback;
+ }
+
+ // }}}
+ // {{{ setLoginCallback()
+
+ /**
+ * Register a callback function to be called on user login.
+ * The function will receive two parameters, the username and a reference to the auth object.
+ *
+ * @param string callback function name
+ * @return void
+ * @see setLogoutCallback()
+ */
+ public function setLoginCallback($loginCallback)
+ {
+ $this->loginCallback = $loginCallback;
+ }
+
+ // }}}
+ // {{{ setFailedLoginCallback()
+
+ /**
+ * Register a callback function to be called on failed user login.
+ * The function will receive two parameters, the username and a reference to the auth object.
+ *
+ * @param string callback function name
+ * @return void
+ */
+ public function setFailedLoginCallback($loginFailedCallback)
+ {
+ $this->loginFailedCallback = $loginFailedCallback;
+ }
+
+ // }}}
+ // {{{ setLogoutCallback()
+
+ /**
+ * Register a callback function to be called on user logout.
+ * The function will receive three parameters, the username and a reference to the auth object.
+ *
+ * @param string callback function name
+ * @return void
+ * @see setLoginCallback()
+ */
+ public function setLogoutCallback($logoutCallback)
+ {
+ $this->logoutCallback = $logoutCallback;
+ }
+
+ // }}}
+ // {{{ setAuthData()
+
+ /**
+ * Register additional information that is to be stored
+ * in the session.
+ *
+ * @param string Name of the data field
+ * @param mixed Value of the data field
+ * @param boolean Should existing data be overwritten? (default
+ * is true)
+ * @return void
+ */
+ public function setAuthData($name, $value, $overwrite = true)
+ {
+ if (!empty($this->session['data'][$name]) && $overwrite == false) {
+ return;
+ }
+ $this->session['data'][$name] = $value;
+ }
+
+ // }}}
+ // {{{ getAuthData()
+
+ /**
+ * Get additional information that is stored in the session.
+ *
+ * If no value for the first parameter is passed, the method will
+ * return all data that is currently stored.
+ *
+ * @param string Name of the data field
+ * @return mixed Value of the data field.
+ */
+ public function getAuthData($name = null)
+ {
+ if (!isset($this->session['data'])) {
+ return null;
+ }
+ if(!isset($name)) {
+ return $this->session['data'];
+ }
+ if (isset($name) && isset($this->session['data'][$name])) {
+ return $this->session['data'][$name];
+ }
+ return null;
+ }
+
+ // }}}
+ // {{{ setAuth()
+
+ /**
+ * Register variable in a session telling that the user
+ * has logged in successfully
+ *
+ * @param string Username
+ * @return void
+ */
+ public function setAuth($username)
+ {
+ $this->log('Auth::setAuth() called.', AUTH_LOG_DEBUG);
+
+ // #10729 - Regenerate session id here only if generating at login only
+ // Don't do it if we are regenerating on every request so we don't
+ // regenerate it twice in one request.
+ if (!$this->regenerateSessionId) {
+ // #2021 - Change the session id to avoid session fixation attacks php 4.3.3 >
+ session_regenerate_id(true);
+ }
+
+ if (!isset($this->session) || !is_array($this->session)) {
+ $this->session = array();
+ }
+
+ if (!isset($this->session['data'])) {
+ $this->session['data'] = array();
+ }
+
+ $this->session['sessionip'] = isset($this->server['REMOTE_ADDR'])
+ ? $this->server['REMOTE_ADDR']
+ : '';
+ $this->session['sessionuseragent'] = isset($this->server['HTTP_USER_AGENT'])
+ ? $this->server['HTTP_USER_AGENT']
+ : '';
+ $this->session['sessionforwardedfor'] = isset($this->server['HTTP_X_FORWARDED_FOR'])
+ ? $this->server['HTTP_X_FORWARDED_FOR']
+ : '';
+
+ // This should be set by the container to something more safe
+ // Like md5(passwd.microtime)
+ if(empty($this->session['challengekey'])) {
+ $this->session['challengekey'] = md5($username.microtime());
+ }
+
+ $this->session['challengecookie'] = md5($this->session['challengekey'].microtime());
+ setcookie('authchallenge', $this->session['challengecookie'], 0, '/');
+
+ $this->session['registered'] = true;
+ $this->session['username'] = $username;
+ $this->session['timestamp'] = time();
+ $this->session['idle'] = time();
+ }
+
+ // }}}
+ // {{{ setAdvancedSecurity()
+
+ /**
+ * Enables advanced security checks
+ *
+ * Currently only ip change and useragent change
+ * are detected
+ * @todo Add challenge cookies - Create a cookie which changes every time
+ * and contains some challenge key which the server can verify with
+ * a session var cookie might need to be crypted (user pass)
+ * @param bool Enable or disable
+ * @return void
+ */
+ public function setAdvancedSecurity($flag=true)
+ {
+ $this->advancedsecurity = $flag;
+ }
+
+ // }}}
+ // {{{ checkAuth()
+
+ /**
+ * Checks if there is a session with valid auth information.
+ *
+ * @return boolean Whether or not the user is authenticated.
+ */
+ public function checkAuth()
+ {
+ $this->log('Auth::checkAuth() called.', AUTH_LOG_DEBUG);
+ $this->authChecks++;
+ if (isset($this->session)) {
+ // Check if authentication session is expired
+ if ( $this->expire > 0
+ && isset($this->session['timestamp'])
+ && ($this->session['timestamp'] + $this->expire) < time()) {
+ $this->log('Session Expired', AUTH_LOG_INFO);
+ $this->expired = true;
+ $this->status = AUTH_EXPIRED;
+ $this->logout();
+ return false;
+ }
+
+ // Check if maximum idle time is reached
+ if ( $this->idle > 0
+ && isset($this->session['idle'])
+ && ($this->session['idle'] + $this->idle) < time()) {
+ $this->log('Session Idle Time Reached', AUTH_LOG_INFO);
+ $this->idled = true;
+ $this->status = AUTH_IDLED;
+ $this->logout();
+ return false;
+ }
+
+ if ( isset($this->session['registered'])
+ && isset($this->session['username'])
+ && $this->session['registered'] == true
+ && $this->session['username'] != '') {
+ Auth::updateIdle();
+
+ if ($this->_isAdvancedSecurityEnabled()) {
+ $this->log('Advanced Security Mode Enabled.', AUTH_LOG_DEBUG);
+
+ // Only Generate the challenge once
+ if ( $this->authChecks == 1
+ && $this->_isAdvancedSecurityEnabled(AUTH_ADV_CHALLENGE)) {
+ $this->log('Generating new Challenge Cookie.', AUTH_LOG_DEBUG);
+ $this->session['challengecookieold'] = $this->session['challengecookie'];
+ $this->session['challengecookie'] = md5($this->session['challengekey'].microtime());
+ setcookie('authchallenge', $this->session['challengecookie'], 0, '/');
+ }
+
+ // Check for ip change
+ if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_IPCHECK)
+ && isset($this->server['REMOTE_ADDR'])
+ && $this->session['sessionip'] != $this->server['REMOTE_ADDR']) {
+ $this->log('Security Breach. Remote IP Address changed.', AUTH_LOG_INFO);
+ // Check if the IP of the user has changed, if so we
+ // assume a man in the middle attack and log him out
+ $this->expired = true;
+ $this->status = AUTH_SECURITY_BREACH;
+ $this->logout();
+ return false;
+ }
+
+ // Check for ip change (if connected via proxy)
+ if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_IPCHECK)
+ && isset($this->server['HTTP_X_FORWARDED_FOR'])
+ && $this->session['sessionforwardedfor'] != $this->server['HTTP_X_FORWARDED_FOR']) {
+ $this->log('Security Breach. Forwarded For IP Address changed.', AUTH_LOG_INFO);
+ // Check if the IP of the user connecting via proxy has
+ // changed, if so we assume a man in the middle attack
+ // and log him out.
+ $this->expired = true;
+ $this->status = AUTH_SECURITY_BREACH;
+ $this->logout();
+ return false;
+ }
+
+ // Check for useragent change
+ if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_USERAGENT)
+ && isset($this->server['HTTP_USER_AGENT'])
+ && $this->session['sessionuseragent'] != $this->server['HTTP_USER_AGENT']) {
+ $this->log('Security Breach. User Agent changed.', AUTH_LOG_INFO);
+ // Check if the User-Agent of the user has changed, if
+ // so we assume a man in the middle attack and log him out
+ $this->expired = true;
+ $this->status = AUTH_SECURITY_BREACH;
+ $this->logout();
+ return false;
+ }
+
+ // Check challenge cookie here, if challengecookieold is not set
+ // this is the first time and check is skipped
+ // TODO when user open two pages similtaneuly (open in new window,open
+ // in tab) auth breach is caused find out a way around that if possible
+ if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_CHALLENGE)
+ && isset($this->session['challengecookieold'])
+ && $this->session['challengecookieold'] != $this->cookie['authchallenge']) {
+ $this->log('Security Breach. Challenge Cookie mismatch.', AUTH_LOG_INFO);
+ $this->expired = true;
+ $this->status = AUTH_SECURITY_BREACH;
+ $this->logout();
+ $this->login();
+ return false;
+ }
+ }
+
+ if (is_callable($this->checkAuthCallback)) {
+ $this->log('Calling checkAuthCallback ('.$this->checkAuthCallback.').', AUTH_LOG_DEBUG);
+ $checkCallback = call_user_func_array($this->checkAuthCallback, array($this->username, &$this));
+ if ($checkCallback == false) {
+ $this->log('checkAuthCallback failed.', AUTH_LOG_INFO);
+ $this->expired = true;
+ $this->status = AUTH_CALLBACK_ABORT;
+ $this->logout();
+ return false;
+ }
+ }
+
+ $this->log('Session OK.', AUTH_LOG_INFO);
+ return true;
+ }
+ } else {
+ $this->log('Unable to locate session storage.', AUTH_LOG_DEBUG);
+ return false;
+ }
+ $this->log('No login session.', AUTH_LOG_DEBUG);
+ return false;
+ }
+
+ // }}}
+ // {{{ staticCheckAuth() [static]
+
+ /**
+ * Statically checks if there is a session with valid auth information.
+ *
+ * @access public
+ * @see checkAuth
+ * @return boolean Whether or not the user is authenticated.
+ */
+ public static function staticCheckAuth($options = null)
+ {
+ static $staticAuth;
+ if(!isset($staticAuth)) {
+ $staticAuth = new Auth('null', $options);
+ }
+ $staticAuth->log('Auth::staticCheckAuth() called', AUTH_LOG_DEBUG);
+ return $staticAuth->checkAuth();
+ }
+
+ // }}}
+ // {{{ getAuth()
+
+ /**
+ * Has the user been authenticated?
+ *
+ * Is there a valid login session. Previously this was different from
+ * checkAuth() but now it is just an alias.
+ *
+ * @return bool True if the user is logged in, otherwise false.
+ */
+ public function getAuth()
+ {
+ $this->log('Auth::getAuth() called.', AUTH_LOG_DEBUG);
+ return $this->checkAuth();
+ }
+
+ // }}}
+ // {{{ logout()
+
+ /**
+ * Logout function
+ *
+ * This function clears any auth tokens in the currently
+ * active session and executes the logout callback function,
+ * if any
+ *
+ * @return void
+ */
+ public function logout()
+ {
+ $this->log('Auth::logout() called.', AUTH_LOG_DEBUG);
+
+ if (is_callable($this->logoutCallback) && isset($this->session['username'])) {
+ $this->log('Calling logoutCallback ('.$this->logoutCallback.').', AUTH_LOG_DEBUG);
+ call_user_func_array($this->logoutCallback, array($this->session['username'], &$this));
+ }
+
+ $this->username = '';
+ $this->password = '';
+
+ $this->session = null;
+ }
+
+ // }}}
+ // {{{ updateIdle()
+
+ /**
+ * Update the idletime
+ *
+ * @return void
+ */
+ public function updateIdle()
+ {
+ $this->session['idle'] = time();
+ }
+
+ // }}}
+ // {{{ getUsername()
+
+ /**
+ * Get the username
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ if (isset($this->session['username'])) {
+ return($this->session['username']);
+ }
+ return('');
+ }
+
+ // }}}
+ // {{{ getStatus()
+
+ /**
+ * Get the current status
+ *
+ * @return string
+ */
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ // }}}
+ // {{{ getPostUsernameField()
+
+ /**
+ * Gets the post varible used for the username
+ *
+ * @return string
+ */
+ public function getPostUsernameField()
+ {
+ return($this->_postUsername);
+ }
+
+ // }}}
+ // {{{ getPostPasswordField()
+
+ /**
+ * Gets the post varible used for the username
+ *
+ * @return string
+ */
+ public function getPostPasswordField()
+ {
+ return($this->_postPassword);
+ }
+
+ // }}}
+ // {{{ sessionValidThru()
+
+ /**
+ * Returns the time up to the session is valid
+ *
+ * @return integer
+ */
+ public function sessionValidThru()
+ {
+ if (!isset($this->session['idle'])) {
+ return 0;
+ }
+ if ($this->idle == 0) {
+ return 0;
+ }
+ return ($this->session['idle'] + $this->idle);
+ }
+
+ // }}}
+ // {{{ listUsers()
+
+ /**
+ * List all users that are currently available in the storage
+ * container
+ *
+ * @return array
+ */
+ public function listUsers()
+ {
+ $this->log('Auth::listUsers() called.', AUTH_LOG_DEBUG);
+ $this->_loadStorage();
+ return $this->storage->listUsers();
+ }
+
+ // }}}
+ // {{{ addUser()
+
+ /**
+ * Add user to the storage container
+ *
+ * @param string Username
+ * @param string Password
+ * @param mixed Additional parameters
+ * @return mixed True on success, PEAR error object on error
+ * and AUTH_METHOD_NOT_SUPPORTED otherwise.
+ */
+ public function addUser($username, $password, $additional = '')
+ {
+ $this->log('Auth::addUser() called.', AUTH_LOG_DEBUG);
+ $this->_loadStorage();
+ return $this->storage->addUser($username, $password, $additional);
+ }
+
+ // }}}
+ // {{{ removeUser()
+
+ /**
+ * Remove user from the storage container
+ *
+ * @param string Username
+ * @return mixed True on success, PEAR error object on error
+ * and AUTH_METHOD_NOT_SUPPORTED otherwise.
+ */
+ public function removeUser($username)
+ {
+ $this->log('Auth::removeUser() called.', AUTH_LOG_DEBUG);
+ $this->_loadStorage();
+ return $this->storage->removeUser($username);
+ }
+
+ // }}}
+ // {{{ changePassword()
+
+ /**
+ * Change password for user in the storage container
+ *
+ * @param string Username
+ * @param string The new password
+ * @return mixed True on success, PEAR error object on error
+ * and AUTH_METHOD_NOT_SUPPORTED otherwise.
+ */
+ public function changePassword($username, $password)
+ {
+ $this->log('Auth::changePassword() called', AUTH_LOG_DEBUG);
+ $this->_loadStorage();
+ return $this->storage->changePassword($username, $password);
+ }
+
+ // }}}
+ // {{{ log()
+
+ /**
+ * Log a message from the Auth system
+ *
+ * @param string The message to log
+ * @param string The log level to log the message under. See the Log documentation for more info.
+ * @return boolean
+ */
+ public function log($message, $level = AUTH_LOG_DEBUG)
+ {
+ if (!$this->enableLogging) return false;
+
+ $this->_loadLogger();
+
+ $this->logger->log('AUTH: '.$message, $level);
+ }
+
+ // }}}
+ // {{{ _loadLogger()
+
+ /**
+ * Load Log object if not already loaded
+ *
+ * Suspend logger instantiation to make Auth lighter to use
+ * for calls which do not require logging
+ *
+ * @return bool True if the logger is loaded, false if the logger
+ * is already loaded
+ */
+ private function _loadLogger()
+ {
+ if(is_null($this->logger)) {
+ if (!class_exists('Log')) {
+ include_once 'Log.php';
+ }
+ $this->logger =& Log::singleton('null',
+ null,
+ 'auth['.getmypid().']',
+ array(),
+ AUTH_LOG_DEBUG);
+ return(true);
+ }
+ return(false);
+ }
+
+ // }}}
+ // {{{ attachLogObserver()
+
+ /**
+ * Attach an Observer to the Auth Log Source
+ *
+ * @param object Log_Observer A Log Observer instance
+ * @return boolean
+ */
+ public function attachLogObserver(&$observer) {
+
+ $this->_loadLogger();
+
+ return $this->logger->attach($observer);
+
+ }
+
+ // }}}
+ // {{{ _isAdvancedSecurityEnabled()
+
+ /**
+ * Is advanced security enabled?
+ *
+ * Pass one of the Advanced Security constants as the first parameter
+ * to check if that advanced security check is enabled.
+ *
+ * @param integer
+ * @return boolean
+ */
+ private function _isAdvancedSecurityEnabled($feature = null) {
+
+ if (is_null($feature)) {
+
+ if ($this->advancedsecurity === true)
+ return true;
+
+ if ( is_array($this->advancedsecurity)
+ && in_array(true, $this->advancedsecurity, true))
+ return true;
+
+ return false;
+
+ } else {
+
+ if (is_array($this->advancedsecurity)) {
+
+ if ( isset($this->advancedsecurity[$feature])
+ && $this->advancedsecurity[$feature] == true)
+ return true;
+
+ return false;
+
+ }
+
+ return (bool)$this->advancedsecurity;
+
+ }
+
+ }
+
+ // }}}
+
+}
+?>