aliroAuthenticator.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /*******************************************************************************
00004  * Aliro - the modern, accessible content management system
00005  *
00006  * Aliro is open source software, free to use, and licensed under GPL.
00007  * You can find the full licence at http://www.gnu.org/copyleft/gpl.html GNU/GPL
00008  *
00009  * The author freely draws attention to the fact that Aliro derives from Mambo,
00010  * software that is controlled by the Mambo Foundation.  However, this section
00011  * of code is totally new.  If it should contain any fragments that are similar
00012  * to Mambo, please bear in mind (1) there are only so many ways to do things
00013  * and (2) the author of Aliro is also the author and copyright owner for large
00014  * parts of Mambo 4.6.
00015  *
00016  * Tribute should be paid to all the developers who took Mambo to the stage
00017  * it had reached at the time Aliro was created.  It is a feature rich system
00018  * that contains a good deal of innovation.
00019  *
00020  * Your attention is also drawn to the fact that Aliro relies on other items of
00021  * open source software, which is very much in the spirit of open source.  Aliro
00022  * wishes to give credit to those items of code.  Please refer to
00023  * http://aliro.org/credits for details.  The credits are not included within
00024  * the Aliro package simply to avoid providing a marker that allows hackers to
00025  * identify the system.
00026  *
00027  * Copyright in this code is strictly reserved by its author, Martin Brampton.
00028  * If it seems appropriate, the copyright will be vested in the Aliro Organisation
00029  * at a suitable time.
00030  *
00031  * Copyright (c) 2007 Martin Brampton
00032  *
00033  * http://aliro.org
00034  *
00035  * counterpoint@aliro.org
00036  *
00037  * aliroLoginDetails is a simple data class used to create an object to carry the
00038  * information from a user login - user ID, password and the flag for whether the
00039  * system is to "remember" the user and automatically log them in.  The main use
00040  * for objects of this class is to pass data to mambots related to the authentication
00041  * process.
00042  *
00043  * aliroExtensionHandler knows all about the various installed extensions in
00044  * the system.  Anything not integral to the core - components, modules, mambots,
00045  * templates - are counted as extensions.  It is a cached singleton class and
00046  * uses common code the implement the object cache.
00047  *
00048  * aliroAuthenticator is the abstract class that contains common code for use
00049  * on both the user and admin sides of Aliro.
00050  *
00051  * aliroUserAuthenticator is the class that is instantiated to handle user side
00052  * authentication - basically login and logout.  On the user side, the actual
00053  * authentication is done by mambots.  The default Aliro authentication mambot
00054  * checks the credentials against the database, although it calls back to the
00055  * aliroUserAuthenticator class to perform the actual validation.  It is possible
00056  * to supplement the default processing with other mambots, or replace it
00057  * completely.  Uses for such an approach might include use of an LDAP system.
00058  * There are several mambot "hooks" and the other purpose for this is to be able
00059  * to integrate extensions that elaborate the handling of users with additional
00060  * properties and such like.
00061  *
00062  * aliroAdminAuthenticator is instantiated to handle user login and logout for
00063  * the admin side.  It is simpler, since no mambots are triggered and the
00064  * only authentication mechanism is a check against the database.
00065  *
00066  */
00067 
00068 class aliroLoginDetails {
00069     private $_user = '';
00070     private $_password = '';
00071     private $_remember = '';
00072 
00073     public function __construct ($user, $password='', $remember='') {
00074         $this->_user = $user;
00075         $this->_password = $password;
00076         $this->_remember = $remember;
00077     }
00078 
00079     public function getUser () {
00080         return $this->_user;
00081     }
00082 
00083     public function getPassword () {
00084         return $this->_password;
00085     }
00086 
00087     public function getRemember () {
00088         return $this->_remember;
00089     }
00090 
00091 }
00092 
00093 abstract class aliroAuthenticator {
00094 
00095     // Not to be called to act on anything other than the current user
00096     public function logout () {
00097         if (!empty($_SESSION["aliro_{$this->prefix}id"])) {
00098             $currentDate = date('Y-m-d/TH:i:s');
00099             $query = "UPDATE #__users SET lastvisitDate='$currentDate' WHERE id='" . $_SESSION["aliro_{$this->prefix}id"] . "'";
00100             aliroDatabase::getInstance()->doSQL($query);
00101         }
00102         aliroSessionFactory::getSession()->logout();
00103     }
00104 
00105     public function makePassword ($syllables = 3) {
00106         // Developed from code by http://www.anyexample.com
00107         // 8 vowel sounds 
00108         $vowels = array ('a', 'o', 'e', 'i', 'y', 'u', 'ou', 'oo'); 
00109         // 20 random consonants 
00110         $consonants = array ('w', 'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'qu');
00111         // Generate three syllables
00112         for ($i=0, $password=''; $i<$syllables; $i++) $password .= $this->makeSyllable($vowels, $consonants, $i);
00113         // Return with suffix added
00114         return $password.$this->makeSuffix($vowels, $consonants);
00115     }
00116 
00117     private function makeSuffix ($vowels, $consonants) {
00118         // 10 random suffixes
00119         $suffix = array ('dom', 'ity', 'ment', 'sion', 'ness', 'ence', 'er', 'ist', 'tion', 'or');
00120         $new = $suffix[array_rand($suffix)];
00121         // return suffix, but put a consonant in front if it starts with a vowel
00122         return (in_array($new[0], $vowels)) ? $consonants[array_rand($consonants)].$new : $new;
00123     }
00124 
00125     private function makeSyllable ($vowels, $consonants, $double=false) {
00126         $doubles = array('n', 'm', 't', 's');
00127         $c = $consonants[array_rand($consonants)];
00128         // One in three chance of doubling the consonant - except for first syllable
00129         if ($double AND in_array($c, $doubles) AND 1 == mt_rand(0,2)) $c .= $c;
00130         return $c.$vowels[array_rand($vowels)];
00131     }
00132     
00133     public function makeSalt () {
00134         return $this->makeRandomString(24);
00135     }
00136     
00137     private function makeRandomString ($length=8) {
00138         $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!%,-:;@_{}~";
00139         for ($i = 0, $makepass = '', $len = strlen($chars); $i < $length; $i++) $makepass .= $chars[mt_rand(0, $len-1)];
00140         return $makepass;
00141     }
00142 
00143 }
00144 
00145 class aliroUserAuthenticator extends aliroAuthenticator {
00146     private static $instance = __CLASS__;
00147     protected $prefix = 'user';
00148 
00149     public static function getInstance () {
00150         return is_object(self::$instance) ? self::$instance : (self::$instance = new self::$instance());
00151     }
00152 
00153     public function userLogin () {
00154         $request = aliroRequest::getInstance();
00155         $username = $request->getParam($_POST, 'username');
00156         $passwd = $request->getParam($_POST, 'passwd');
00157         $remember = $request->getParam($_REQUEST, 'remember');
00158         if (!$username OR !$passwd) {
00159             $message = T_('Please complete the username and password fields.');
00160             $request->redirectSame($message, _ALIRO_ERROR_WARN);
00161             exit;
00162         }
00163         $message = $this->systemLogin ($username, $passwd, $remember);
00164         if ($message) $request->redirectSame ($message, _ALIRO_ERROR_WARN);
00165         if ($return = $request->getParam($_REQUEST, 'return')) $request->redirect($return);
00166         elseif (isset($_SESSION['aliro_redirect_here'])) $request->redirect ($_SESSION['aliro_redirect_here']);
00167         else $request->redirect();
00168     }
00169 
00170     function systemLogin ($username=null, $passwd=null, $remember=null) {
00171         $session = aliroSessionFactory::getSession();
00172         if (!$session->cookiesAccepted()) return T_('Your browser is not accepting cookies - login is not possible.');
00173         $my = null;
00174         $mambothandler = aliroMambotHandler::getInstance();
00175         $database = aliroDatabase::getInstance();
00176         $username = $database->getEscaped($username);
00177         $escpasswd = $database->getEscaped($passwd);
00178         $remember = $remember ? true : false;
00179         $loginfo = new aliroLoginDetails($username, $escpasswd, $remember);
00180         $checkuser = true;
00181         $logresults = $mambothandler->trigger('requiredLogin',array($loginfo));
00182         $message = '';
00183         if (count($logresults) == 0) $logresults[] = T_('Logins are not permitted.  There is no authentication check active.');
00184         foreach ($logresults as $result) {
00185             if (($result instanceof mosUser) AND $result->id) {
00186                 if (!isset($my)) $my = $result;
00187             }
00188             elseif ($result) {
00189                 $message = $result;
00190                 $checkuser = false;
00191                 break;
00192             }
00193         }
00194         if ($checkuser AND isset($my)) {
00195             $session->setNewUserData($my);
00196             $mambothandler->trigger('goodLogin', array($loginfo));
00197             $currentDate = date("Y-m-d/TH:i:s");
00198             $query = "UPDATE #__users SET lastvisitDate='$currentDate', block=0 where id='$my->id'";
00199             if ($remember) {
00200                 $lifetime = time() + 365*24*60*60;
00201                 setcookie("usercookie[username]", $username, $lifetime, "/");
00202                 setcookie("usercookie[password]", $passwd, $lifetime, "/");
00203             }
00204         }
00205         else {
00206             $my = null;
00207             $query = "UPDATE #__users SET block=block+1 where username='$username'";
00208             if ($remember) {
00209                 $lifetime = time() - 365*24*60*60;
00210                 setcookie("usercookie[username]", $username, $lifetime, "/");
00211                 setcookie("usercookie[password]", $passwd, $lifetime, "/");
00212             }
00213         }
00214         $database->doSQL($query);
00215         if (is_null($my)) {
00216             $mambothandler->trigger('badLogin', array($loginfo));
00217             sleep(2);
00218         }
00219         return $message;
00220     }
00221 
00222     public function logout () {
00223         $mambothandler = aliroMambotHandler::getInstance();
00224         $loginfo = new aliroLoginDetails($_SESSION['aliro_username']);
00225         $mambothandler->trigger('beforeLogout', array($loginfo));
00226         parent::logout();
00227     }
00228 
00229     function authenticate (&$message, &$my, $username, $passwd, $remember=null) {
00230         $message = '';
00231         $database = aliroDatabase::getInstance();
00232         $my = new mosUser();
00233         $database->setQuery( "SELECT id, gid, block, name, username, email, sendEmail, usertype FROM #__users WHERE username='$username'");
00234         if ($database->loadObject($my)) {
00235             if ($my->block > 10) {
00236                 $message = T_('Your login has been blocked. Please contact the administrator.');
00237                 return false;
00238             }
00239             $database = aliroCoreDatabase::getInstance();
00240             $database->setQuery("SELECT COUNT(*) FROM #__core_users WHERE id=$my->id  AND password=MD5(CONCAT(salt,'$passwd'))");
00241             if ($database->loadResult()) {
00242                 unset($my->block);
00243                 return true;
00244             }
00245         }
00246         $message = T_('Incorrect username or password. Please try again.');
00247         return false;
00248     }
00249 
00250 }
00251 
00252 class aliroAdminAuthenticator extends aliroAuthenticator {
00253     private static $instance = __CLASS__;
00254     protected $prefix = 'admin';
00255 
00256     public static function getInstance () {
00257         return is_object(self::$instance) ? self::$instance : (self::$instance = new self::$instance());
00258     }
00259 
00260     function login () {
00261         $session = aliroSessionFactory::getSession();
00262         if (!($session->cookiesAccepted())) return null;
00263         
00264         $database = aliroDatabase::getInstance();
00266         $request = aliroRequest::getInstance();
00267 
00268         $usrname = $database->getEscaped($request->getParam($_POST, 'usrname'));
00269         $pass = $database->getEscaped($request->getParam($_POST, 'pass'));
00270 
00271         $my = null;
00272         if (!$pass) {
00273             $request->setErrorMessage(T_('Please enter a password'), _ALIRO_ERROR_WARN);
00274             return $my;
00275         }
00276 
00277         $users = $database->doSQLget("SELECT * FROM #__users WHERE usertype IN ('Administrator', 'Super Administrator') OR (username='$usrname' AND block<=10)");
00278         $admins = count($users);
00279         $database = aliroCoreDatabase::getInstance();
00280         foreach ($users as $key=>$oneuser) {
00281             if ($oneuser->username == $usrname) {
00282                 $database->setQuery("SELECT COUNT(*) FROM #__core_users WHERE id=$oneuser->id  AND password=MD5(CONCAT(salt,'$pass'))");
00283                 if ($database->loadResult()) {
00284                     $my =& $users[$key];
00285                     if (!in_array($my->usertype, array('Administrator', 'Super Administrator'))) $admins--;
00286                 }
00287             }
00288         }
00289         if ($admins == 0) {
00290             $request->setErrorMessage(T_('You cannot login. There are no administrators set up.'), _ALIRO_ERROR_FATAL);
00291             return null;
00292         }
00293         if (isset($my)) {
00294             $session->setNewUserData ($my);
00295             $currentDate = date("Y-m-d/TH:i:s");
00296             $query = "UPDATE #__users SET lastvisitDate='$currentDate', block=0 where id='$my->id'";
00297         }
00298         else {
00299             $request->setErrorMessage(T_('Incorrect Username, Password, or Access Level.  Please try again'), _ALIRO_ERROR_WARN);
00300             $query = "UPDATE #__users SET block=block+1 where username='$usrname'";
00301             sleep(2);
00302         }
00303         $database->doSQL("OPTIMIZE TABLE #__error_log, #__session, #__session_data");
00304         $database = aliroDatabase::getInstance();
00305         $database->doSQL($query);
00306         return $my;
00307     }
00308 
00309     function logout () {
00310         parent::logout();
00311         $request = aliroRequest::getInstance();
00312         $request->redirect($request->getCfg('live_site'));
00313     }
00314 
00315 }

Generated on Thu Apr 17 13:03:26 2008 for ALIRO by  doxygen 1.5.5