Xataface 2.0
Xataface Application Framework
Dataface/AuthenticationTool.php
Go to the documentation of this file.
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 
 All Data Structures Namespaces Files Functions Variables Enumerations