controller = &$controller; //pr($controller); } function init($auth_config = null) { if(is_array($auth_config) && !is_null($auth_config) && !empty($auth_config)) { $this->login_page = isset($auth_config['login_page']) ? $auth_config['login_page'] : 'users/login'; $this->logout_page = isset($auth_config['logout_page'])? $auth_config['logout_page'] : 'users/logout'; $this->access_page = isset($auth_config['access_page'])? $auth_config['access_page'] : $this->login_page; $this->auto_redirect = isset($auth_config['auto_redirect']) ? (boolean)$auth_config['auto_redirect'] : true; $this->hashkey = isset($auth_config['hashkey'])? (string) $auth_config['hashkey'] : 'mYpERsOnALhaSHkeY'; $this->maintenance_mode = isset($auth_config['maintenance_mode'])? (int) $auth_config['maintenance_mode']: 0; $this->maintenance_msg = isset($auth_config['maintenance_msg'])? (string) $auth_config['maintenance_msg']: ""; } else { $this->login_page = 'users/login'; $this->logout_page = 'users/logout'; $this->auto_redirect = true; $this->hashkey = "mYpERsOnALhaSHkeY"; $this->maintenance_mode = 0; $this->maintenance_msg = ""; } // pass auth data to the view so it can be used by the helper $this->_pass_auth_data(); } // --------------These functions are supposed to be called from outside of othAuth------------------- function load_user_info(){ $this->login_info = $this->_valid_session(); // Load the user info $this->load_user($this->login_info); } function get_user_info () { if(empty($this->user_info)){ $this->load_user_info(); } return $this->user_info; } function get_user_field ($str = 'id') { if(empty($this->user_info)){ $this->load_user_info(); } return $this->user_info[$str]; } function is_guest() { if(empty($this->user_info)){ $this->load_user_info(); } return $this->user_info['is_guest']; } function is_admin() { if(empty($this->user_info)){ $this->load_user_info(); } return $this->user_info['is_admin']; } //----------------------login/logout functions------------------------------------------------------ // users/login users/logout function login($params) // username,password,group { //$params = $params[$this->user_table]; if($params == null || !isset($params[$this->user_login_var]) || !isset($params[$this->user_passw_var])) { return 0; } $set_cookie = isset($params[$this->user_cookie_var]) ? (int)$params[$this->user_cookie_var] : 0; $ret = $this->_login($params[$this->user_login_var], $params[$this->user_passw_var], $set_cookie); if($ret == 1 && $this->auto_redirect == true) { $this->redirect($this->access_page); } return $ret; } function _login($login = "", $passw = "", $set_cookie = false) { if(!$this->_check_login_attempts()) { return -3; // too many login attempts } if($login == "" || $passw == "") { return -1; } uses('sanitize'); $login = Sanitize::sql($login); $conditions = array($this->user_table_login => $login); $UserModel = $this->_create_model($this->user_model); $row = $UserModel->find($conditions, $this->user_table_passwSalt); if(!empty($row[$this->user_model])) $hashed_passw = $this->_get_hash_of($passw, $row[$this->user_model][$this->user_table_passwSalt]); else{ $this->_save_login_attempts(); return -2; } $conditions = array($this->user_table_login => $login, $this->user_table_passw => $hashed_passw); $row = $UserModel->find($conditions); if(empty($row)) { $this->_save_login_attempts(); return -2; } else { //$this->_delete_login_attempts(); //$row = $row[0]; if($set_cookie) { $this->_save_cookie($login, $passw); } $this->_save_session($login, $passw); /* // Update the last visit date to now if(isset($this->user_table_lastLogin)) { $row[$this->user_model][$this->user_table_lastLogin] = date('Y-m-d h:i:s'); $UserModel->id = $row[$this->user_model]['id']; $res = $UserModel->saveField($this->user_table_lastLogin,$row[$this->user_model][$this->user_table_lastLogin]); } // 0.2.5 save history if($this->history_active) { $this->_add_history($row); } */ return 1; } } function logout ($kill_cookie = false) { $us = 'othAuth.'.$this->hashkey; if($this->Session->valid() && $this->Session->check($us)) { $ses = $this->Session->read($us); if(!empty($ses) && is_array($ses)) { // two logins of different hashkeys can exist if($this->hashkey == $ses[$this->user_model]['hashkey']) { $this->Session->del($us); $this->Session->del('othAuth.frompage'); /* $o = $this->Session->check('othAuth'); if( is_array( $o ) && empty( $o )) { $this->Session->del('othAuth'); } */ if($kill_cookie) { $this->_save_cookie(null,true); } if($this->auto_redirect == true) { // check if logout_page is the action where logout is called! if(!empty($this->logout_page)) { $this->redirect($this->logout_page); } return true; } } } } return false; } function _get_hash_of($str, $salt = "") { vendor($this->pass_crypt_callback_file); if(function_exists($this->pass_crypt_callback)) { return call_user_func($this->pass_crypt_callback,$str, $salt); } return false; } //-------------------------History, session and the likes--------------------------------------------------- // 0.2.5 function _add_history(&$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_lastLogin])) { $data[$this->history_model]['visitdate'] = $row[$this->user_model][$this->user_table_lastLogin]; }else { $data[$this->history_model]['visitdate'] = date('Y-m-d h:i:s'); } if (!class_exists($this->history_model)) { loadModel($this->history_model); } $HistoryModel =& new $this->history_model; $HistoryModel->unbindAll(); $HistoryModel->recursive = -1; $HistoryModel->save($data); } function _save_session($login, $passw) { $hk = $this->_get_hash_of($this->hashkey.$login.$passw, $this->salt); $row[$this->user_login_var] = $login; $row[$this->user_passw_var] = $passw; $row['login_hash'] = $hk; $row['hashkey'] = $this->hashkey; $this->Session->write('othAuth_'.$this->hashkey,$row); } // null, true to delete the cookie function _save_cookie($login, $passw ,$del = false) { //die(pr($row)); if($this->cookie_active) { if(!$del) { $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 _read_cookie() { // 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); $data[$this->user_login_var] = $login; $data[$this->user_passw_var] = $passw; $redirect_old = $this->auto_redirect; $this->auto_redirect = false; $ret = $this->login($data); $this->auto_redirect = $redirect_old; } } // delete attempts after a successful login function _delete_login_attempts() { if($this->login_limit) { $ip = env('REMOTE_ADDR'); $Model = $this->_create_model($this->login_attempts_model); $Model->del($ip); if($this->cookie_active) { setcookie('othAuth_login_attempts','',time() - 31536000,'/'); } } } function _check_login_attempts() { if($this->login_limit) { $ip = env('REMOTE_ADDR'); $Model = $this->_create_model($this->login_attempts_model); /* if (!is_numeric($this->login_locked_out)) { $keep_for = (int) strtotime($this->login_locked_out); $time = ($keep_for > 0 ? $keep_for : 999999999); } else { $keep_for = $this->login_locked_out; $time = time() + ($keep_for > 0 ? $keep_for : 999999999); } */ // delete all expired and timedout records $del_sql = "DELETE FROM {$Model->useTable} WHERE expire <= NOW() AND num >= $this->login_attempts_num"; /*if($this->login_attempts_timeout > 0) { $timeout = $this->login_attempts_timeout * 60; $del_sql .= " OR (UNIX_TIMESTAMP(created) > (UNIX_TIMESTAMP(NOW()) - $timeout))"; }*/ $Model->query($del_sql); $row = $Model->find(array($this->login_attempts_model.'.ip'=>$ip)); //die("hi!"); if(!empty($row)) { $num = $row[$this->login_attempts_model]['num']; $this->login_attempts_current_num = $num; if($num >= $this->login_attempts_num) { return false; } }else { $this->login_attempts_current_num = 0; } if($this->cookie_active && isset($_COOKIE['othAuth_login_attempts'])) { $cdata = $_COOKIE['othAuth_login_attempts']; if (get_magic_quotes_gpc()) { $cdata=stripslashes($cdata); } $cdata = $this->decrypt($cdata); $cdata = @unserialize($cdata); $time = $cdata['t']; $num_tries = $cdata['n']; if($num_tries >= $this->login_attempts_num) { return false; } if($this->login_attempts_current_num == 0 && $num_tries > 0) { $this->login_attempts_current_num = $num_tries; } } } return true; } function _save_login_attempts() { if($this->login_limit) { $num_tries = $this->login_attempts_current_num + 1; //die(date("Y-m-d H:i:s",$keep_for)); $time = time(); $expire = date("Y-m-d H:i:s", $time + ($this->login_attempts_timeout * 60)); $ip = env('REMOTE_ADDR'); //die(pr($expire)); $data[$this->login_attempts_model]['ip'] = $ip; $data[$this->login_attempts_model]['num'] = $num_tries; $data[$this->login_attempts_model]['expire'] = $expire; $Model = & new $this->login_attempts_model; $Model->unbindAll(); $Model->recursive = -1; $Model->save($data); if($this->cookie_active) { $cdata = $this->encrypt(serialize(array('t'=>time(),'n'=>$num_tries))); setcookie('othAuth_login_attempts',$cdata,$time,'/'); } } } function __not_current($page) { if($page == "") return false; $c = strtolower($this->controller->name); $a = strtolower($this->controller->action); $page = strtolower($page.'/'); $c_a = $this->_handle_cake_admin($c,$a); $not_current = strpos($page,$c_a); // !== is required, $not_current might be boolean(false) return ((!is_int($not_current)) || ($not_current !== 0)); } function redirect($page = "",$back = false) { if($page == "") //$page = $this->redirect_page; $page = $this->logout_page; if(isset($this->auth_url_redirect_var)) { if(!isset($this->controller->params['url'][$this->auth_url_redirect_var])) { if($back == true) { $frompage = !isset($this->controller->params['url']['url'])? '/': '/'.$this->controller->params['url']['url']; $this->Session->write('othAuth.frompage',$frompage); $page .= "?".$this->auth_url_redirect_var."=".$frompage; } else { if($this->Session->check('othAuth.frompage')) { $page = $this->Session->read('othAuth.frompage'); $this->Session->del('othAuth.frompage'); } } } } if($this->__not_current($page)) { if($this->__not_current($page)) { if ($this->RequestHandler->isAjax()) { $this->RequestHandler->setAjax($this->controller); // Brute force ! echo ''; exit; } else { $this->controller->redirect($page); exit; } } } } // Confirms that an existing login is still valid function check() { // Level 3 Maintenance? if ($this->maintenance_mode >=3) die($this->maintenance_msg); // Uhm where are we? $this->cur_url = $this->current_url(); if($this->_valid_restrictions()) { // Attempt to retrieve the user login info from session/cookie first $this->login_info = $this->_valid_session(); // Load the user info $this->load_user($this->login_info); // Once you are here you must have logged in already. That means you MUST have valid session if(!$this->login_info) { $this->logout(); if($this->auto_redirect == true) { $this->redirect($this->login_page,true); } return false; } $permi = $this->_check_permission(); // check permissions on the current controller/action/p/a/r/a/m/s if(!$permi) { if($this->auto_redirect == true) { // should probably add $this->noaccess_page too or just flash $this->redirect($this->noaccess_page,true); } return false; } return true; }//die("lalala"); return true; } function _valid_restrictions() { // Whatever you say, all admin actions MUST be checked for permission if($this->is_cake_admin_action()) if($this->__not_current($this->login_page) && $this->__not_current($this->logout_page)) return true; $isset = isset($this->controller->othAuthRestrictions); if(!$isset) { return true; } else { $oth_res = $this->controller->othAuthRestrictions; if(in_array($this->cur_url['con_act_par'], $oth_res) || in_array($this->cur_url['con_act'].'*', $oth_res) || in_array($this->cur_url['controller'].'/*', $oth_res)) { return false; } else { return true; } } } function _check_permission() { // Level 2 Maintenance? Even admin can't access any page if ($this->maintenance_mode == 2) die($this->maintenance_msg); // Admin is really a super human after all if($this->user_info['is_admin']) return true; if ($this->maintenance_mode == 1) die($this->maintenance_msg); $method = $this->controller->action."_auth"; if(method_exists($this->controller, $method)){ switch ($this->controller->$method()){ case "granted": return true; break; case "denied": return false; break; default: break; } } if(array_key_exists($this->cur_url['con_act'], $this->user_info['permission'])){ foreach($this->user_info['permission'][$this->cur_url['con_act']] as $value){ $ret = "continue"; if($value[0] == "_"){ $ret = method_exists($this, $value) ? $this->$value() : $ret; } else{ $ret = method_exists($this->controller, $value) ? $this->controller->$value() : $ret; } switch ($ret){ case "granted": return true; break; case "denied": return false; break; default: break; } } } // Alrighty, do you have full permission on this controller? if($this->_check_permission2(&$this->user_info['permission'])) return true; /* Remove comment if you want to use this, you will need to look at the code and figure out the models/tables needed tho // Now unless you are a mod, otherwise you can't do anything, really!!! if($this->user_info['is_mod']) { // A Mod is ONLY a Mod when he/she is in his category $this->cur_cat = $this->controller->current_categories(); // Are we at the category you moderate? if (in_array($this->cur_cat, $this->user_info['mod']['cat'])) { // Load up their mod permissions $this->user_info['mod_permissions'] = $this->load_permission(implode("," ,$this->user_info['mod']['group'][$this->cur_cat])); if($this->_check_permission2(&$this->user_info['mod_permissions'])) return true; } } */ return false; } function _check_permission2(&$permission_array) { // Alrighty, do you have full permission on this controller? if(array_key_exists($this->cur_url['con_act']."*", $permission_array)) return true; // Uhm, by any chance you are granted the permission to perform this very specific action? if(array_key_exists($this->cur_url['con_act_par'], $permission_array)) return true; return false; } function current_url() { uses('inflector'); $cur_url = array(); $cur_url['controller'] = strtolower(Inflector::underscore($this->controller->name)); $cur_url['action'] = strtolower($this->controller->action); $cur_url['here'] = strtolower($this->controller->here); $cur_url['con_act'] = $this->_handle_cake_admin($cur_url['controller'], $cur_url['action']);// controller/admin_action -> admin/controller/action $cur_url['param_str'] = ''; $cur_url['param_arr'] = array(); if(isset($this->controller->params['pass'])) { $cur_url['param_arr'] = $this->controller->params['pass']; $cur_url['param_str'] = implode('/',$this->controller->params['pass']); } $cur_url['con_act_par'] = $cur_url['con_act'].$cur_url['param_str']; return $cur_url; } function _handle_cake_admin($c,$a) { if(defined('CAKE_ADMIN')) { $strpos = strpos($a,CAKE_ADMIN.'_'); if($strpos === 0) { $function = substr($a,strlen(CAKE_ADMIN.'_')); if($c == null) return $function.'/'; $c_a = CAKE_ADMIN.'/'.$c.'/'.$function.'/'; return $c_a; }else { if($c == null) return $a.'/'; } } return $c.'/'.$a.'/'; } function get_safe_cake_admin_action() { if(defined('CAKE_ADMIN')) { $a = $this->controller->action; $strpos = strpos($a,CAKE_ADMIN.'_'); if($strpos === 0) { $function = substr($a,strlen(CAKE_ADMIN.'_')); return $function; } } return $this->controller->action; } function is_cake_admin_action() { if(defined('CAKE_ADMIN')) { $a = $this->controller->action; $strpos = strpos($a,CAKE_ADMIN.'_'); if($strpos === 0) { return true; } } return false; } function _valid_session() { // try to read cookie $this->_read_cookie(); $us = 'othAuth_'.$this->hashkey; // does session exists if($this->Session->valid() && $this->Session->check($us)) { $ses = $this->Session->read($us); $ret = array(); uses('sanitize'); //die(pr($ses[$this->user_table_login])); $ret[$this->user_login_var] = Sanitize::sql($ses[$this->user_login_var]); $ret[$this->user_passw_var] = Sanitize::sql($ses[$this->user_passw_var]); $hk = $ses['login_hash']; // is user invalid if ($this->_get_hash_of($this->hashkey.$ret[$this->user_login_var].$ret[$this->user_passw_var], $this->salt) == $hk) {return $ret;} } //$this->logout(); return false; } //---------------------------------Below are functions that help loading the user information-------------- function load_user($login_info) { // Initialize the user_info array $this->user_info = array( 'id' => 0, 'username' => '', 'name' => 'Guest', 'email' => '', 'passwd' => '', 'is_guest' => true, 'is_active' => false, 'is_admin' => false, //'is_mod' => false, 'lastLogin' => '', 'ip' => $_SERVER['REMOTE_ADDR'], 'permission' => array(), 'mod' => array('cat' => array(), 'group' => array()), 'group' => array('id' => array(), 'name' => array()), //'mod_permission' => array() ); if ($login_info){ $login = $login_info[$this->user_login_var]; $conditions = array($this->user_table_login => $login); $UserModel = $this->_create_model($this->user_model); $row = $UserModel->find($conditions); } else $row = array(); if(!empty($row)){ // Load groups first $this->user_info['id']= $row[$this->user_model][$this->user_table_id]; $this->user_info['username'] = $row[$this->user_model][$this->user_table_login]; $this->user_info['name'] = $row[$this->user_model][$this->user_table_realName]; $this->user_info['email'] = $row[$this->user_model][$this->user_table_email]; $this->user_info['passwd'] = $row[$this->user_model][$this->user_table_passw]; $this->user_info['is_guest'] = $row[$this->user_model][$this->user_table_id] == 0; $this->user_info['is_active'] = $row[$this->user_model][$this->user_table_active]; $this->user_info['lastLogin'] = $row[$this->user_model][$this->user_table_lastLogin]; $this->user_info['entry_group'] = array(); $this->user_info['group'] = $this->load_group($this->user_info['id']); //$group_ids = $this->load_category(); //$this->user_info['group']['id'] = array_diff($this->user_info['group']['id'], $this->user_info['mod']['group']); $this->user_info['permission'] = $this->load_permission(implode(",", $this->user_info['group']['id'])); // Only after loading all user's base group can we know if he is an admin (belong to group 1) $this->user_info['is_admin'] = in_array(1, $this->user_info['group']['id']); } } // Sanitize, check, do whatever needed to clean $id before passing it to this function!!!! // NOTE: we only load NORMAL groups, mod_groups are loaded bt load_category function load_group($id, $except = null) { $sql = "SELECT groups.id, groups.name FROM groups_users, groups WHERE groups_users.user_id = $id AND groups.id = groups_users.group_id"; if($except != null) $sql = $sql." AND groups_users.group_id NOT IN ($except)"; $GroupModel = $this->_create_model($this->group_model); $rows = $GroupModel->query($sql); $ret = array(); if(!empty($rows)){ foreach ($rows as $row){ $ret['id'][] = $row['groups']['id']; $ret['name'][] = $row['groups']['name']; } } return $ret; } // given a string of groups function load_permission($group_ids) { // We sort the permissions by order for 1 reason: so that the permission with // highest passing-possibility will be checked first, thus reduce the load $sql = "SELECT * FROM permissions LEFT JOIN groups_permissions ON (groups_permissions.permission_id = permissions.id) WHERE groups_permissions.group_id IN ($group_ids) ORDER BY permissions.order"; $PermissionModel = $this->_create_model($this->permission_model); $rows = $PermissionModel->query($sql); //die(pr($rows)); $ret = array(); //e(pr($rows)); if(!empty($rows)){ foreach ($rows as $row){ $permission = split("->", $row['permissions']['name']); $ret[$permission[0]][] = isset($permission[1]) ? $permission[1] : ""; } } //e(pr($ret)); return $ret; } // This function loads the categories the user moderates // It also checks which /*function load_category() { $group_ids = implode(",", $this->user_info['group']['id']); $sql = "SELECT * FROM categories_groups WHERE group_id IN ($group_ids)"; $CategoryModel = $this->_create_model($this->category_model); $rows = $CategoryModel->query($sql); $mod_groups = array (); if(!empty($rows)){ foreach ($rows as $row){ //e(pr($row)); $this->user_info['mod']['cat'][] = $row['categories_groups']['category_id']; // We load it this way, just in case we may have more than 1 mod-group per category $this->user_info['mod']['group'][$row['categories_groups']['category_id']][] = $row['categories_groups']['group_id']; $mod_groups[] = $row['categories_groups']['group_id']; } } if(count($this->user_info['mod']['cat']) > 0) $this->user_info['is_mod'] = true; else $this->user_info['is_mod'] = false; //return $mod_groups; if (count($mod_groups) > 0) return implode(",", $mod_groups); else return null; } */ // passes data to the view to be used by the helper function _pass_auth_data() { $data = get_object_vars($this); unset($data['controller']); unset($data['components']); unset($data['Session']); unset($data['RequestHandler']); $this->controller->set('othAuth_data',$data); } function encrypt($string) { $key = $this->hashkey; $result = ''; for($i=0; $ihashkey; $result = ''; $string = base64_decode($string); for($i=0; $iuser_login_var."/".$this->user_passw_var." empty"; }break; case -2: { return "Wrong ".$this->user_login_var."/".$this->user_passw_var; }break; case -3: { return "Too many login attempts."; }break; default: { return "Invalid error ID"; }break; } } function _create_model($object_model, $recursive = -1, $unbind = array()) { if (!class_exists($object_model)) { loadModel($object_model); } $ObjectModel =& new $object_model; $ObjectModel->recursive = $recursive; $ObjectModel->unbindAll($unbind); return $ObjectModel; } } ?>