<?php/***************************************************************************\ * End Config *\***************************************************************************/class AuthComponent extends Component{ var $controller = true; var $currentUser; var $User, $Role, $Controller,$Sanitize; function initialize( &$controller) { //making sure we don't initialize twice. if(empty($this->Controller)) { $this->Controller =& $controller; //set callbacks for data and stuffs if (! class_exists('Sanitize')) { Uses('Sanitize'); } $this->Sanitize = new Sanitize(); loadModel('User'); loadModel('Role'); $this->User = new User; $this->Role = new Role; //set up our info for the current user if (!$this->Controller->Session->check(RBAC_KEY)) { $this->setUserSession(RBAC_GUEST_NAME, RBAC_GUEST_ID, RBAC_GUEST_LOGIN,$this->buildPermissionList(RBAC_GUEST_ID)); } $this->currentUser = $this->Controller->Session->read(RBAC_KEY); } } /***************************************************************************\ * log in/log out related methods * \***************************************************************************/ /** * Destroys the session which has the effect of logging the user out. * @return */ function logout() { $this->Controller->Session->destroy(); } /** * Default login() action, checks passwords and populates the session with proper data * Assumes that it is called from the UsersController or another controller with similar data structure. * Uses the calling controllers data * @returns No return, if it works it redirects, otherwise view should be shown. */ function login() { $supp = null; //db user info for attempted log in $r_salt = null; //stored salt $r_hash = null; //stored hash if(!isset($this->Controller->data['User']['password'])) { $this->Controller->PulseError('Please fill out all required fields.','AuthController : s02'); } else { $this->Sanitize->paranoid($this->Controller->data['User']['user_name']); $supp = $this->User->checkUserPass($this->Controller->data['User']['user_name'], $this->Controller->data['User']['password']); if ($supp === false ) //no user by that name most likely { $this->Controller->PulseError('User/Password error','AuthController :s05'); } elseif($supp['User']['active'] === false) { $this->Controller->PulseError('User has been locked, please contact your Administrator','AuthController : s01'); } else { //everything verifies, Storing user info and redirecting $supp = $supp['User']; $perms = $this->buildPermissionList($supp['id']); //check to see if there is a role assigned to every logged in user // usefull for things like.. I donno... logging out? :P if (defined('RBAC_LOGIN_ROLE')) { $this->parseRolePermissions($this->Role->find(array('Role.name'=>RBAC_LOGIN_ROLE),null,null,2), $perms); } //set the session info. if ($this->setUserSession($supp['first_name']." ".$supp['last_name'], $supp['id'], $supp['user_name'],$perms)) { $redirect = $this->Controller->Session->read('loginRedirect'); if (empty($redirect)) { $redirect = '/'; } elseif(substr($redirect,0,1) !== '/') { $redirect = '/'. $redirect; } $this->Controller->flash('Log in Successful', $redirect); } else { $this->Controller->PulseError('Failed to create session.','AuthController : s03'); } } } } /** * Writes Session info a user * @return * @param $user_name Object * @param $user_id Object * @param $user_login Object * @param $permissions Object */ private function setUserSession($user_name,$user_id,$user_login,$permissions) { //everything verifies, Storing user info and redirecting $user_array = array('User'=>array( 'login' =>$user_login, 'id' =>$user_id, 'name' =>$user_name), 'Permissions' => $permissions); return $this->Controller->Session->write(RBAC_KEY, $user_array); } /** * Checks if a user is an admin. Looks at the Permission structure in $this->currentUser * @return Bool * @param $user_id */ public function isAdmin($user_id = null) { return (isset($this->currentUser['Permissions']['is_rbac_admin']) && $this->currentUser['Permissions']['is_rbac_admin'] == true) ; } /** * sets a page to be redirected to on login. * @return */ public function setLoginRedirect() { if(isset($this->params['url']['url'])) { $this->session->write('loginRedirect',$this->params['url']['url']); } } /***************************************************************************\ * Access level control and reporting functions * \***************************************************************************/ /** * Get a data item about the user * @return {String} The info, or null if not set. * @param {String} $info One of these three 'login', 'id', 'name' */ public function getCurrent($info) { return isset($this->currentUser['User'][$info]) ? $this->currentUser['User'][$info] : NULL; } /** * Compares two lists of roles, four possible return values: * 1 : $list1 contains every group in $list2, and one or more additionial * 0 : $list1 and $list2 have the exact same contents * -1 : $list2 contains at least one member that $list1 does not * -2 : one of the parameters is not an array * @return int * @param {Array} $list1 List of groups * @param $list2 List of groups */ public function compareRoles(array $list1, $list2) { $retVal = -2; if(is_array($list1) && is_array($list2)) { //get our difference $diff = array_diff($list1,$list2); if (!empty($diff)) { $retVal = 1; //assuming 1, if loop ends without altering, this is valid. array_flip($list1); //flip list1 for easy checking... $currentVal = array_pop($diff); //priming read... while($currentVal !== null && $retVal !== -1) { if ( !isset($list1[$currentVal])) { $retVal = -1; } $currentVal = array_pop($diff); } } else { $retVal = 0; } } return $retVal; //Todo finish me (hint, array_diff() ) } /** * Adds the permissions for a transient role to the current permission set. * This only lasts through the page view. * @return * @param $role_name Object */ public function addTransRole($role_name) { $this->parseRolePermissions($this->Role->find(array('Role.name'=>$role_name),null,null,2), $this->currentUser['Permissions']); } public function buildRoleList() { //If no User id specified, assume current user. if($user_id == null) { $user_id = $this->getCurrent('id'); } $this->User->id = $user_id; } /** * Builds the permission list for user specified with $user_id * @return * @param $user_id Object */ public function buildPermissionList($user_id = null) { $permissions = array(); //the array we are going to return $permTree = false; //our buffer for the find() //If no User id specified, assume current user. if($user_id == null) { $user_id = $this->getCurrent('id'); } $this->User->id = $user_id; //make sure that the user exists if($this->User->exists()) { //unbind all User associations except for the Role Assoc. $this->User->unbindAll(array('hasAndBelongsToMany'=>array('Role'))); $permissions = $this->parseUserPermissions($this->User->find("User.id = '".$user_id."'",null,null,3)); } return $permissions; } /** * Parses the results of a User array passed to it from a find() * @return returns a permissions array in the format of 'ControllerName:Action'=> true/false * @param {Array} $user_info User info array from find() */ function parseUserPermissions($user_info) { $permissions = array(); //short cut to check for admin role if(array_search(RBAC_ADMIN_ROLE,Set::extract($user_info,'Role.{n}.name') ) !== false) { $user_info['Role'] = array(); //hey lookie, this is an admin! lets fetch all roles! (except for Guest role) $this->User->Role->unbindAll(array('hasMany'=>array('Permission'))); $this->User->Role->recursive = 2; foreach($this->User->Role->findAll(array('Not' => array('name'=>RBAC_GUEST_ROLE))) as $key => $curRole) { //need to fix the structure of the array to match expected $user_info['Role'][$key] = $curRole['Role']; $user_info['Role'][$key]['Permission'] = $curRole['Permission']; } $permissions['is_rbac_admin'] = 'yes'; } if ( is_array($user_info) && !empty($user_info['Role'])) { foreach($user_info['Role'] as $role) { $this->parseRolePermissions($role, $permissions); } } return $permissions; } /** * Add the permissions of a Role that have been returned from a find() to $permissions. * @return {Array} returns the the permissions after the role has been applied. * @param {Array} $permTree Array holding the Roles for the User * @param {Array} $permissions Array holding the current permissions list */ function parseRolePermissions($role, &$permissions) { //does this role have any permissions? if (!empty($role['Permission'])) { foreach($role['Permission'] as $currPerm) { //if it's not set, create empty permission for simplicities sake if (!isset($permissions[$currPerm['Action']['controller']][$currPerm['Action']['action_name']])) { $permissions[$currPerm['Action']['controller']][$currPerm['Action']['action_name']] = null; // } //Our target permission, by reference $tPerm =& $permissions[$currPerm['Action']['controller']][$currPerm['Action']['action_name']]; //if the permission has been denied previously, then skip if ($tPerm !== false) { //if both are set, cannot_exec overrides can. if ($currPerm['cannot_exec'] === 1) { $tPerm['execute'] = false; //denied! I say NO! } elseif($currPerm['can_exec'] === 1) { $tPerm['execute'] = true; //ok for now. $tPerm['menu_category'] = $currPerm['Action']['menu_category']; $tPerm['menu_desc'] = $currPerm['Action']['menu_desc']; $tPerm['alternate_url'] = $currPerm['Action']['alternate_url']; } } } } } /** * Checks to see if a user can execute the specified action. If $user_id is null it assumes * current user, and checks cached permissions. * @return * @param $controller Object * @param $action Object * @param $user_id Object[optional] */ function canExecute($controller = null, $action = null, $user_id = null) { $retVal = false; //defaults to current controller and action if no controller/action is specified if ($controller == null) { $controller = $this->Controller->name; } if ($action == NULL ) { if (!isset($this->Controller->params['action'])) { pr($this->Controller->params); } $action = $this->Controller->params['action']; } if ($user_id === null) { $perm = $this->currentUser['Permissions']; } else { $perm = $this->BuildPermissionList($user_id); } //if it's set and is true, then return true, otherwise it's denied if ((isset ($perm[$controller][$action]['execute']) && $perm[$controller][$action]['execute'] == 1) || $this->isAdmin()) { $retVal = true; } return $retVal; }}?><?phpclass AuthHelper extends Helper{ var $helpers = array('Session','Html'); var $info = null; /** * Loads $this->info with the current user data from the session (this will not show dynamic roles...) * @return */ private function setInfo() { if (empty($this->info)) { $this->info = $this->Session->read('AuthInfo'); } } /** * Checks if a user is an admin. Looks at the Permission structure in $this->info * @return Bool * @param $user_id */ public function isAdmin($user_id = null) { $this->setInfo(); return (isset($this->info['Permissions']['is_pulse_admin']) && $this->info['Permissions']['is_pulse_admin'] == true) ; } /** * Get a file the User id of the current user * @return User_id of the current user, or false if not set */ public function getCurrent($info) { $this->setInfo(); return isset($this->info['User'][$info]) ? $this->output($this->info['User'][$info]) : $this->output(NULL); } /** * Checks to see if the current user is guest or not set, and returns false on either one * @return true if user is not guest, false if user is guest or logged in. */ public function getLoginStatus() { $this->setInfo(); return (!empty($this->info['User']['login']) && $this->info['User']['login'] != 'guest'); } /** * Outputs a <dl class="prettylist"> with the permissions and their allowed/dissalowed state * @return {Mixed} a string with the <dl> or null on error * @param {Array} $perms Permission list to parse */ public function parsePermissions($permList= array()) { $retVal = null; if($permList === array()) { $this->setInfo(); $permList = $this->info; } if (is_array($permList)) { $retVal = '<dl class="prettylist"><dt class="title">Permission</dt><dd class="title">value</dd>'; foreach ($permList as $controller => $action) { if( is_array($action) ) { foreach ($action as $actionName => $perm) { $retVal .= "\n<dt>".$controller." : ".$actionName."</dt><dd>"; if ($perm['execute'] == 1) //are they authorized? { $retVal .= "Allow"; } else { $retVal .= "Deny"; } $retVal .= "</dd>"; } } } } return $this->output($retVal); } public function getCurrentMenu() {// $retVal = '<ul id="mainMenu">'; //our returned string, init with the start of the list //uncommment for dropdown $retVal = '<ul class="menusub">'; //our returned string, init with the start of the list //uncommment for dropdown $menuBuff = array(); //menu buffer, filled after parsing the array. $this->setInfo(); //need to make sure our info has been set. It will, but good habits.. //cycle through the menu items and get every permission with associated menu entries foreach ($this->info['Permissions'] as $controller => $action) { if(is_array($action)) //is_rbac_admin will freak this out. { foreach ($action as $actionName => $perm) { if ($perm['execute'] == 1 && !empty($perm['menu_category']) && !empty($perm['menu_desc'])) //are they authorized, and is this a menu item? { $menuBuff[$perm['menu_category']][] = array( 'description'=>$perm['menu_desc'], 'controller'=>$controller, 'action'=>$actionName, 'alt_url'=>$perm['alternate_url']); } } } } //Build our menu. It might be nice to have some way to sort them, but I'll go there later ;p foreach ($menuBuff as $catName => $catItems ) { $retVal .= "<li>".$catName."\n<ul>"; foreach($catItems as $item) { if(!empty($item['alt_url'])) { $link = $this->Html->link($item['description'], $item['alt_url']); } else { $link = $this->Html->link($item['description'], '/'.$item['controller'].'/'.$item['action'].'/'); } $retVal .= "\n<li>".$link."</li>"; } $retVal .= "\n</ul></li>"; } $retVal .= "</ul>"; //close out our menu list and return return $this->output($retVal); }}?>