true, Cerberus::OPTION_RENEW_TOKEN=>true)); //logging In / Out if($sAction=='logout') { $oCerberus->logMeOut(); } else/*if(($sLogin=='' && $sPass=='') || $oCerberus->checkPostToken($sPostToken))*/ { $oCerberus->logMeIn($sLogin, $sPass); } /*else { echo 'pouet'; }*/ $sLayout = $sMenu = ''; if($oCerberus->isLogguedIn()) { $sMenu = '
Log out
'; $sLayout = 'Loggued In. '.$oCerberus->getNewPostToken(); } else { $sLayout = '
Login  pass 
'; } $sErrors = $oCerberus->getCleanMessages(); echo 'Cerberus'.$sMenu."\n".$sLayout.'
'.$sErrors.''; pre('new session post token : '.$_SESSION[Cerberus::SESSION_POST_TOKEN]); /* Class */ /* Requirements */ require_once 'functions.php'; require_once 'php_object.php'; require_once 'mysql_manager.php'; /** * Cerberus * Access control class * @author FranzZ * * Requirements: * Database with DB_TABLE_USER table and fields: * - DB_FIELD_ID_USER * - DB_FIELD_LOGIN * - DB_FIELD_PASS * - DB_FIELD_TOKEN * * Setup: * - Replace required tables and fields names with the mysql manager constants * - Set options : * - Cerberus::OPTION_AUTO_LOGON * - Cerberus::OPTION_RENEW_TOKEN */ class Cerberus extends PhpObject { // Database private $oMySql; const DB_TABLE_USER = MySqlManager::USER_TABLE; const DB_FIELD_ID_USER = 'id_user'; const DB_FIELD_LOGIN = 'user'; const DB_FIELD_PASS = 'pass'; const DB_FIELD_TOKEN = 'token'; //Session const SESSION_ID_USER = self::DB_FIELD_ID_USER; const SESSION_LOGIN = self::DB_FIELD_LOGIN; const SESSION_TOKEN = self::DB_FIELD_TOKEN; const SESSION_POST_TOKEN = 'post_token'; //Cookie const COOKIE_ID_USER = self::DB_FIELD_ID_USER; const COOKIE_TOKEN = self::DB_FIELD_TOKEN; const COOKIE_POST_TOKEN = self::SESSION_POST_TOKEN; //Options const OPTION_AUTO_LOGON = 'auto_logon'; const OPTION_RENEW_TOKEN = 'renew_token'; public $abOptions; //Session Variables private $iUserId; private $sLogin; private $sToken; private $sPostToken; public function __construct(&$oMySql, $abOptions) { parent::__construct(); $this->iUserId = $this->sLogin = $this->sToken = $this->sPostToken = false; $this->oMySql = $oMySql; $this->setOptions($abOptions); $this->syncSession(); } private function setOptions($abOptions) { //default values $this->abOptions = array(self::OPTION_AUTO_LOGON=>false, self::OPTION_RENEW_TOKEN=>true); $this->abOptions = array_merge($this->abOptions, $abOptions); } private function getOption($sOptionName) { return $this->abOptions[$sOptionName]; } public function getUserId() { return $this->iUserId; } private function syncSession() { if(isset($_SESSION[self::SESSION_ID_USER])) { $this->iUserId = $_SESSION[self::SESSION_ID_USER]; } if(isset($_SESSION[self::SESSION_LOGIN])) { $this->sLogin = $_SESSION[self::SESSION_LOGIN]; } if(isset($_SESSION[self::SESSION_TOKEN])) { $this->sToken = $_SESSION[self::SESSION_TOKEN]; } if(isset($_SESSION[self::SESSION_POST_TOKEN])) { $this->sPostToken = $_SESSION[self::SESSION_POST_TOKEN]; } } public function register($asData) { //data to register //TODO To be customized $sLogin = strtolower(trim($asData[self::DB_FIELD_LOGIN])); $sPass = $asData[self::DB_FIELD_PASS]; if($sLogin=='' || $sPass=='') { $this->addError('Empty mandatory fields (Nickname or password)'); } elseif(htmlspecialchars($sLogin, ENT_QUOTES)!=$sLogin) { $this->addError('Nickname: HTML characters are forbidden'); } elseif($this->checkAccount($sLogin)) { $this->addError('Nickname: There is already a user called by that name, choose a different one'); } else { $asData[self::DB_FIELD_LOGIN] = $sLogin; $asData[self::DB_FIELD_PASS] = self::encryptPassword($sPass); $this->oMySql->insertRow(self::DB_TABLE_USER, $asData); return $this->logMeIn($sLogin, $sPass); } return false; } public function logMeIn($sLogin='', $sPass='') { $bResult = false; $bFirstLogin = true; if($sLogin=='' || $sPass=='') { $bFirstLogin = false; if($this->iUserId && $this->sLogin && $this->sToken && $this->checkToken()) { //log in with session variables $iUserId = $this->iUserId; $sLogin = $this->sLogin; $sToken = $this->sToken; $bResult = true; } elseif($this->getOption(self::OPTION_AUTO_LOGON) && $this->checkToken(true)) { //log in with cookies $iUserId = $_COOKIE[self::COOKIE_ID_USER]; $sLogin = $this->oMySql->selectValue(self::DB_TABLE_USER, self::DB_FIELD_LOGIN, $iUserId); $sToken = $_COOKIE[self::COOKIE_TOKEN]; $bResult = true; } else { $this->addWarning('No login info (cookie / session)'); } } else { $asUser = $this->getUser($sLogin); if(!$asUser) { $this->addError('Unknown user'); } elseif(!$this->checkPassword($sPass, $asUser[self::DB_FIELD_PASS])) { $this->addError('Incorrect password'); } else { $iUserId = $asUser[self::DB_FIELD_ID_USER]; $sToken = $asUser[self::DB_FIELD_TOKEN]; $bResult = true; } } if($bResult) { //Class $this->iUserId = $iUserId; $this->sLogin = $sLogin; $this->sToken = $sToken; //Session $_SESSION[self::SESSION_ID_USER] = $iUserId; $_SESSION[self::SESSION_LOGIN] = $sLogin; $_SESSION[self::SESSION_TOKEN] = $sToken; //Cookie (doesn't leave any password nor login on user's computer) self::setCookie(self::COOKIE_ID_USER, $iUserId); self::setCookie(self::COOKIE_TOKEN, $sToken); //reset pass if($bFirstLogin || $this->getOption(self::OPTION_RENEW_TOKEN)) { $this->resetToken(); } } else { $this->logMeOut(); } return $bResult; } public function isLogguedIn() { $bLogguedIn = false; if($this->iUserId && $this->sLogin && $this->sToken) { //check if token is set and valid if($this->checkToken()) { //Check if user got a actual account in the database $bLogguedIn = $this->checkAccount($this->sLogin, $this->iUserId); } else { $this->addError('Authentication problem, please sign in again'); } } /* echo "[TEST]
check token :
db token ", $this->iUserId." - ".$this->getDbToken($this->iUserId),"
session token ", $_SESSION[self::SESSION_TOKEN], "
class token ", $this->sToken, "
cookie token ", $_COOKIE[self::COOKIE_TOKEN], '
[/TEST]'; */ return $bLogguedIn; } public function logMeOut() { //Database if($this->iUserId) { $this->oMySql->updateRow(self::DB_TABLE_USER, $this->iUserId, array(self::DB_FIELD_TOKEN=>'')); } //Class variables $this->iUserId = $this->sLogin = $this->sToken = $this->sPostToken = false; //Cookie self::setCookie(self::COOKIE_TOKEN, '', -1); self::setCookie(self::COOKIE_ID_USER, '', -1); //Server session $_SESSION = array(); return session_destroy(); } private function checkAccount($sUserName, $iUserId=0) { $asConstraints = array(self::DB_FIELD_LOGIN=>$sUserName); if($iUserId>0) { $asConstraints[self::DB_FIELD_ID_USER] = $iUserId; } return $this->oMySql->selectValue(self::DB_TABLE_USER, 'COUNT(1)', $asConstraints); } private function getUser($oUser) { $sField = is_numeric($oUser)?self::DB_FIELD_ID_USER:self::DB_FIELD_LOGIN; return $this->oMySql->selectRow(self::DB_TABLE_USER, array($sField=>$oUser)); } public static function encryptPassword($sPass) { $sRandomText = 'F_RA-1H"2{bvj)5f?0sd3r#fP,K]U|w}hGiN@(sZ.sDe!7*x/:Mq+&'; for($iIndex=0; $iIndex < strlen($sPass); $iIndex++) { $sPass[$iIndex] = $sRandomText[$iIndex%strlen($sRandomText)] ^ $sPass[$iIndex]; } return md5($sPass); } private static function createToken() { return self::encryptPassword( $_SERVER['HTTP_USER_AGENT']. $_SERVER['REMOTE_ADDR']. $_SERVER['REQUEST_TIME']. strstr(microtime(), ' ', true). $_SERVER['SERVER_SIGNATURE']. $_SERVER['SERVER_ADMIN']); } private function resetToken() { //new token $sToken = $this->createToken(); //set database token $this->oMySql->updateRow(self::DB_TABLE_USER, $this->iUserId, array(self::DB_FIELD_TOKEN=>$sToken)); //set session token $_SESSION[self::SESSION_TOKEN] = $sToken; $this->sToken = $sToken; //set cookie token self::setCookie(self::COOKIE_TOKEN, $sToken); } public static function setCookie($sCookieName, $oCookieValue, $iTime=1) { setcookie($sCookieName, $oCookieValue, time()+60*60*24*$iTime); $_COOKIE[$sCookieName] = $oCookieValue; } private function checkToken($bCookieCheck=false) { $bTokenOk = $iUserId = $sToken = false; //Cookie check if($bCookieCheck && array_key_exists(self::COOKIE_ID_USER, $_COOKIE) && array_key_exists(self::COOKIE_TOKEN, $_COOKIE)) { $iUserId = $_COOKIE[self::COOKIE_ID_USER]; $sToken = $_COOKIE[self::COOKIE_TOKEN]; } //Session check elseif(!$bCookieCheck && $this->iUserId && $this->sToken !== false) { $iUserId = $this->iUserId; $sToken = $this->sToken; } if($iUserId && $sToken) { $sDbPass = $this->getDbToken($bCookieCheck?$_COOKIE[self::COOKIE_ID_USER]:$this->iUserId); $bTokenOk = ($sDbPass == $_COOKIE[self::COOKIE_TOKEN] && ($sDbPass == $this->sToken || $bCookieCheck)); } return $bTokenOk; } private function getDbToken($iUserId) { $sPass = false; if($iUserId !== false) { $sPass = $this->oMySql->selectValue(self::DB_TABLE_USER, self::DB_FIELD_TOKEN, $iUserId); } return $sPass; } public function getNewPostToken() { $sToken = self::createToken(); $this->sPostToken = $sToken; $_SESSION[self::SESSION_POST_TOKEN] = $sToken; return $sToken; } public function checkPostToken($sPostToken) { pre(array('Posted'=>$sPostToken, 'Class'=>$this->sPostToken, 'Session'=>$_SESSION[self::SESSION_POST_TOKEN]), 'check posted token'); $bPostTokenOk = ($this->sPostToken && $sPostToken!='' && $sPostToken == $this->sPostToken); $this->sPostToken = ''; $_SESSION[self::SESSION_POST_TOKEN] = ''; return $bPostTokenOk; } private static function checkPassword($sClearPass, $sEncodedPass) { return self::encryptPassword($sClearPass) == $sEncodedPass; } public function getCleanMessages($sType=parent::ALL_TAB) { return $this->getCleanMessageStacks(array($this->oMySql), $sType); } } ?>