545 lines
16 KiB
PHP
545 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* Tzn Framework
|
|
*
|
|
* @package tzn_helpers
|
|
* @author Stan Ozier <framework@tirzen.com>
|
|
* @version 0.4
|
|
* @since 0.1
|
|
* @copyright GNU Lesser General Public License (LGPL) version 3
|
|
*/
|
|
|
|
/**
|
|
* AuthHelper
|
|
*
|
|
* authentication system
|
|
*/
|
|
class AuthHelper extends Helper {
|
|
|
|
protected $isLoggedIn;
|
|
protected $isLoggingOut;
|
|
|
|
protected $fc;
|
|
protected $error;
|
|
|
|
public function __construct($obj) {
|
|
parent::__construct($obj);
|
|
$this->fc = FrontController::getInstance();
|
|
$this->error = '';
|
|
$this->isLoggedIn = $this->isLoggingOut = false;
|
|
|
|
}
|
|
|
|
public function checkPassword($password) {
|
|
$pass = $this->obj->get('password');
|
|
$salt = $this->obj->get('salt');
|
|
switch (APP_AUTH_PASSWORD_MODE) {
|
|
case 1:
|
|
if ($pass == "") {
|
|
$pass = crypt("", $salt);
|
|
}
|
|
if (crypt($password, $salt) != $pass) {
|
|
// password invalid
|
|
$this->error = 'password_invalid';
|
|
$this->badAccess();
|
|
return false;
|
|
}
|
|
break;
|
|
case 2:
|
|
$sql = "ENCRYPT('$password','$salt')";
|
|
if (!self::checkDbPass($sql, $pass)) {
|
|
// password not OK
|
|
$this->error = 'password_invalid';
|
|
$this->badAccess();
|
|
return false; // error or password mismatch
|
|
}
|
|
break;
|
|
case 3:
|
|
$sql = "ENCODE('$password','$pass')";
|
|
if (!self::checkDbPass($sql, $pass)) {
|
|
// password not OK
|
|
$this->error = 'password_invalid';
|
|
$this->badAccess();
|
|
return false; // error or password mismatch
|
|
}
|
|
break;
|
|
case 4:
|
|
if (!$pass && !$password) {
|
|
break;
|
|
}
|
|
$sql = "MD5('$password')";
|
|
if (!self::checkDbPass($sql, $pass)) {
|
|
// password not OK
|
|
$this->error = 'password_invalid';
|
|
$this->badAccess();
|
|
return false; // error or password mismatch
|
|
}
|
|
break;
|
|
case 5:
|
|
if (!$pass && !$password) {
|
|
break;
|
|
}
|
|
if ($_SESSION['challenge']) {
|
|
$value = md5($pass.$_SESSION['challenge']);
|
|
unset($_SESSION['challenge']);
|
|
if ($value == $password) {
|
|
break;
|
|
}
|
|
}
|
|
$this->error = 'password_invalid';
|
|
$this->badAccess();
|
|
return false;
|
|
break;
|
|
default:
|
|
for ($i = 0; $i < strlen($pass); $i += 2) {
|
|
$passBin .= chr(hexdec(substr($s,$i,2)));
|
|
}
|
|
$iv = mcrypt_create_iv (mcrypt_get_iv_size (MCRYPT_3DES,
|
|
MCRYPT_MODE_ECB), MCRYPT_RAND);
|
|
if (mcrypt_decrypt (MCRYPT_3DES, $pass, $passBin,
|
|
MCRYPT_MODE_ECB, $iv) == $password)
|
|
{
|
|
break;
|
|
}
|
|
$this->error = 'password_invalid';
|
|
$this->badAccess();
|
|
return false;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
*
|
|
*/
|
|
public function activateAccount($byUser=false) {
|
|
// update DB
|
|
$this->obj->set('activation','');
|
|
$this->obj->set('enabled',1);
|
|
if ($this->obj->isLoaded()) {
|
|
$this->obj->fields('enabled,activation');
|
|
$this->obj->update();
|
|
}
|
|
|
|
// send Emails
|
|
/* -TODO-
|
|
include CMS_INCLUDE_PATH.'language/'.$GLOBALS['objCms']->settings->get('default_language').'/system.php';
|
|
include_once(CMS_CLASS_PATH."pkg_com.php");
|
|
|
|
$objMessage = new EmailMessage();
|
|
|
|
//email admin (if account activated by user)
|
|
if ($byUser) {
|
|
if ($objMessage->loadByKey('description','sign_up_new')) {
|
|
$bodyMessage = "\r\n\t"
|
|
.$this->obj->getName()."\r\n\r\n"
|
|
.CMS_WWW_URL.'admin/member.php?id='.$this->obj->getUid()."\r\n";
|
|
if ($objMessage->send($bodyMessage, $this->obj->email)) {
|
|
// well, ok, fine
|
|
} else {
|
|
$pErrorMessage = $GLOBALS['langSystemEmailStuff']['send_error'];
|
|
}
|
|
} else {
|
|
$pErrorMessage = $GLOBALS['langSystemEmailStuff']['send_not_found'];
|
|
}
|
|
}
|
|
|
|
// email user
|
|
if ($this->obj->email) {
|
|
if ($objMessage->loadByKey('description','sign_up_confirmation')) {
|
|
$bodyMessage = CMS_WWW_URL.'login.php?username='.$this->obj->username;
|
|
if ($_POST['password1']) {
|
|
$bodyMessage .= "\r\n\t"
|
|
.$GLOBALS['langTznUser']['login_username'].': '
|
|
.$this->obj->username."\r\n\t"
|
|
.$GLOBALS['langTznUser']['login_password'].': '
|
|
.$_POST['password1']."\r\n";
|
|
}
|
|
if ($objMessage->send($bodyMessage, $this->obj->email)) {
|
|
// well, ok, fine
|
|
} else {
|
|
$this->_error['activation'] = $GLOBALS['langSystemEmailStuff']['send_error'];
|
|
}
|
|
} else {
|
|
$this->_error['activation'] = $GLOBALS['langSystemEmailStuff']['send_not_found'];
|
|
}
|
|
} else {
|
|
$this->_error['activation'] = $GLOBALS['langSystemEmailStuff']['send_no_address'];
|
|
}
|
|
*/
|
|
|
|
return (empty($this->error));
|
|
}
|
|
/**
|
|
* login and update DB
|
|
*/
|
|
protected function _activateLogin() {
|
|
$updTz = '';
|
|
if (isset($_REQUEST['appUserTimeZone'])) {
|
|
if ($this->obj->get('time_zone') != $_REQUEST['appUserTimeZone']) {
|
|
$this->obj->set('time_zone',$_REQUEST['appUserTimeZone']);
|
|
$updTz = ',time_zone';
|
|
}
|
|
}
|
|
// register session
|
|
$_SESSION["appUserId"] = $this->obj->getUid();
|
|
$_SESSION["appUserLastLogin"] = $this->obj->get('last_login_date');
|
|
$_SESSION["appUserLastAddress"] = $this->obj->get('last_login_address');
|
|
$this->updateSessionVariables();
|
|
|
|
// update last login
|
|
$this->obj->set('last_login_date',APP_SQL_NOW);
|
|
$this->obj->set('last_login_address', $_SERVER['REMOTE_ADDR']);
|
|
$_SESSION['appUserCurrentAddress'] = $this->obj->get('last_login_address');
|
|
$this->obj->_isLoggedIn = true;
|
|
$this->obj->set('bad_access',0);
|
|
$this->obj->set('visits',$this->obj->get('visits')+1);
|
|
$this->obj->fields('last_login_date,last_login_address,bad_access,visits'.$updTz);
|
|
$this->obj->update();
|
|
}
|
|
|
|
/**
|
|
* update sessions variables (on login and when updating own profile)
|
|
*/
|
|
public function updateSessionVariables() {
|
|
$_SESSION["appUserName"] = $this->obj->get('username');
|
|
$_SESSION["appUserTimeZone"] = $this->obj->get('time_zone');
|
|
$this->obj->setupTimeZone();
|
|
}
|
|
|
|
/**
|
|
* Verify username and password
|
|
*/
|
|
public function login($username, $password, $activation=false) {
|
|
$this->error = '';
|
|
if ($username == '') {
|
|
$this->error = 'username_required';
|
|
return false;
|
|
}
|
|
if (APP_AUTH_FIELD == 'username' && (!VarUsr::sanitize($username, $error))) {
|
|
$this->error = $error;
|
|
return false;
|
|
}
|
|
$this->obj->set(APP_AUTH_FIELD,$username);
|
|
if ($this->obj->load(APP_AUTH_FIELD)) {
|
|
$activ = $this->obj->get('activation');
|
|
if (!$this->obj->get('enabled')) {
|
|
if (!$activation || $activation != $activ) {
|
|
//Account Disabled
|
|
$this->error = 'account_disabled';
|
|
} else {
|
|
$this->error = 'account_not_active';
|
|
}
|
|
}
|
|
if (!$this->checkPassword($password)) {
|
|
$this->error = 'password_invalid';
|
|
} else if ($activation && $activation == $activ) {
|
|
// activate account
|
|
$this->activateAccount(true);
|
|
}
|
|
if (!empty($this->error)) {
|
|
$this->badAccess();
|
|
return false;
|
|
}
|
|
} else {
|
|
$this->error = 'username_not_found';
|
|
return false;
|
|
}
|
|
|
|
$this->_activateLogin();
|
|
return true;
|
|
}
|
|
/**
|
|
*coming soon
|
|
*/
|
|
public function silentLogin($username, $password) {
|
|
$this->error = '';
|
|
if ($username == '') {
|
|
return false;
|
|
}
|
|
$this->obj->set(APP_AUTH_FIELD, $username);
|
|
if ($this->obj->load(APP_AUTH_FIELD)) {
|
|
if (!$this->obj->get('enabled')) {
|
|
//Account Disabled
|
|
$this->error = 'user_disabled';
|
|
}
|
|
if (!$this->checkPassword($password)) {
|
|
$this->error = 'user_password_invalid';
|
|
}
|
|
} else {
|
|
$this->error = 'user_name_not_found';
|
|
return false;
|
|
}
|
|
return (empty($this->error));
|
|
}
|
|
/**
|
|
* Is there a cookie for AutoLogin ??
|
|
*/
|
|
public function checkAutoLogin($forReal=true) {
|
|
if (empty($_COOKIE['auto_login'])) {
|
|
return false;
|
|
}
|
|
$arrVal = explode(":",$_COOKIE['auto_login']);
|
|
$id = VarUid::sanitize($arrVal[0]);
|
|
$salt = VarStr::sanitize($arrVal[1]);
|
|
if (!$id || !$salt) {
|
|
return false;
|
|
}
|
|
if ($this->obj->load($this->dbUid(true)."='".$id
|
|
."' AND ".$this->dbField('salt', $salt)." AND "
|
|
.$this->dbField('auto_login',1)." AND ".$this->dbField('enabled',1))
|
|
) {
|
|
if (!$forReal) {
|
|
return true;
|
|
}
|
|
setCookie('auto_login',$this->obj->getUid().":".$this->obj->get('salt')
|
|
,time()+(3600*24*30));
|
|
$this->activateLogin();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Activate AutoLogin
|
|
*/
|
|
public function setAutoLogin() {
|
|
if (($this->obj->getUid()) && ($this->obj->get('salt'))) {
|
|
setCookie('autoLogin',$this->obj->getUid().":".$this->obj->get('salt')
|
|
,time()+(3600*24*30));
|
|
$this->obj->set('auto_login','1');
|
|
$this->obj->fields('auto_login');
|
|
$this->obj->update();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* De-activate AutoLogin
|
|
*/
|
|
public function resetAutoLogin() {
|
|
if (($this->obj->getUid()) && ($this->obj->get('salt'))) {
|
|
setCookie('autoLogin');
|
|
if ($this->obj->get('auto_login')) {
|
|
$this->obj->set('auto_login', 0);
|
|
$this->obj->fields('auto_login');
|
|
$this->obj->update();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* Logout logs the user out (yes indeed)
|
|
* Note: This will destroy the session, and not just the session data!
|
|
*/
|
|
public function logout() {
|
|
$_SESSION = array();
|
|
// If you want to kill the session, also delete the session cookie.
|
|
// Note: This will destroy the session, and not just the session data!
|
|
if (isset($_COOKIE[session_name()])) {
|
|
setcookie(session_name(), '', time()-42000, '/');
|
|
}
|
|
// Finally, destroy the session.
|
|
@session_destroy();
|
|
// while you're at it, delete auto login
|
|
$this->resetAutoLogin();
|
|
// set internal variable
|
|
$this->isLoggedIn = false;
|
|
$this->isLoggingOut = true;
|
|
}
|
|
/**
|
|
* check if user is logged in. Do not load from DB by default
|
|
*/
|
|
public function isLoggedIn($load=false) {
|
|
|
|
// --- login previously checked ---
|
|
|
|
if (empty($_SESSION['appUserId'])) {
|
|
$_SESSION['appUserId'] = 0;
|
|
}
|
|
|
|
if ($this->isLoggedIn && !$this->isLoggingOut && $this->obj->getUid()) {
|
|
// user seems already logged in
|
|
if ($load) {
|
|
// load is requested
|
|
if ($this->obj->load() != $_SESSION['appUserId']) {
|
|
return false;
|
|
}
|
|
} else if ($this->obj->getUid() != $_SESSION['appUserId']) {
|
|
// ID in session and in object are different
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// --- first login check ---
|
|
if ($_SESSION['appUserId'] == 0 || $this->isLoggingOut) {
|
|
// invalid ID in session or currently logging out
|
|
// $this->fc->addMessage('ERROR:#security_expired');
|
|
return false;
|
|
|
|
} else {
|
|
|
|
// login seems OK : initialize properties
|
|
$this->obj->set('id',$_SESSION['appUserId']);
|
|
$this->obj->set('username', $_SESSION['appUserName']);
|
|
|
|
// time zone
|
|
$this->obj->set('time_zone', $_SESSION['appUserTimeZone']);
|
|
$this->obj->setupTimeZone();
|
|
|
|
$this->isLoggedIn = true;
|
|
|
|
// check user IP
|
|
if ($_SESSION['appUserCurrentAddress'] && $_SERVER['REMOTE_ADDR'] != $_SESSION['appUserCurrentAddress']) {
|
|
$this->fc->addMessage('ERROR:#security_ip '.$_SERVER['REMOTE_ADDR'].' / '.$_SESSION['appUserCurrentAddress']);
|
|
return false;
|
|
}
|
|
|
|
// check that User ID is same in cookie and in session
|
|
if ($load) {
|
|
if ($this->obj->load() != $_SESSION['appUserId']) {
|
|
$this->fc->addMessage('ERROR:#security_expired');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// reset last session stats with previous login info
|
|
$this->obj->set('last_login_date', $_SESSION['appUserLastLogin']);
|
|
$this->obj->set('last_login_address', $_SESSION['appUserLastAddress']);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* All in one user login and access check function
|
|
*/
|
|
public function checkLogin($canAutoLogin=true) {
|
|
|
|
if ($this->isLoggedIn(true)) {
|
|
return true;
|
|
} else {
|
|
if ($canAutoLogin && $this->checkAutoLogin()) {
|
|
// auto logged in
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* forgotten password? Try to get it back or generate new one
|
|
* type can be 'username' or 'email'
|
|
*/
|
|
public function forgotPassword($key, $value) {
|
|
if ($this->obj->get('salt') == "") {
|
|
if (!$this->obj->loadByKey($key,$value)) {
|
|
// user not found
|
|
$this->error = $key."_not_found";
|
|
return false;
|
|
}
|
|
}
|
|
switch (APP_AUTH_PASSWORD_MODE) {
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 5:
|
|
$this->generateNewSalt();
|
|
$newpass = StringHelper::genRandom(6,"123456789");
|
|
$this->obj->setRawPassword($newpass, $this->obj->get('salt'));
|
|
$this->updatePassword();
|
|
return $newpass;
|
|
break;
|
|
case 3:
|
|
$strSql = "SELECT DECODE(password, '".$this->obj->get('salt')
|
|
."') as pass FROM ".$this->_table
|
|
." WHERE ".$this->obj->dbUid()."='".$this->obj->getUid()."'";
|
|
if ($rows = DbConnnector::query($strSql)) {
|
|
if (!empty($rows[0])) {
|
|
return $rows[0]->pass;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
$iv = mcrypt_create_iv (mcrypt_get_iv_size (MCRYPT_3DES,
|
|
MCRYPT_MODE_ECB), MCRYPT_RAND);
|
|
return mcrypt_decrypt (MCRYPT_3DES, $this->obj->get('salt'),
|
|
$passBin, MCRYPT_MODE_ECB, $iv);
|
|
break;
|
|
}
|
|
$this->error = 'password_recover';
|
|
return false;
|
|
}
|
|
|
|
public function getLoginCountry() {
|
|
$myIP = escapeshellarg($_SERVER['REMOTE_ADDR']);
|
|
$pCountry = '00000'; // $_SERVER['REMOTE_ADDR'];
|
|
if (@defined('APP_GEOLOCATION_SCRIPT') && is_file(APP_GEOLOCATION_SCRIPT)) {
|
|
$arrOutput = array();
|
|
exec(APP_GEOLOCATION_SCRIPT.' '.$myIP, $arrOutput);
|
|
$strOutput = implode(' ',$arrOutput);
|
|
if (preg_match('/(located in)/i',$strOutput)) {
|
|
$strOutput = trim(substr($strOutput,strpos($strOutput,'in')+2));
|
|
$pCountry = $strOutput;
|
|
}
|
|
}
|
|
return $pCountry;
|
|
}
|
|
|
|
/**
|
|
* get error
|
|
*/
|
|
public function getAuthError($clean=true) {
|
|
if (!$this->error) {
|
|
return false;
|
|
} else {
|
|
$str = $this->error;
|
|
if ($clean) {
|
|
$this->error = '';
|
|
}
|
|
return $str;
|
|
}
|
|
}
|
|
|
|
// ---- Database manipulation ---------------------------------------------
|
|
|
|
protected function generateNewSalt() {
|
|
$this->obj->set('salt',
|
|
StringHelper::genRandom(
|
|
8,
|
|
'abcdefghijklmnopqrstuvwxyz'
|
|
.'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
|
)
|
|
);
|
|
}
|
|
|
|
public static function checkDbPass($mode, $pass) {
|
|
return (self::getDbPass($mode) == $pass);
|
|
}
|
|
|
|
public static function getDbPass($mode) {
|
|
$sql = 'SELECT '.$mode.' as passhash';
|
|
if ($rows = DbConnector::query($sql)) {
|
|
if (!empty($rows[0])) {
|
|
return $rows[0]['passhash'];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected function badAccess() {
|
|
$sql = "UPDATE ".$this->obj->dbTable()." SET"
|
|
." bad_access=bad_access+1"
|
|
." WHERE ".$this->obj->dbUid()." = '".$this->obj->getUid()."'";
|
|
DbConnector::query($sql);
|
|
}
|
|
|
|
protected function updatePassword() {
|
|
$sql = "UPDATE ".$this->obj->dbTable()." SET"
|
|
." password=".$this->obj->sql('password')
|
|
." WHERE ".$this->obj->dbUid()." = '".$this->obj->getUid()."'";
|
|
DbConnector::query($sql);
|
|
}
|
|
} |