All pastes #989772 Raw Edit

Someone

public text v1 · immutable
#989772 ·published 2008-04-19 18:28 UTC
rendered paste body
<?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;
	}

}
?>



<?php


class 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);
	}
}
?>