othAuth component v0.5.4.5
the component part of othAuth
changes:
0.5.4.5:
- Fixed a bug that was introduced by lately, missing /
- Fixed a bug ( not really bug but oh well ) preventing othAuth from recovering a session from the cookie data in some situations
0.5.4:
- Fixed a bug in loginAttempts reported by PatDaMilla
- Added support for parameters sent via url in a traditional way, mainly for redirects, thanks to Ritesh.
- Probably some other minor bugs
0.5.3:
- Added compatibility with 1.2 redirections
0.5.2:
- Fixed a bug in getData
- Fixed a bug related to the '/' route
- Added lazy model loading support
- Hmm..maybe something else..eh
0.5.1:
added a minor modification to _passAuthData
changes:
0.5.4.5:
- Fixed a bug that was introduced by lately, missing /
- Fixed a bug ( not really bug but oh well ) preventing othAuth from recovering a session from the cookie data in some situations
0.5.4:
- Fixed a bug in loginAttempts reported by PatDaMilla
- Added support for parameters sent via url in a traditional way, mainly for redirects, thanks to Ritesh.
- Probably some other minor bugs
0.5.3:
- Added compatibility with 1.2 redirections
0.5.2:
- Fixed a bug in getData
- Fixed a bug related to the '/' route
- Added lazy model loading support
- Hmm..maybe something else..eh
0.5.1:
added a minor modification to _passAuthData
Component Class:
Download code
<?php
/*
* othAuth an auth system for cakePHP
* comments, bug reports are welcome crazylegs AT gmail DOT com
* @author Othman Ouahbi aka CraZyLeGs
* @website: http://www.devmoz.com/blog/
* @version 0.5.4.5
* @license MIT
* todo Router::url() in cakeAdmin and probably somewhere else
*/
class othAuthComponent extends Object
{
/**
* Constants to modify the behaviour of othAuth Component
*/
// Form vars
var $user_login_var = 'username';
var $user_passw_var = 'passwd';
var $user_group_var = 'group_id';
var $user_cookie_var = 'cookie';
// DB vars
var $user_table = 'users';
var $user_table_login = 'username';
var $user_table_passw = 'passwd';
var $user_table_gid = 'group_id';
var $user_table_active = 'active';
var $user_table_last_visit = 'last_visit';
var $auth_url_redirect_var = 'from';
var $show_auth_url_redirect_var = true; // decorate the url or not
var $user_model = 'User';
var $group_model = 'Group';
var $permission_model = 'Permission';
var $history_active = false;
var $history_model = 'UserHistory';
/*
* Internals you don't normally need to edit those
*/
var $components = array('Session','RequestHandler');
var $controller = true;
var $gid = 1;
var $redirect_page;
var $hashkey = "mYpERsOnALhaSHkeY";
var $auto_redirect = true;
var $login_page = '/users/login';
var $logout_page = '';
var $access_page = '/users/access_page';
var $noaccess_page = "/users/login"; // session_flash, flash, back or a page url
var $mode = 'oth';
var $pass_crypt_method = 'md5'; // md5, sha1, crypt, crc32,callback
var $pass_crypt_callback = null; // function name
var $pass_crypt_callback_file = ''; // file where the function is declared ( in vendors )
var $cookie_active = true;
var $cookie_lifetime = '+1 day';
// asc : the most important group is the group with smallest value
// desc: the most important group is the group with greatest value
var $gid_order = 'asc'; // asc desc
var $strict_gid_check = true;
var $kill_old_login = true; // when true, form can have another login with the same hash and del the old
var $allowedAssocUserModels = array();
var $allowedAssocGroupModels = array();
var $allowedAssocPermissionModels = array();
var $allowedLoginChars = array('@','.','_');
var $error_number = 0;
var $login_limit = false; // flag to toggle login attempts feature
var $login_attempts_model = 'LoginAttempts';
var $login_attempts_num = 3;
var $login_attempts_timeout = 2; // in minutes
var $login_locked_out = '+1 day';
// startup() is kindof useless here because we init the component in beforeFilter,
// and startup is called after that and before the action.
// $this->othAuth->controller = &$this;
function startup(&$controller)
{
//$this->controller = &$controller;
}
function _getGidOp()
{
if($this->strict_gid_check)
{
return '';
}else
{
return ($this->gid_order == 'desc')? '>=' : '<=';
}
}
function _getHashOf($str)
{
switch($this->pass_crypt_method)
{
case 'sha1':
return ($str == '')? '' : sha1($str);
break;
case 'crypt':
return crypt($str);
break;
case 'callback':
vendor($this->pass_crypt_callback_file);
if(function_exists($this->pass_crypt_callback))
{
return call_user_func($this->pass_crypt_callback,$str);
}
return false;
break;
case 'md5':
default:
return md5($str);
break;
}
}
function init($auth_config = null)
{
if(is_array($auth_config) && !is_null($auth_config) && !empty($auth_config))
{
if(isset($auth_config['login_page']))
{
$this->login_page = $auth_config['login_page'];
}
if(isset($auth_config['logout_page']))
{
$this->logout_page = $auth_config['logout_page'];
}
if(isset($auth_config['access_page']))
{
$this->access_page = $auth_config['access_page'];
}
if(isset($auth_config['noaccess_page']))
{
$this->noaccess_page = $auth_config['noaccess_page'];
}else
{
$this->noaccess_page = $this->login_page;
}
if(isset($auth_config['auto_redirect']))
{
$this->auto_redirect = (boolean) $auth_config['auto_redirect'];
}
if(isset($auth_config['hashkey']))
{
$this->hashkey = $auth_config['hashkey'];
}
if(isset($auth_config['strict_gid_check']))
{
$this->strict_gid_check = (boolean) $auth_config['strict_gid_check'];
}
if(isset($auth_config['mode']))
{
$this->mode = $auth_config['mode'];
}
if(isset($auth_config['allowModels']) &&
is_array($auth_config['allowModels']))
{
if(isset($auth_config['allowModels']['user']) &&
is_array($auth_config['allowModels']['user']))
{
$this->allowedAssocUserModels = $auth_config['allowModels']['user'];
}
if(isset($auth_config['allowModels']['group']) &&
is_array($auth_config['allowModels']['group']))
{
$this->allowedAssocGroupModels = $auth_config['allowModels']['group'];
}
if(isset($auth_config['allowModels']['permission']) &&
is_array($auth_config['allowModels']['permission']))
{
$this->allowedAssocPermissionModels = $auth_config['allowModels']['permission'];
}
}
}
// pass auth data to the view so it can be used by the helper
$this->_passAuthData();
}
function login($ap = 1,$order ='asc') // username,password,group
{
if(!$this->_checkLoginAttempts())
{
return -3; // too many login attempts
}
$params = null;
if(!empty($this->controller->data[$this->user_model]))
{
$params[$this->user_model] = $this->controller->data[$this->user_model];
}
return $this->_login($params);
}
function _login($params,$ignore_cookie = false)
{
switch ($this->mode)
{
case 'oth':
return $this->othLogin($params,$ignore_cookie);
break;
case 'nao':
return $this->naoLogin($params,$ignore_cookie);
break;
case 'acl':
return $this->aclLogin($params,$ignore_cookie);
break;
default:
return $this->othLogin($params,$ignore_cookie);
break;
}
}
function othLogin($params,$ignore_cookie=false) // username,password,group
{
$params = $params[$this->user_model];
if($this->Session->valid() && $this->Session->check('othAuth.'.$this->hashkey))
{
if(!$this->kill_old_login)
{
return 1;
}
}
if(($params == null) ||
!isset($params[$this->user_login_var]) ||
!isset($params[$this->user_passw_var]))
{
return 0;
}
uses('sanitize');
$login = Sanitize::paranoid($params[$this->user_login_var],$this->allowedLoginChars);
$passw = Sanitize::paranoid($params[$this->user_passw_var]);
if($login == "" || $passw == "")
{
return -1;
}
if(!$ignore_cookie)
{
$passw = $this->_getHashOf($passw);
}
$gid_check_op = $this->_getGidOp();//($this->strict_gid_check)?'':'<=';
$conditions = array();
if(isset($params[$this->user_group_var]))
{
$this->gid = (int) Sanitize::paranoid($params[$this->user_group_var]);
// FIX
if( $this->gid < 1)
{
$this->gid = 1;
}
$conditions[$this->user_model.'.'.$this->user_table_gid] = $gid_check_op.$this->gid;
}
$conditions[$this->user_model.'.'.$this->user_table_login] = $login;
$conditions[$this->user_model.'.'.$this->user_table_passw] = $passw;
$conditions[$this->user_model.'.'.$this->user_table_active] = 1;
$UserModel = & $this->_createModel();
$row = $UserModel->find($conditions);
if( empty($row) /* || $num_users != 1 */ )
{
$this->_saveLoginAttempts();
return -2;
}
else
{
$this->_deleteLoginAttempts();
if(!$ignore_cookie &&
!empty($params[$this->user_cookie_var]) )
{
$this->_saveCookie($row);
}
$this->_saveSession($row);
// Update the last visit date to now
if(isset($this->user_table_last_visit))
{
$row[$this->user_model][$this->user_table_last_visit] = date('Y-m-d H:i:s');
$res = $UserModel->save($row,true,array($this->user_table_last_visit));
}
// 0.2.5 save history
if($this->history_active)
{
$this->_addHistory($row);
}
if($this->auto_redirect == true)
{
if(!empty($row[$this->group_model]['redirect']))
{
$goto = $row[$this->group_model]['redirect'];
}
else
{
$goto = $this->access_page;
}
$back = false;//isset($this->controller->params['url']['url'][$this->auth_url_redirect_var]);
$this->redirect($goto,$back);
}
return 1;
}
}
function naoLogin($params,$ignore_cookie = false) // username,password,group
{
$params = $params[$this->user_model];
if($this->Session->valid() && $this->Session->check('othAuth.'.$this->hashkey))
{
if(!$this->kill_old_login)
{
return 1;
}
}
if($params == null ||
!isset($params[$this->user_login_var]) ||
!isset($params[$this->user_passw_var]))
{
return 0;
}
uses('sanitize');
$login = Sanitize::paranoid($params[$this->user_login_var],$this->allowedLoginChars);
$passw = Sanitize::paranoid($params[$this->user_passw_var]);
if(isset($params[$this->user_group_var]))
{
$this->gid = (int) Sanitize::paranoid($params[$this->user_group_var]);
if( $this->gid < 1)
{
$this->gid = 1;
}
}
if($login == "" || $passw == "")
{
return -1;
}
if(!$ignore_cookie)
{
$passw = $this->_getHashOf($passw);
}
$conditions = array(
"{$this->user_model}.".$this->user_table_login => "$login",
"{$this->user_model}.".$this->user_table_passw => "$passw",
"{$this->user_model}.".$this->user_table_active => 1);
$UserModel =& new $this->user_model;
$UserModel->unbindAll(array('belongsTo'=>array($this->group_model)));
$UserModel->recursive = 2;
$UserModel->{$this->group_model}->unbindAll(array('hasAndBelongsToMany'=>array($this->permission_model)));
$row = $UserModel->find($conditions);
$num_users = (int) $UserModel->findCount($conditions);
$gids = array();
if(!empty($row[$this->group_model])){
foreach ($row[$this->group_model] as $group){
$gids[] = $group['level'];
}
}
if($this->strict_gid_check)
{
$allowed = in_array($this->gid,$gids);
}
else
{
$allowed = false;
switch($this->gid_order)
{
case 'asc':
foreach($gids as $gid)
{
if($this->gid >= $gid)
{
$allowed = true;
break;
}
}
break;
case 'desc':
foreach($gids as $gid)
{
if($this->gid >= $gid)
{
$allowed = true;
break;
}
}
break;
}
}
if( empty($row) || $num_users != 1 || !$allowed)
{
$this->_saveLoginAttempts();
return -2;
}
else
{
$this->_deleteLoginAttempts();
if(!$ignore_cookie &&
!empty($params[$this->user_cookie_var]) )
{
$this->_saveCookie($row);
}
$this->_saveSession($row);
// Update the last visit date to now
if(isset($this->user_table_last_visit))
{
$row[$this->user_model][$this->user_table_last_visit] = date('Y-m-d H:i:s');
$res = $UserModel->save($row,true,array($this->user_table_last_visit));
}
// 0.2.5 save history
if($this->history_active)
{
$this->_addHistory($row);
}
$redirect_page = $this->access_page;
foreach($row[$this->group_model] as $grp)
{
if($grp['level'] == $this->gid)
{
if(!empty($grp['redirect']))
{
$redirect_page = $grp['redirect'];
}
}
}
$this->redirect($redirect_page);
return 1;
}
}
// 0.2.5
function _addHistory(&$row)
{
$data[$this->history_model]['username'] = $row[$this->user_model][$this->user_table_login];
$data[$this->history_model]['fullname'] = $row[$this->user_model]['fullname'];
$data[$this->history_model]['groupname'] = $row[$this->group_model]['name'];
if(isset($row[$this->user_model][$this->user_table_last_visit]))
{
$data[$this->history_model]['visitdate'] = $row[$this->user_model][$this->user_table_last_visit];
}else
{
$data[$this->history_model]['visitdate'] = date('Y-m-d H:i:s');
}
loadModel($this->history_model);
$HistoryModel =& new $this->history_model;
$HistoryModel->save($data);
}
function _saveSession($row)
{
$login = $row[$this->user_model][$this->user_table_login];
$passw = $row[$this->user_model][$this->user_table_passw];
$gid = $row[$this->user_model][$this->user_table_gid];
$hk = $this->_getHashOf($this->hashkey.$login.$passw/*.$gid*/);
$row["{$this->user_model}"]['login_hash'] = $hk;
$row["{$this->user_model}"]['hashkey'] = $this->hashkey;
$this->Session->write('othAuth.'.$this->hashkey,$row);
}
// null, true to delete the cookie
function _saveCookie($row,$del = false)
{
if($this->cookie_active)
{
if(!$del)
{
$login = $row[$this->user_model][$this->user_table_login];
$passw = $row[$this->user_model][$this->user_table_passw];
$time = strtotime($this->cookie_lifetime);
$data = $login.'|'.$passw;
$data = serialize($data);
$data = $this->encrypt($data);
setcookie('othAuth',$data,$time,'/');
}else
{
setcookie('othAuth','',strtotime('-999 day'),'/');
}
}
}
function _readCookie()
{
// does session exists
if($this->Session->valid() && $this->Session->check('othAuth.'.$this->hashkey))
{
return;
}
if($this->cookie_active && isset($_COOKIE['othAuth'])) {
$str = $_COOKIE['othAuth'];
if (get_magic_quotes_gpc())
{
$str=stripslashes($str);
}
$str = $this->decrypt($str);
$str = @unserialize($str);
list($login,$passw) = explode('|',$str);
//die($passw);
$data[$this->user_model][$this->user_login_var] = $login;
$data[$this->user_model][$this->user_passw_var] = $passw;
$redirect_old = $this->auto_redirect;
$this->auto_redirect = false;
$ret = $this->_login($data,true);
$this->auto_redirect = $redirect_old;
}
}
// delete attempts after a successful login
function _deleteLoginAttempts()
{
if($this->login_limit)
{
$ip = env('REMOTE_ADDR');
loadModel($this->login_attempts_model);
$Model = & new $this->login_attempts_model;
$Model->del($ip);
if($this->cookie_active)
{
setcookie('othAuth.login_attempts','',time() - 31536000,'/');
}
}