diff --git a/include/class.auth.php b/include/class.auth.php index 3609e2d8921a01ebe5ab38103e900380ce44f465..51474a5f6158c9b4357a35e9b656eca6fd1c4c5f 100644 --- a/include/class.auth.php +++ b/include/class.auth.php @@ -43,48 +43,23 @@ class AuthenticationBackend { } /* static */ - function process($username, $password=null, $backend=null, &$errors) { - global $ost; + 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) // 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) { - //Log debug info. - $ost->logDebug('Staff login', - sprintf("%s logged in [%s], via %s", $result->getUserName(), - $_SERVER['REMOTE_ADDR'], get_class($bk))); //Debug. - - if ($result instanceof Staff) { - $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() ' - .' WHERE staff_id='.db_input($result->getId()); - db_query($sql); - //Now set session crap and lets roll baby! - $_SESSION['_staff'] = array(); //clear. - $_SESSION['_staff']['userID'] = $username; - $result->refreshSession(); //set the hash. - - $_SESSION['TZ_OFFSET'] = $result->getTZoffset(); - $_SESSION['TZ_DST'] = $result->observeDaylight(); - - $_SESSION['_staff']['backend'] = $bk; - } - - //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', $result); - - $result->cancelResetTokens(); - + static::_login($result, $username, $bk); + $result->backend = $bk; return $result; } // TODO: Handle permission denied, for instance @@ -97,6 +72,83 @@ class AuthenticationBackend { Signal::send('auth.login.failed', null, $info); } + function singleSignOn(&$errors) { + global $ost; + + foreach (static::$registry 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; + return $result; + } + // TODO: Handle permission denied, for instance + elseif ($result instanceof AccessDenied) { + $errors['err'] = $result->reason; + break; + } + } + } + + 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, $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 */ @@ -144,6 +196,16 @@ class AuthenticationBackend { function supportsPasswordReset() { return false; } + + /* abstract */ + function authenticate($username, $password) { + return false; + } + + /* abstract */ + function signOn() { + return false; + } } class RemoteAuthenticationBackend { diff --git a/scp/login.php b/scp/login.php index 7c13cf68b495fd76b12e3a33f744fc85c16d0a5c..5d49282b8a6bbed101a07d0c73b48490495f52bb 100644 --- a/scp/login.php +++ b/scp/login.php @@ -22,17 +22,12 @@ require_once(INCLUDE_DIR.'class.csrf.php'); $dest = $_SESSION['_staff']['auth']['dest']; $msg = $_SESSION['_staff']['auth']['msg']; $msg = $msg?$msg:'Authentication Required'; +$dest=($dest && (!strstr($dest,'login.php') && !strstr($dest,'ajax.php')))?$dest:'index.php'; if($_POST) { // Lookup support backends for this staff $username = trim($_POST['userid']); - $sql = 'SELECT backend FROM '.STAFF_TABLE - .' WHERE username='.db_input($username) - .' OR email='.db_input($username); - $backend = db_result(db_query($sql)); - if ($user = AuthenticationBackend::process($username, - $_POST['passwd'], $backend, $errors)) { - $dest=($dest && (!strstr($dest,'login.php') && !strstr($dest,'ajax.php')))?$dest:'index.php'; + $_POST['passwd'], $errors)) { @header("Location: $dest"); require_once('index.php'); //Just incase header is messed up. exit; @@ -40,6 +35,14 @@ if($_POST) { $msg = $errors['err']?$errors['err']:'Invalid login'; } + +// Consider single sign-on authentication backends +if (!$thisstaff->getId() || !$thisstaff->isValid()) { + if (($user = AuthenticationBackend::singleSignOn($errors)) + && ($user instanceof Staff)) + @header("Location: $dest"); +} + define("OSTSCPINC",TRUE); //Make includes happy! include_once(INCLUDE_DIR.'staff/login.tpl.php'); ?>