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');
 ?>