Commit 28e928775d9a58b957666d6fb5f013e26ce034c1
1 parent
d68677d7
Rework the login/session verification code to make it easier to
understand, and to make it more dynamic in terms of error conditions later on. git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5175 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
6 changed files
with
141 additions
and
121 deletions
lib/authentication/authenticationprovider.inc.php
| ... | ... | @@ -87,4 +87,20 @@ class KTAuthenticationProvider extends KTStandardDispatcher { |
| 87 | 87 | function do_performEditSourceProvider() { |
| 88 | 88 | return $this->errorRedirectTo('viewsource', _kt("Provider does not support editing"), 'source_id=' . $_REQUEST['source_id']); |
| 89 | 89 | } |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Perform provider-specific on-logout activities | |
| 93 | + * | |
| 94 | + * @param User The user who has just logged in | |
| 95 | + */ | |
| 96 | + function login($oUser) { | |
| 97 | + } | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Perform provider-specific on-logout activities | |
| 101 | + * | |
| 102 | + * @param User The user who is about to be logged out | |
| 103 | + */ | |
| 104 | + function logout($oUser) { | |
| 105 | + } | |
| 90 | 106 | } | ... | ... |
lib/authentication/authenticationutil.inc.php
| ... | ... | @@ -42,16 +42,26 @@ class KTAuthenticationUtil { |
| 42 | 42 | return KTAuthenticationUtil::getAuthenticatorForSource($iSourceId); |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | + function &getAuthenticationProviderForUser($oUser) { | |
| 46 | + $iSourceId = $oUser->getAuthenticationSourceId(); | |
| 47 | + return KTAuthenticationUtil::getAuthenticationProviderForSource($iSourceId); | |
| 48 | + } | |
| 49 | + | |
| 45 | 50 | function &getAuthenticatorForSource($oSource) { |
| 51 | + $oProvider =& KTAuthenticationUtil::getAuthenticationProviderForSource($oSource); | |
| 52 | + return $oProvider->getAuthenticator($oSource); | |
| 53 | + } | |
| 54 | + | |
| 55 | + function &getAuthenticationProviderForSource($oSource) { | |
| 46 | 56 | if ($oSource) { |
| 47 | 57 | $oSource =& KTUtil::getObject('KTAuthenticationSource', $oSource); |
| 48 | 58 | $sProvider = $oSource->getAuthenticationProvider(); |
| 49 | 59 | $oRegistry =& KTAuthenticationProviderRegistry::getSingleton(); |
| 50 | 60 | $oProvider =& $oRegistry->getAuthenticationProvider($sProvider); |
| 51 | 61 | } else { |
| 52 | - $oProvider = new KTBuiltinAuthenticationProvider; | |
| 62 | + $oProvider =& new KTBuiltinAuthenticationProvider; | |
| 53 | 63 | } |
| 54 | - return $oProvider->getAuthenticator($oSource); | |
| 64 | + return $oProvider; | |
| 55 | 65 | } |
| 56 | 66 | |
| 57 | 67 | function synchroniseGroupToSource($oGroup) { | ... | ... |
lib/dispatcher.inc.php
| ... | ... | @@ -197,19 +197,13 @@ class KTStandardDispatcher extends KTDispatcher { |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | 199 | function loginRequired() { |
| 200 | - $url = generateControllerUrl("login"); | |
| 201 | - $redirect = urlencode($_SERVER['REQUEST_URI']); | |
| 202 | - if ((strlen($redirect) > 1)) { | |
| 203 | - $url = $url . "&redirect=" . $redirect; | |
| 204 | - } | |
| 205 | - redirect($url); | |
| 206 | - exit(0); | |
| 200 | + checkSessionAndRedirect(true); | |
| 207 | 201 | } |
| 208 | 202 | |
| 209 | 203 | function dispatch () { |
| 210 | - $session = new Session(); | |
| 211 | - $sessionStatus = $session->verify($bDownload); | |
| 212 | - if ($sessionStatus === false) { | |
| 204 | + $this->session = new Session(); | |
| 205 | + $sessionStatus = $this->session->verify(); | |
| 206 | + if ($sessionStatus !== true) { | |
| 213 | 207 | $this->loginRequired(); |
| 214 | 208 | } |
| 215 | 209 | ... | ... |
lib/session/Session.inc
| ... | ... | @@ -10,7 +10,6 @@ |
| 10 | 10 | * it under the terms of the GNU General Public License as published by |
| 11 | 11 | * the Free Software Foundation; using version 2 of the License. |
| 12 | 12 | * |
| 13 | - * | |
| 14 | 13 | * This program is distributed in the hope that it will be useful, |
| 15 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ... | ... | @@ -21,9 +20,8 @@ |
| 21 | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 22 | 21 | * |
| 23 | 22 | * @version $Revision$ |
| 24 | - * @author Michael Joseph <michael@jamwarehouse.com>, Jam Warehouse (Pty) Ltd, South Africa | |
| 25 | - * @package lib.session | |
| 26 | 23 | */ |
| 24 | + | |
| 27 | 25 | class Session { |
| 28 | 26 | |
| 29 | 27 | /** |
| ... | ... | @@ -32,13 +30,14 @@ class Session { |
| 32 | 30 | * @param int the id of the user to create a session for |
| 33 | 31 | * @return string the generated sessionID |
| 34 | 32 | */ |
| 35 | - function create($iUserID) { | |
| 33 | + function create($oUser) { | |
| 34 | + $iUserId = $oUser->getId(); | |
| 36 | 35 | global $default; |
| 37 | 36 | |
| 38 | 37 | session_start(); |
| 39 | 38 | |
| 40 | 39 | // bind user id to session |
| 41 | - $_SESSION["userID"] = $iUserID; | |
| 40 | + $_SESSION["userID"] = $iUserId; | |
| 42 | 41 | $_SESSION["KTErrorMessage"] = array(); |
| 43 | 42 | |
| 44 | 43 | // use the PHP generated session id |
| ... | ... | @@ -47,13 +46,12 @@ class Session { |
| 47 | 46 | // retrieve client ip |
| 48 | 47 | $ip = $this->getClientIP(); |
| 49 | 48 | |
| 50 | - $default->log->debug("Session::create() new session for $iUserID, from $ip, sessionID=$sessionID"); | |
| 49 | + $default->log->debug("Session::create() new session for $iUserId, from $ip, sessionID=$sessionID"); | |
| 51 | 50 | |
| 52 | 51 | // insert session information into db |
| 53 | - $sql = $default->db; | |
| 54 | 52 | $aParams = array( |
| 55 | 53 | 'session_id' => $sessionID, |
| 56 | - 'user_id' => $iUserID, | |
| 54 | + 'user_id' => $iUserId, | |
| 57 | 55 | 'lastused' => date("Y-m-d H:i:s", time()), |
| 58 | 56 | 'ip' => $ip, |
| 59 | 57 | ); |
| ... | ... | @@ -62,6 +60,10 @@ class Session { |
| 62 | 60 | if (PEAR::isError($result)) { |
| 63 | 61 | die("Error creating session: " . $result->toString()); |
| 64 | 62 | } |
| 63 | + | |
| 64 | + $oProvider =& KTAuthenticationUtil::getAuthenticationProviderForUser($oUser); | |
| 65 | + $oProvider->login($oUser); | |
| 66 | + | |
| 65 | 67 | return $sessionID; |
| 66 | 68 | } |
| 67 | 69 | |
| ... | ... | @@ -106,85 +108,75 @@ class Session { |
| 106 | 108 | * @param boolean optional parameter set if we're downloading a file |
| 107 | 109 | * @return int session verification status |
| 108 | 110 | */ |
| 109 | - function verify($bDownload = false) { | |
| 110 | - global $default, $lang_sesstimeout, $lang_sessinuse, $lang_err_sess_notvalid; | |
| 111 | + function verify() { | |
| 112 | + global $default; | |
| 113 | + | |
| 111 | 114 | // this is a workaround for an SSL download bug with IE. |
| 112 | 115 | session_cache_limiter('none'); |
| 113 | 116 | session_start(); |
| 114 | 117 | header("Cache-Control: must-revalidate"); |
| 115 | 118 | header("Expires: " . gmdate("D, d M Y H:i:s", time() - 3600) . " GMT"); |
| 116 | 119 | $sessionID = session_id(); |
| 117 | - if (strlen($sessionID) > 0) { | |
| 118 | - // initialise return status | |
| 119 | - $sessionStatus = 0; | |
| 120 | - | |
| 121 | - // this should be an existing session, so check the db | |
| 122 | - $sql = $default->db; | |
| 123 | - $sql->query(array("SELECT * FROM $default->sessions_table WHERE session_id = ?", $sessionID));/*ok*/ | |
| 124 | - $numrows = $sql->num_rows($sql); | |
| 125 | - | |
| 126 | - // FIXME: if there aren't more rows that the max sessions for this user | |
| 127 | - if ($numrows >= 1) { | |
| 128 | - $default->log->debug("Session::verify found session in db"); | |
| 129 | - while($sql->next_record()) { | |
| 130 | - $iUserID = $sql->f("user_id"); | |
| 131 | - $ip = $this->getClientIP(); | |
| 132 | - // check that ip matches | |
| 133 | - if ($ip == trim($sql->f("ip"))) { | |
| 134 | - // now check if the timeout has been exceeded | |
| 135 | - $lastused = $sql->f("lastused"); | |
| 136 | - $diff = time() - strtotime($lastused); | |
| 137 | - if($diff <= $default->sessionTimeout) { | |
| 138 | - // session has been verified, update status | |
| 139 | - $sessionStatus = 1; | |
| 140 | - // use userID to refresh user details and set on session | |
| 141 | - | |
| 142 | - // ??: will this change during a user session? | |
| 143 | - // only set the userID if its not in the array already | |
| 144 | - if (!$_SESSION["userID"]) { | |
| 145 | - $_SESSION["userID"] = $iUserID; | |
| 146 | - } | |
| 147 | - | |
| 148 | - // update last used timestamp | |
| 149 | - $aFV = array( | |
| 150 | - 'lastused' => getCurrentDateTime(), | |
| 151 | - ); | |
| 152 | - $aWFV = array( | |
| 153 | - 'user_id' => $iUserID, | |
| 154 | - 'session_id' => $sessionID, | |
| 155 | - ); | |
| 156 | - $res = DBUtil::whereUpdate($default->sessions_table, $aFV, $aWFV); | |
| 157 | - // add the array to the session | |
| 158 | - $_SESSION["sessionStatus"] = $sessionStatus; | |
| 159 | - } else { | |
| 160 | - // session timed out status | |
| 161 | - $sessionStatus = 2; | |
| 162 | - // destroy this session | |
| 163 | - $this->destroy(); | |
| 164 | - $_SESSION["errorMessage"] = $lang_sesstimeout; | |
| 165 | - } | |
| 166 | - } else { | |
| 167 | - // session in use status | |
| 168 | - $sessionStatus = 3; | |
| 169 | - $_SESSION["errorMessage"] = $lang_sessinuse; | |
| 170 | - } | |
| 171 | - } | |
| 172 | - } else { | |
| 173 | - // the session doesn't exist in the db | |
| 174 | - $default->log->info("Session::verify sessionID=$sessionID, not in db"); | |
| 175 | - $sessionStatus = false; | |
| 176 | - } | |
| 177 | - } else { | |
| 120 | + | |
| 121 | + if (empty($sessionID)) { | |
| 178 | 122 | $default->log->info("Session::verify session not in db"); |
| 179 | - // there is no session | |
| 180 | - $sessionStatus = false; | |
| 123 | + return PEAR::raiseError('You need to login to access this page'); | |
| 124 | + } | |
| 125 | + | |
| 126 | + // this should be an existing session, so check the db | |
| 127 | + $aRows = DBUtil::getResultArray(array("SELECT * FROM $default->sessions_table WHERE session_id = ?", $sessionID)); | |
| 128 | + $numrows = count($aRows); | |
| 129 | + | |
| 130 | + // FIXME: if there aren't more rows that the max sessions for this user | |
| 131 | + if ($numrows < 1) { | |
| 132 | + // the session doesn't exist in the db | |
| 133 | + $default->log->info("Session::verify sessionID=$sessionID, not in db"); | |
| 134 | + return PEAR::raiseError('You need to login to access this page'); | |
| 135 | + return false; | |
| 181 | 136 | } |
| 182 | - | |
| 183 | - // remove old sessions | |
| 184 | - Session::removeStaleSessions(); | |
| 185 | 137 | |
| 186 | - // return the status | |
| 187 | - return $sessionStatus; | |
| 138 | + $default->log->debug("Session::verify found session in db"); | |
| 139 | + $aRow = $aRows[0]; | |
| 140 | + // foreach ($aRows as $aRow) { | |
| 141 | + | |
| 142 | + $iUserID = $aRow["user_id"]; | |
| 143 | + | |
| 144 | + // check that ip matches | |
| 145 | + $ip = $this->getClientIP(); | |
| 146 | + if ($ip != trim($aRow["ip"])) { | |
| 147 | + return PEAR::raiseError("You are coming from a different IP address than the session requires"); | |
| 148 | + return false; | |
| 149 | + } | |
| 150 | + | |
| 151 | + | |
| 152 | + // now check if the timeout has been exceeded | |
| 153 | + $lastused = $aRow["lastused"]; | |
| 154 | + $diff = time() - strtotime($lastused); | |
| 155 | + if($diff <= $default->sessionTimeout) { | |
| 156 | + // update last used timestamp | |
| 157 | + $aFV = array( | |
| 158 | + 'lastused' => getCurrentDateTime(), | |
| 159 | + ); | |
| 160 | + $aWFV = array( | |
| 161 | + 'user_id' => $iUserID, | |
| 162 | + 'session_id' => $sessionID, | |
| 163 | + ); | |
| 164 | + $res = DBUtil::whereUpdate($default->sessions_table, $aFV, $aWFV); | |
| 165 | + // add the array to the session | |
| 166 | + $_SESSION["sessionStatus"] = $sessionStatus; | |
| 167 | + | |
| 168 | + Session::removeStaleSessions(); | |
| 169 | + | |
| 170 | + return true; | |
| 171 | + } else { | |
| 172 | + return PEAR::raiseError('Session timed out'); | |
| 173 | + } | |
| 174 | + | |
| 175 | + // } | |
| 176 | + | |
| 177 | + Session::removeStaleSessions(); | |
| 178 | + | |
| 179 | + return false; | |
| 188 | 180 | } |
| 189 | 181 | |
| 190 | 182 | /** | ... | ... |
lib/session/control.inc
| ... | ... | @@ -126,37 +126,42 @@ function checkSessionAndRedirect($bRedirect, $bDownload = false) { |
| 126 | 126 | global $default; |
| 127 | 127 | |
| 128 | 128 | $session = new Session(); |
| 129 | - $sessionStatus = $session->verify($bDownload); | |
| 129 | + $sessionStatus = $session->verify(); | |
| 130 | 130 | |
| 131 | - if ($sessionStatus != 1) { | |
| 132 | - // verification failed | |
| 133 | - $default->log->debug("checkSession:: session check failed"); | |
| 134 | - if ($bRedirect) { | |
| 135 | - // redirect to login with error message | |
| 136 | - if ($sessionStatus == 2) { | |
| 137 | - // session timed out | |
| 138 | - $url = generateControllerUrl("login", "errorMessage=" . urlencode("Session timed out")); | |
| 139 | - } else { | |
| 140 | - $url = generateControllerUrl("login"); | |
| 141 | - } | |
| 142 | - $redirect = urlencode(KTUtil::addQueryStringSelf($_SERVER["QUERY_STRING"])); | |
| 143 | - if ((strlen($redirect) > 1)) { | |
| 144 | - $default->log->debug("checkSession:: redirect url=$redirect"); | |
| 145 | - // this session verification failure represents either the first visit to | |
| 146 | - // the site OR a session timeout etc. (in which case we still want to bounce | |
| 147 | - // the user to the login page, and then back to whatever page they're on now) | |
| 148 | - $url = $url . "&redirect=" . $redirect; | |
| 149 | - } | |
| 150 | - $default->log->debug("checkSession:: about to redirect to $url"); | |
| 151 | - redirect($url); | |
| 152 | - exit; | |
| 153 | - } else { | |
| 154 | - return false; | |
| 155 | - } | |
| 156 | - } else { | |
| 131 | + if ($sessionStatus === true) { | |
| 157 | 132 | $default->log->debug("checkSession:: returning true"); |
| 158 | 133 | return true; |
| 159 | 134 | } |
| 135 | + | |
| 136 | + // verification failed | |
| 137 | + $default->log->debug("checkSession:: session check failed"); | |
| 138 | + if (empty($bRedirect)) { | |
| 139 | + return false; | |
| 140 | + } | |
| 141 | + | |
| 142 | + $sErrorMessage = ""; | |
| 143 | + if (PEAR::isError($sessionStatus)) { | |
| 144 | + $sErrorMessage = $sessionStatus->getMessage(); | |
| 145 | + } | |
| 146 | + // redirect to login with error message | |
| 147 | + if ($sErrorMessage) { | |
| 148 | + // session timed out | |
| 149 | + $url = generateControllerUrl("login", "errorMessage=" . urlencode($sErrorMessage)); | |
| 150 | + } else { | |
| 151 | + $url = generateControllerUrl("login"); | |
| 152 | + } | |
| 153 | + | |
| 154 | + $redirect = urlencode(KTUtil::addQueryStringSelf($_SERVER["QUERY_STRING"])); | |
| 155 | + if ((strlen($redirect) > 1)) { | |
| 156 | + $default->log->debug("checkSession:: redirect url=$redirect"); | |
| 157 | + // this session verification failure represents either the first visit to | |
| 158 | + // the site OR a session timeout etc. (in which case we still want to bounce | |
| 159 | + // the user to the login page, and then back to whatever page they're on now) | |
| 160 | + $url = $url . "&redirect=" . $redirect; | |
| 161 | + } | |
| 162 | + $default->log->debug("checkSession:: about to redirect to $url"); | |
| 163 | + redirect($url); | |
| 164 | + exit; | |
| 160 | 165 | } |
| 161 | 166 | |
| 162 | 167 | /** | ... | ... |
login.php
| ... | ... | @@ -38,11 +38,11 @@ class LoginPageDispatcher extends KTDispatcher { |
| 38 | 38 | |
| 39 | 39 | function check() { |
| 40 | 40 | // bounce out immediately. |
| 41 | - $session = new Session(); | |
| 42 | - if ($session->verify() == 1) { // erk. neil - DOUBLE CHECK THIS PLEASE. | |
| 41 | + $this->session = new Session(); | |
| 42 | + if ($this->session->verify() == 1) { // erk. neil - DOUBLE CHECK THIS PLEASE. | |
| 43 | 43 | exit(redirect(generateControllerLink('dashboard'))); |
| 44 | 44 | } else { |
| 45 | - $session->destroy(); // toast it - its probably a hostile session. | |
| 45 | + $this->session->destroy(); // toast it - its probably a hostile session. | |
| 46 | 46 | } |
| 47 | 47 | return true; |
| 48 | 48 | } |
| ... | ... | @@ -139,7 +139,7 @@ class LoginPageDispatcher extends KTDispatcher { |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | $session = new Session(); |
| 142 | - $sessionID = $session->create($oUser->getId()); | |
| 142 | + $sessionID = $session->create($oUser); | |
| 143 | 143 | |
| 144 | 144 | // DEPRECATED initialise page-level authorisation array |
| 145 | 145 | $_SESSION["pageAccess"] = NULL; |
| ... | ... | @@ -156,6 +156,9 @@ class LoginPageDispatcher extends KTDispatcher { |
| 156 | 156 | } else { |
| 157 | 157 | $url = generateControllerUrl("dashboard"); |
| 158 | 158 | } |
| 159 | + $oAuthenticator =& KTAuthenticationUtil::getAuthenticatorForUser($oUser); | |
| 160 | + $oAuthenticator->login($oUser); | |
| 161 | + | |
| 159 | 162 | exit(redirect($url)); |
| 160 | 163 | } |
| 161 | 164 | } | ... | ... |