diff --git a/include/class.auth.php b/include/class.auth.php index 09c1a4c8f6993a2dca9267cc0a2f4220fd4de805..3071cd424b9493a19a137066dde710f1291178fb 100644 --- a/include/class.auth.php +++ b/include/class.auth.php @@ -44,15 +44,25 @@ interface AuthDirectorySearch { * receives a username and optional password. If the authentication * succeeds, an instance deriving from <User> should be returned. */ -class AuthenticationBackend { - static private $registry = array(); +abstract class AuthenticationBackend { + static protected $registry = array(); static $name; static $id; + /* static */ static function register($class) { - if (is_string($class)) + if (is_string($class) && class_exists($class)) $class = new $class(); + + if (!is_object($class) + || !($class instanceof AuthenticationBackend)) + return false; + + return static::_register($class); + } + + static function _register($class) { // XXX: Raise error if $class::id is already in the registry static::$registry[$class::$id] = $class; } @@ -65,24 +75,28 @@ class AuthenticationBackend { return static::$registry[$id]; } - /* static */ - function process($username, $password=null, &$errors) { + static function process($username, $password=null, &$errors) { + if (!$username) return false; - $backend = static::_getAllowedBackends($username); - - foreach (static::$registry as $bk) { - if ($backend && $bk->supportsAuthentication() && $bk::$id != $backend) + $backends = static::getAllowedBackends($username); + foreach (static::allRegistered() as $bk) { + if ($backends //Allowed backends + && $bk->supportsAuthentication() + && in_array($bk::$id, $backends)) // User cannot be authenticated against this backend continue; + // All backends are queried here, even if they don't support // authentication so that extensions like lockouts and audits // can be supported. $result = $bk->authenticate($username, $password); - if ($result instanceof AuthenticatedUser) { - static::_login($result, $username, $bk); - $result->backend = $bk; + + if ($result instanceof AuthenticatedUser + && (static::login($result, $bk))) { + $result->setBackend($bk); + return $result; } // TODO: Handle permission denied, for instance @@ -91,6 +105,7 @@ class AuthenticationBackend { break; } } + $info = array('username'=>$username, 'password'=>$password); Signal::send('auth.login.failed', null, $info); } @@ -98,19 +113,17 @@ class AuthenticationBackend { function singleSignOn(&$errors) { global $ost; - foreach (static::$registry as $bk) { + foreach (static::allRegistered() as $bk) { // All backends are queried here, even if they don't support // authentication so that extensions like lockouts and audits // can be supported. $result = $bk->signOn(); if ($result instanceof AuthenticatedUser) { - // Ensure staff members are allowed to be authenticated - // against this backend - if ($result instanceof Staff - && !static::_isBackendAllowed($result, $bk)) - continue; - static::_login($result, $result->getUserName(), $bk); - $result->backend = $bk; + //Perform further Object specific checks and the actual login + if (!static::login($result, $bk)) + continue + + $result->setBackend($bk); return $result; } // TODO: Handle permission denied, for instance @@ -131,57 +144,6 @@ class AuthenticationBackend { return $users; } - function _isBackendAllowed($staff, $bk) { - $sql = 'SELECT backend FROM '.STAFF_TABLE - .' WHERE staff_id='.db_input($staff->getId()); - $backend = db_result(db_query($sql)); - return !$backend || strcasecmp($bk::$id, $backend) === 0; - } - - function _getAllowedBackends($username) { - $username = trim($_POST['userid']); - $sql = 'SELECT backend FROM '.STAFF_TABLE - .' WHERE username='.db_input($username) - .' OR email='.db_input($username); - return db_result(db_query($sql)); - } - - function _login($user, $username, $bk) { - global $ost; - - if ($user instanceof Staff) { - //Log debug info. - $ost->logDebug('Staff login', - sprintf("%s logged in [%s], via %s", $user->getUserName(), - $_SERVER['REMOTE_ADDR'], get_class($bk))); //Debug. - - $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() ' - .' WHERE staff_id='.db_input($user->getId()); - db_query($sql); - //Now set session crap and lets roll baby! - $_SESSION['_staff'] = array(); //clear. - $_SESSION['_staff']['userID'] = $username; - - $user->refreshSession(); //set the hash. - - $_SESSION['TZ_OFFSET'] = $user->getTZoffset(); - $_SESSION['TZ_DST'] = $user->observeDaylight(); - } - - //Regenerate session id. - $sid = session_id(); //Current id - session_regenerate_id(true); - // Destroy old session ID - needed for PHP version < 5.1.0 - // DELME: remove when we move to php 5.3 as min. requirement. - if(($session=$ost->getSession()) && is_object($session) - && $sid!=session_id()) - $session->destroy($sid); - - Signal::send('auth.login.succeeded', $user); - - $user->cancelResetTokens(); - } - /** * Fetches the friendly name of the backend */ @@ -212,21 +174,148 @@ class AuthenticationBackend { return false; } - /* abstract */ - function authenticate($username, $password) { - return false; - } - - /* abstract */ function signOn() { - return false; + return null; } + + abstract function authenticate($username, $password); + abstract function login($user, $bk); + abstract function getAllowedBackends($userid); + } class RemoteAuthenticationBackend { var $create_unknown_user = false; } +abstract class StaffAuthenticationBackend extends AuthenticationBackend { + + static private $_registry = array(); + + static function _register($class) { + static::$_registry[$class::$id] = $class; + } + + static function allRegistered() { + return array_merge(self::$_registry, parent::allRegistered()); + } + + function isBackendAllowed($staff, $bk) { + + if (!($backends=self::getAllowedBackends($staff->getId()))) + return true; //No restrictions + + return in_array($bk::$id, array_map('strtolower', $backends)); + } + + function getAllowedBackends($userid) { + + $backends =array(); + //XXX: Only one backend can be specified at the moment. + $sql = 'SELECT backend FROM '.STAFF_TABLE + .' WHERE backend IS NOT NULL '; + if (is_numeric($userid)) + $sql.= ' AND staff_id='.db_input($userid); + else { + $sql.= ' AND (username='.db_input($userid) .' OR email='.db_input($userid).')'; + } + + if (($res=db_query($sql)) && db_num_rows($res)) + $backends[] = db_result($res); + + return array_filter($backends); + } + + function login($user, $bk) { + global $ost; + + if (!($user instanceof Staff)) + return false; + + // Ensure staff is allowed for realz to be authenticated via the backend. + if (!static::isBackendAllowed($user, $bk)) + return false; + + //Log debug info. + $ost->logDebug('Staff login', + sprintf("%s logged in [%s], via %s", $user->getUserName(), + $_SERVER['REMOTE_ADDR'], get_class($bk))); //Debug. + + $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() ' + .' WHERE staff_id='.db_input($user->getId()); + db_query($sql); + //Now set session crap and lets roll baby! + $_SESSION['_staff'] = array(); //clear. + $_SESSION['_staff']['userID'] = $user->getUserName(); + + $user->refreshSession(); //set the hash. + + $_SESSION['TZ_OFFSET'] = $user->getTZoffset(); + $_SESSION['TZ_DST'] = $user->observeDaylight(); + + //Regenerate session id. + $sid = session_id(); //Current id + session_regenerate_id(true); + // Destroy old session ID - needed for PHP version < 5.1.0 + // DELME: remove when we move to php 5.3 as min. requirement. + if(($session=$ost->getSession()) && is_object($session) + && $sid!=session_id()) + $session->destroy($sid); + + Signal::send('auth.login.succeeded', $user); + + $user->cancelResetTokens(); + + return true; + } +} + +abstract class UserAuthenticationBackend extends AuthenticationBackend { + + static private $_registry = array(); + + static function _register($class) { + static::$_registry[$class::$id] = $class; + } + + static function allRegistered() { + return array_merge(self::$_registry, parent::allRegistered()); + } + + function getAllowedBackends($userid) { + // White listing backends for specific user not supported. + return array(); + } + + function login($user, $bk) { + global $ost; + + if (!($user instanceof TicketUser)) + return false; + + $_SESSION['_client'] = array(); //clear. + $_SESSION['_client']['userID'] = $user->getEmail(); //Email + //$_SESSION['_client']['key'] = $ticket->getExtId(); //Ticket ID --acts as password when used with email. See above. + $_SESSION['_client']['token'] = $user->getSessionToken(); + $_SESSION['TZ_OFFSET'] = $ost->getConfig()->getTZoffset(); + $_SESSION['TZ_DST'] = $ost->getConfig()->observeDaylightSaving(); + $user->refreshSession(); //set the hash. + //Log login info... + $msg=sprintf('%s/%s logged in [%s]', + $user->getEmail(), $user->getId(), $_SERVER['REMOTE_ADDR']); + $ost->logDebug('User login', $msg); + + //Regenerate session ID. + $sid=session_id(); //Current session id. + session_regenerate_id(TRUE); //get new ID. + if(($session=$ost->getSession()) && is_object($session) && $sid!=session_id()) + $session->destroy($sid); + + return true; + } + +} + /** * This will be an exception in later versions of PHP */ @@ -287,8 +376,9 @@ class AuthLockoutBackend extends AuthenticationBackend { } AuthenticationBackend::register(AuthLockoutBackend); -class osTicketAuthentication extends AuthenticationBackend { - static $name = "Local Authenication"; + +class osTicketAuthentication extends StaffAuthenticationBackend { + static $name = "Local Authentication"; static $id = "local"; function authenticate($username, $password) { @@ -306,5 +396,5 @@ class osTicketAuthentication extends AuthenticationBackend { } } } -AuthenticationBackend::register(osTicketAuthentication); +StaffAuthenticationBackend::register(osTicketAuthentication); ?>