![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00002 /*------------------------------------------------------------------------------- 00003 * Xataface Web Application Framework 00004 * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 *------------------------------------------------------------------------------- 00020 */ 00029 import('Dataface/Table.php'); 00030 class Dataface_AuthenticationTool { 00031 00032 var $authType = 'basic'; 00033 00034 var $conf; 00038 var $delegate; 00039 00043 var $usersTable; 00044 00048 var $usernameColumn; 00049 00053 var $passwordColumn; 00054 00058 var $userLevelColumn; 00059 00060 private $emailColumn=null; 00061 00065 var $authEnabled = true; 00066 00067 public static function &getInstance($params=array()){ 00068 static $instance = 0; 00069 if ( $instance === 0 ){ 00070 $instance = new Dataface_AuthenticationTool($params); 00071 if ( !defined('DATAFACE_AUTHENTICATIONTOOL_LOADED') ){ 00072 define('DATAFACE_AUTHENTICATIONTOOL_LOADED', true); 00073 } 00074 } 00075 00076 return $instance; 00077 } 00078 00079 function Dataface_AuthenticationTool($params=array()){ 00080 $this->conf = $params; 00081 $this->usersTable = ( isset($params['users_table']) ? $params['users_table'] : null); 00082 $this->usernameColumn = ( isset($params['username_column']) ? $params['username_column'] : null); 00083 $this->passwordColumn = (isset( $params['password_column']) ? $params['password_column'] : null); 00084 $this->userLevelColumn = (isset( $params['user_level_column']) ? $params['user_level_column'] : null); 00085 00086 $this->setAuthType(@$params['auth_type']); 00087 } 00088 00089 function setAuthType($type){ 00090 if ( isset( $type ) and $type != $this->authType ){ 00091 $this->authType = $type; 00092 $this->delegate = null; 00093 // It is possible to define a delegate to this tool by adding the 00094 // auth_type option to the conf.ini file _auth section. 00095 $module = basename($type); 00096 $module_path = array( 00097 DATAFACE_SITE_PATH.'/modules/Auth/'.$module.'/'.$module.'.php', 00098 DATAFACE_PATH.'/modules/Auth/'.$module.'/'.$module.'.php' 00099 ); 00100 foreach ( $module_path as $path ){ 00101 if ( is_readable($path) ){ 00102 import($path); 00103 $classname = 'dataface_modules_'.$module; 00104 $this->delegate = new $classname; 00105 break; 00106 } 00107 } 00108 00109 } 00110 } 00111 00112 function getCredentials(){ 00113 00114 if ( isset($this->delegate) and method_exists($this->delegate, 'getCredentials') ){ 00115 return $this->delegate->getCredentials(); 00116 } else { 00117 $username = (isset($_REQUEST['UserName']) ? $_REQUEST['UserName'] : null); 00118 $password = (isset($_REQUEST['Password']) ? $_REQUEST['Password'] : null); 00119 return array('UserName'=>$username, 'Password'=>$password); 00120 } 00121 } 00122 00123 function checkCredentials(){ 00124 $app =& Dataface_Application::getInstance(); 00125 if ( !$this->authEnabled ) return true; 00126 if ( isset($this->delegate) and method_exists($this->delegate, 'checkCredentials') ){ 00127 return $this->delegate->checkCredentials(); 00128 } else { 00129 // The user is attempting to log in. 00130 $creds = $this->getCredentials(); 00131 if ( !isset( $creds['UserName'] ) || !isset($creds['Password']) ){ 00132 // The user did not submit a username of password for login.. trigger error. 00133 //throw new Exception("Username or Password Not specified", E_USER_ERROR); 00134 return false; 00135 } 00136 import('Dataface/Serializer.php'); 00137 $serializer = new Dataface_Serializer($this->usersTable); 00138 //$res = mysql_query( 00139 $sql = "SELECT `".$this->usernameColumn."` FROM `".$this->usersTable."` 00140 WHERE `".$this->usernameColumn."`='".addslashes( 00141 $serializer->serialize($this->usernameColumn, $creds['UserName']) 00142 )."' 00143 AND `".$this->passwordColumn."`=". 00144 $serializer->encrypt( 00145 $this->passwordColumn, 00146 "'".addslashes($serializer->serialize($this->passwordColumn, $creds['Password']))."'" 00147 ); 00148 $res = mysql_query($sql, $app->db()); 00149 if ( !$res ) throw new Exception(mysql_error($app->db()), E_USER_ERROR); 00150 00151 if ( mysql_num_rows($res) === 0 ){ 00152 return false; 00153 } 00154 $found = false; 00155 while ( $row = mysql_fetch_row($res) ){ 00156 if ( strcmp($row[0], $creds['UserName'])===0 ){ 00157 $found=true; 00158 break; 00159 } 00160 } 00161 @mysql_free_result($res); 00162 return $found; 00163 } 00164 00165 } 00166 00167 00168 function setPassword($password){ 00169 $app =& Dataface_Application::getInstance(); 00170 if ( isset($this->delegate) and method_exists($this->delegate, 'setPassword') ){ 00171 return $this->delegate->setPassword($username, $password); 00172 } else { 00173 00174 $user = $this->getLoggedInUser(); 00175 if ( !$user ){ 00176 00177 throw new Exception("Failed to set password because there is no logged in user."); 00178 } 00179 00180 $user->setValue($this->passwordColumn, $password); 00181 $res = $user->save(); 00182 if ( PEAR::isError($res) ){ 00183 throw new Exception($res->getMessage()); 00184 } 00185 return true; 00186 } 00187 } 00188 00189 function authenticate(){ 00190 $app =& Dataface_Application::getInstance(); 00191 if ( !$this->authEnabled ) return true; 00192 00193 00194 if ( $app->sessionEnabled() or $app->autoSession ){ 00195 $app->startSession($this->conf); 00196 } 00197 $appdel =& $app->getDelegate(); 00198 00199 // Fire a trigger before we authenticate 00200 if ( isset($appdel) and method_exists($appdel, 'before_authenticate') ){ 00201 $appdel->before_authenticate(); 00202 } 00203 00204 if ( isset( $_REQUEST['-action'] ) and $_REQUEST['-action'] == 'logout' ){ 00205 $app->startSession(); 00206 // the user has invoked a logout request. 00207 00208 if ( isset($appdel) and method_exists($appdel, 'before_action_logout' ) ){ 00209 $res = $appdel->before_action_logout(); 00210 if ( PEAR::isError($res) ) return $res; 00211 } 00212 $username = @$_SESSION['UserName']; 00213 session_destroy(); 00214 00215 import('Dataface/Utilities.php'); 00216 00217 Dataface_Utilities::fireEvent('after_action_logout', array('UserName'=>$username)); 00218 00219 00220 if ( isset($this->delegate) and method_exists($this->delegate, 'logout') ){ 00221 $this->delegate->logout(); 00222 } 00223 if ( isset($_REQUEST['-redirect']) and !empty($_REQUEST['-redirect']) ){ 00224 $app->redirect($_REQUEST['-redirect']); 00225 } else if ( isset($_SESSION['-redirect']) ){ 00226 $redirect = $_SESSION['-redirect']; 00227 unset($_SESSION['-redirect']); 00228 $app->redirect($redirect); 00229 00230 00231 } else { 00232 $app->redirect(DATAFACE_SITE_HREF); 00233 } 00234 00235 } 00236 00237 if ( isset( $_REQUEST['-action'] ) and $_REQUEST['-action'] == 'login' ){ 00238 $app->startSession(); 00239 if ( $this->isLoggedIn() ){ 00240 $app->redirect(DATAFACE_SITE_HREF.'?--msg='.urlencode("You are logged in")); 00241 00242 } 00243 00244 if ( $this->isLockedOut() ){ 00245 $app->redirect(DATAFACE_SITE_HREF.'?--msg='.urlencode("Sorry, you are currently locked out of the site due to failed login attempts. Please try again later, or contact a system administrator for help.")); 00246 00247 } 00248 // The user is attempting to log in. 00249 $creds = $this->getCredentials(); 00250 $approved = $this->checkCredentials(); 00251 00252 if ( isset($creds['UserName']) and !$approved ){ 00253 00254 $this->flagFailedAttempt($creds); 00255 00256 return PEAR::raiseError( 00257 df_translate('Incorrect Password', 00258 'Sorry, you have entered an incorrect username /password combination. Please try again.' 00259 ), 00260 DATAFACE_E_LOGIN_FAILURE 00261 ); 00262 } else if ( !$approved ){ 00263 00264 $this->showLoginPrompt(); 00265 exit; 00266 } 00267 00268 $this->clearFailedAttempts(); 00269 00270 // If we are this far, then the login worked.. We will store the 00271 // userid in the session. 00272 $_SESSION['UserName'] = $creds['UserName']; 00273 00274 import('Dataface/Utilities.php'); 00275 00276 Dataface_Utilities::fireEvent('after_action_login', array('UserName'=>$_SESSION['UserName'])); 00277 $msg = df_translate('You are now logged in','You are now logged in'); 00278 if ( isset( $_REQUEST['-redirect'] ) and !empty($_REQUEST['-redirect']) ){ 00279 00280 $redirect = df_append_query($_REQUEST['-redirect'], array('--msg'=>$msg)); 00281 //$app->redirect($redirect); 00282 00283 } else if ( isset($_SESSION['-redirect']) ){ 00284 $redirect = $_SESSION['-redirect']; 00285 unset($_SESSION['-redirect']); 00286 $redirect = df_append_query($redirect, array('--msg'=>$msg)); 00287 //$app->redirect($redirect); 00288 00289 } else { 00290 // Now we forward to the homepage: 00291 $redirect = $_SERVER['HOST_URI'].DATAFACE_SITE_HREF; 00292 } 00293 00294 $redirect = preg_replace('/-action=login_prompt/', '', $redirect); 00295 $app->redirect($redirect); 00296 00297 } 00298 00299 if ( isset($this->delegate) and method_exists($this->delegate, 'authenticate') ){ 00300 $res = $this->delegate->authenticate(); 00301 if ( PEAR::isError($res) and $res->getCode() == DATAFACE_E_REQUEST_NOT_HANDLED ){ 00302 // we just pass the buck 00303 } else { 00304 return $res; 00305 } 00306 } 00307 00308 if ( isset($this->conf['pre_auth_types']) ){ 00309 $pauthtypes = explode(',',$this->conf['pre_auth_types']); 00310 if ( $pauthtypes ){ 00311 $oldType = $this->authType; 00312 foreach ($pauthtypes as $pauthtype){ 00313 $this->setAuthType($pauthtype); 00314 if ( isset($this->delegate) and method_exists($this->delegate, 'authenticate') ){ 00315 $res = $this->delegate->authenticate(); 00316 if ( PEAR::isError($res) and $res->getCode() == DATAFACE_E_REQUEST_NOT_HANDLED) { 00317 // pass the buck 00318 } else { 00319 return $res; 00320 } 00321 } 00322 } 00323 $this->setAuthType($oldType); 00324 } 00325 } 00326 00327 00328 } 00329 00333 function isLoggedIn(){ 00334 if ( !$this->authEnabled ) return true; 00335 if ( isset($this->delegate) and method_exists($this->delegate, 'isLoggedIn') ){ 00336 return $this->delegate->isLoggedIn(); 00337 } 00338 00339 return (isset($_SESSION['UserName']) and $_SESSION['UserName']); 00340 } 00341 00346 function showLoginPrompt($msg=''){ 00347 if ( !$this->authEnabled ) return true; 00348 if ( isset($this->delegate) and method_exists($this->delegate, 'showLoginPrompt') ){ 00349 return $this->delegate->showLoginPrompt($msg); 00350 } 00351 header("HTTP/1.1 401 Please Log In"); 00352 $app =& Dataface_Application::getInstance(); 00353 $url = $app->url('-action=login_prompt'); 00354 $app =& Dataface_Application::getInstance(); 00355 $query =& $app->getQuery(); 00356 if ( $msg ) $msgarray = array($msg); 00357 else $msgarray = array(); 00358 if ( isset($query['--msg']) ){ 00359 $msgarray[] = $query['--msg']; 00360 } 00361 $msg = trim(implode('<br>',$msgarray)); 00362 if ( $msg ) $url .= '&--msg='.urlencode($msg); 00363 if ( $query['-action'] != 'login' and $query['-action'] != 'login_prompt' ) $_SESSION['-redirect'] = (isset($_SERVER['REQUEST_URI'])?$_SERVER['REQUEST_URI']:$app->url('')); 00364 else { 00365 $referer = @$_SERVER['HTTP_REFERER']; 00366 if ( !$_SESSION['-redirect'] and $referer and strpos($referer, df_absolute_url(DATAFACE_SITE_URL)) === 0 ){ 00367 $_SESSION['-redirect'] = $referer; 00368 } 00369 } 00370 header("Location: $url"); 00371 exit; 00372 //df_display(array('msg'=>$msg, 'redirect'=>@$_REQUEST['-redirect']), 'Dataface_Login_Prompt.html'); 00373 00374 } 00375 00380 function &getLoggedInUser(){ 00381 $null = null; 00382 if ( !$this->authEnabled ) return $null; 00383 if ( isset($this->delegate) and method_exists($this->delegate, 'getLoggedInUser') ){ 00384 $user =& $this->delegate->getLoggedInUser(); 00385 return $user; 00386 } 00387 if ( !$this->isLoggedIn() ) return $null; 00388 static $user = 0; 00389 if ( $user === 0 ){ 00390 $user = df_get_record($this->usersTable, array($this->usernameColumn => '='.$_SESSION['UserName'])); 00391 if ( !$user ){ 00392 $user = new Dataface_Record($this->usersTable, array($this->usernameColumn => $_SESSION['UserName'])); 00393 } 00394 } 00395 return $user; 00396 00397 } 00398 00399 function getLoggedInUsername(){ 00400 $null = null; 00401 if ( !$this->authEnabled ) return $null; 00402 if ( isset($this->delegate) and method_exists($this->delegate, 'getLoggedInUsername') ){ 00403 return $this->delegate->getLoggedInUsername(); 00404 } 00405 00406 $user =& $this->getLoggedInUser(); 00407 if ( isset($user) ){ 00408 return $user->strval($this->usernameColumn); 00409 } 00410 00411 return $null; 00412 00413 } 00414 function _createFailedLoginsTable(){ 00415 $res = mysql_query("create table if not exists `dataface__failed_logins` ( 00416 `attempt_id` int(11) not null auto_increment primary key, 00417 `ip_address` varchar(32) not null, 00418 `username` varchar(32) not null, 00419 `time_of_attempt` int(11) not null 00420 )", df_db()); 00421 if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR); 00422 } 00423 00424 function flagFailedAttempt($credentials){ 00425 $this->_createFailedLoginsTable(); 00426 $res = mysql_query("insert into `dataface__failed_logins` (ip_address,username,time_of_attempt) values ( 00427 '".addslashes($_SERVER['REMOTE_ADDR'])."', 00428 '".addslashes($credentials['UserName'])."', 00429 '".addslashes(time())."' 00430 )", df_db()); 00431 if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR); 00432 00433 00434 } 00435 00436 function clearFailedAttempts(){ 00437 $this->_createFailedLoginsTable(); 00438 $res = mysql_query("delete from `dataface__failed_logins` where ip_address='".addslashes($_SERVER['REMOTE_ADDR'])."'", df_db()); 00439 if ( !$res ) throw new Exception(mysql_error(df_db())); 00440 } 00441 00442 function isLockedOut(){ 00443 $this->_createFailedLoginsTable(); 00444 $res = mysql_query("delete from `dataface__failed_logins` where `time_of_attempt` < ".(time()-(60*30)), df_db()); 00445 if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR); 00446 $res = mysql_query("select count(*) from `dataface__failed_logins` where `ip_address`='".addslashes($_SERVER['REMOTE_ADDR'])."'", df_db()); 00447 if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR); 00448 list($num) = mysql_fetch_row($res); 00449 @mysql_free_result($res); 00450 return ($num > 20); 00451 } 00452 00453 function getEmailColumn(){ 00454 if ( !isset($this->emailColumn) ){ 00455 import('Dataface/Ontology.php'); 00456 Dataface_Ontology::registerType('Person', 'Dataface/Ontology/Person.php', 'Dataface_Ontology_Person'); 00457 $ontology = Dataface_Ontology::newOntology('Person', $this->usersTable); 00458 if ( isset($this->conf['email_column']) ) $this->emailColumn = $this->conf['email_column']; 00459 else $this->emailColumn = $ontology->getFieldname('email'); 00460 } 00461 return $this->emailColumn; 00462 } 00463 00464 00465 } 00466