<?php /** * TUser, TUserManager class * * @author Qiang Xue <qiang.xue@gmail.com> * @link http://www.pradosoft.com/ * @copyright Copyright © 2005 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Revision: $ $Date: $ * @package System.Security */ /** * TUser class * * TUser implements basic user functionality for a prado application. * To get the name of the user, use {@link getName Name} property. * The property {@link getIsGuest IsGuest} tells if the user a guest/anonymous user. * To obtain or test the roles that the user is in, use property * {@link getRoles Roles} and call {@link isInRole()}, respectively. * * TUser is meant to be used together with {@link TUserManager} and * {@link TAuthManager}. * * @author Qiang Xue <qiang.xue@gmail.com> * @version $Revision: $ $Date: $ * @package System.Security * @since 3.0 */ class TUser extends TComponent implements IUser { /** * @var TUserManager user manager */ private $_manager; /** * @var boolean if the user is a guest */ private $_isGuest=true; /** * @var string username */ private $_name=''; /** * @var array user roles */ private $_roles=array(); /** * Constructor. * @param TUserManager user manager */ public function __construct($manager=null) { parent::__construct(); $this->_manager=$manager; } /** * @return TUserManager user manager */ public function getManager() { return $this->_manager; } /** * @return string username */ public function getName() { return $this->_name; } /** * @param string username */ public function setName($value) { $this->_name=$value; } /** * @return boolean if the user is a guest */ public function getIsGuest() { return $this->_isGuest; } /** * @param boolean if the user is a guest */ public function setIsGuest($value) { $this->_isGuest=TPropertyValue::ensureBoolean($value); if($this->_isGuest) { $this->_name=$this->_manager->getGuestName(); $this->_roles=array(); } } /** * @return array list of roles that the user is of */ public function getRoles() { return $this->_roles; } /** * @return array|string list of roles that the user is of. If it is a string, roles are assumed by separated by comma */ public function setRoles($value) { if(is_array($value)) $this->_roles=$value; else { $this->_roles=array(); foreach(explode(',',$value) as $role) { if(($role=trim($role))!=='') $this->_roles[]=$role; } } } /** * @param string role to be tested. Note, role is case-insensitive. * @return boolean whether the user is of this role */ public function isInRole($role) { foreach($this->_roles as $r) if(strcasecmp($role,$r)===0) return true; return false; } /** * @return string user data that is serialized and will be stored in session */ public function saveToString() { return serialize(array($this->_name,$this->_roles,$this->_isGuest)); } /** * @param string user data that is serialized and restored from session * @return IUser the user object */ public function loadFromString($data) { if(!empty($data)) { $array=unserialize($data); $this->_name=$array[0]; $this->_roles=$array[1]; $this->_isGuest=$array[2]; } return $this; } } /** * TUserManager class * * TUserManager manages a static list of users {@link TUser}. * The user information is specified via module configuration using the following XML syntax, * <module id="users" type="System.Security.TUserManager" PasswordMode="Clear"> * <user name="Joe" password="demo" /> * <user name="John" password="demo" /> * <role name="Administrator" users="John" /> * <role name="Writer" users="Joe,John" /> * </module> * * The user passwords may be specified as clear text, SH1 or MD5 hashed by setting * {@link setPasswordMode PasswordMode} as <b>Clear</b>, <b>SH1</b> or <b>MD5</b>. * The default name for a guest user is <b>Guest</b>. It may be changed * by setting {@link setGuestName GuestName} property. * * TUserManager may be used together with {@link TAuthManager} which manages * how users are authenticated and authorized in a Prado application. * * @author Qiang Xue <qiang.xue@gmail.com> * @version $Revision: $ $Date: $ * @package System.Security * @since 3.0 */ class TUserManager extends TModule { /** * extension name to the user file */ const USER_FILE_EXT='.xml'; /** * @var array list of users managed by this module */ private $_users=array(); /** * @var array list of roles managed by this module */ private $_roles=array(); /** * @var string guest name */ private $_guestName='Guest'; /** * @var string password mode, Clear|MD5|SH1 */ private $_passwordMode='MD5'; /** * @var boolean whether the module has been initialized */ private $_initialized=false; /** * @var string user/role information file */ private $_userFile=null; /** * Initializes the module. * This method is required by IModule and is invoked by application. * It loads user/role information from the module configuration. * @param TXmlElement module configuration */ public function init($config) { if($this->_userFile!==null) { if(is_file($this->_userFile)) { $dom=new TXmlDocument; $dom->loadFromFile($this->_userFile); $this->loadUserData($dom); } else throw new TConfigurationException('usermanager_userfile_invalid',$this->_userFile); } $this->loadUserData($config); $this->_initialized=true; } /** * Loads user/role information from an XML node. * @param TXmlElement the XML node containing the user information */ private function loadUserData($xmlNode) { foreach($xmlNode->getElementsByTagName('user') as $node) { $name=strtolower($node->getAttribute('name')); $this->_users[$name]=$node->getAttribute('password'); if(($roles=trim($node->getAttribute('roles')))!=='') { foreach(explode(',',$roles) as $role) $this->_roles[$name][]=$role; } } foreach($xmlNode->getElementsByTagName('role') as $node) { foreach(explode(',',$node->getAttribute('users')) as $user) { if(($user=trim($user))!=='') $this->_roles[strtolower($user)][]=$node->getAttribute('name'); } } } /** * @return string the full path to the file storing user/role information */ public function getUserFile() { return $this->_userFile; } /** * @param string user/role data file path (in namespace form). The file format is XML * whose content is similar to that user/role block in application configuration. * @throws TInvalidOperationException if the module is already initialized * @throws TConfigurationException if the file is not in proper namespace format */ public function setUserFile($value) { if($this->_initialized) throw new TInvalidOperationException('usermanager_userfile_unchangeable'); else if(($this->_userFile=Prado::getPathOfNamespace($value,self::USER_FILE_EXT))===null) throw new TConfigurationException('usermanager_userfile_invalid',$value); } /** * @return string guest name, defaults to 'Guest' */ public function getGuestName() { return $this->_guestName; } /** * @param string name to be used for guest users. */ public function setGuestName($value) { $this->_guestName=$value; } /** * @return string (Clear|MD5|SH1) how password is stored, clear text, or MD5 or SH1 hashed. Default to MD5. */ public function getPasswordMode() { return $this->_passwordMode; } /** * @param string (Clear|MD5|SH1) how password is stored, clear text, or MD5 or SH1 hashed. */ public function setPasswordMode($value) { $this->_passwordMode=TPropertyValue::ensureEnum($value,array('Clear','MD5','SHA1')); } /** * Validates if the username and password are correct. * @param string user name * @param string password * @return boolean true if validation is successful, false otherwise. */ public function validateUser($username,$password) { if($this->_passwordMode==='MD5') $password=md5($password); else if($this->_passwordMode==='SHA1') $password=sha1($password); $username=strtolower($username); return (isset($this->_users[$username]) && $this->_users[$username]===$password); } /** * Returns a user instance given the user name. * @param string user name, null if it is a guest. * @return TUser the user instance, null if the specified username is not in the user database. */ public function getUser($username=null) { if($username===null) { $user=new TUser($this); $user->setIsGuest(true); return $user; } else { $username=strtolower($username); if(isset($this->_users[$username])) { $user=new TUser($this); $user->setName($username); $user->setIsGuest(false); if(isset($this->_roles[$username])) $user->setRoles($this->_roles[$username]); return $user; } else return null; } } /** * Sets a user as a guest. * User name is changed as guest name, and roles are emptied. * @param TUser the user to be changed to a guest. */ public function switchToGuest($user) { $user->setIsGuest(true); $user->setName($this->getGuestName()); $user->setRoles(array()); } } ?>