diff options
author | emkael <emkael@tlen.pl> | 2016-02-24 23:18:07 +0100 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2016-02-24 23:18:07 +0100 |
commit | 6f7fdef0f500cd4bb540affd3bc1482243f337c1 (patch) | |
tree | 4853eecd0769a903e6130c1896e1d070848150dd /lib/prado/framework/Security/TUserManager.php | |
parent | 61f2ea48a4e11cb5fb941b3783e19c9e9ef38a45 (diff) |
* Prado 3.3.0
Diffstat (limited to 'lib/prado/framework/Security/TUserManager.php')
-rw-r--r-- | lib/prado/framework/Security/TUserManager.php | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/lib/prado/framework/Security/TUserManager.php b/lib/prado/framework/Security/TUserManager.php new file mode 100644 index 0000000..6ca8a42 --- /dev/null +++ b/lib/prado/framework/Security/TUserManager.php @@ -0,0 +1,399 @@ +<?php +/** + * TUserManager class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Security + */ + +/** + * Using TUser class + */ +Prado::using('System.Security.TUser'); + +/** + * TUserManager class + * + * TUserManager manages a static list of users {@link TUser}. + * The user information is specified via module configuration using the following XML syntax, + * <code> + * <module id="users" class="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> + * </code> + * + * PHP configuration style: + * <code> + * array( + * 'users' => array( + * 'class' => 'System.Security.TUserManager', + * 'properties' => array( + * 'PasswordMode' => 'Clear', + * ), + * 'users' => array( + * array('name'=>'Joe','password'=>'demo'), + * array('name'=>'John','password'=>'demo'), + * ), + * 'roles' => array( + * array('name'=>'Administrator','users'=>'John'), + * array('name'=>'Writer','users'=>'Joe,John'), + * ), + * ), + * ) + * </code> + * + * In addition, user information can also be loaded from an external file + * specified by {@link setUserFile UserFile} property. Note, the property + * only accepts a file path in namespace format. The user file format is + * similar to the above sample. + * + * The user passwords may be specified as clear text, SH1 or MD5 hashed by setting + * {@link setPasswordMode PasswordMode} as <b>Clear</b>, <b>SHA1</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> + * @author Carl Mathisen <carl@kamikazemedia.no> + * @package System.Security + * @since 3.0 + */ +class TUserManager extends TModule implements IUserManager +{ + /** + * 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 TUserManagerPasswordMode password mode + */ + private $_passwordMode=TUserManagerPasswordMode::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 mixed module configuration + */ + public function init($config) + { + $this->loadUserData($config); + if($this->_userFile!==null) + { + if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + { + $userFile = include $this->_userFile; + $this->loadUserDataFromPhp($userFile); + } + else + { + $dom=new TXmlDocument; + $dom->loadFromFile($this->_userFile); + $this->loadUserDataFromXml($dom); + } + } + $this->_initialized=true; + } + + /* + * Loads user/role information + * @param mixed the variable containing the user information + */ + private function loadUserData($config) + { + if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP) + $this->loadUserDataFromPhp($config); + else + $this->loadUserDataFromXml($config); + } + + /** + * Loads user/role information from an php array. + * @param array the array containing the user information + */ + private function loadUserDataFromPhp($config) + { + if(isset($config['users']) && is_array($config['users'])) + { + foreach($config['users'] as $user) + { + $name = trim(strtolower(isset($user['name'])?$user['name']:'')); + $password = isset($user['password'])?$user['password']:''; + $this->_users[$name] = $password; + $roles = isset($user['roles'])?$user['roles']:''; + if($roles!=='') + { + foreach(explode(',',$roles) as $role) + { + if(($role=trim($role))!=='') + $this->_roles[$name][]=$role; + } + } + } + } + if(isset($config['roles']) && is_array($config['roles'])) + { + foreach($config['roles'] as $role) + { + $name = isset($role['name'])?$role['name']:''; + $users = isset($role['users'])?$role['users']:''; + foreach(explode(',',$users) as $user) + { + if(($user=trim($user))!=='') + $this->_roles[strtolower($user)][]=$name; + } + } + } + } + + /** + * Loads user/role information from an XML node. + * @param TXmlElement the XML node containing the user information + */ + private function loadUserDataFromXml($xmlNode) + { + foreach($xmlNode->getElementsByTagName('user') as $node) + { + $name=trim(strtolower($node->getAttribute('name'))); + $this->_users[$name]=$node->getAttribute('password'); + if(($roles=trim($node->getAttribute('roles')))!=='') + { + foreach(explode(',',$roles) as $role) + { + if(($role=trim($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'); + } + } + } + + /** + * Returns an array of all users. + * Each array element represents a single user. + * The array key is the username in lower case, and the array value is the + * corresponding user password. + * @return array list of users + */ + public function getUsers() + { + return $this->_users; + } + + /** + * Returns an array of user role information. + * Each array element represents the roles for a single user. + * The array key is the username in lower case, and the array value is + * the roles (represented as an array) that the user is in. + * @return array list of user role information + */ + public function getRoles() + { + return $this->_roles; + } + + /** + * @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 || !is_file($this->_userFile)) + 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 TUserManagerPasswordMode how password is stored, clear text, or MD5 or SHA1 hashed. Default to TUserManagerPasswordMode::MD5. + */ + public function getPasswordMode() + { + return $this->_passwordMode; + } + + /** + * @param TUserManagerPasswordMode how password is stored, clear text, or MD5 or SHA1 hashed. + */ + public function setPasswordMode($value) + { + $this->_passwordMode=TPropertyValue::ensureEnum($value,'TUserManagerPasswordMode'); + } + + /** + * 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===TUserManagerPasswordMode::MD5) + $password=md5($password); + else if($this->_passwordMode===TUserManagerPasswordMode::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; + } + } + + /** + * Returns a user instance according to auth data stored in a cookie. + * @param THttpCookie the cookie storing user authentication information + * @return TUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data. + * @since 3.1.1 + */ + public function getUserFromCookie($cookie) + { + if(($data=$cookie->getValue())!=='') + { + $data=unserialize($data); + if(is_array($data) && count($data)===2) + { + list($username,$token)=$data; + if(isset($this->_users[$username]) && $token===md5($username.$this->_users[$username])) + return $this->getUser($username); + } + } + return null; + } + + /** + * Saves user auth data into a cookie. + * @param THttpCookie the cookie to receive the user auth data. + * @since 3.1.1 + */ + public function saveUserToCookie($cookie) + { + $user=$this->getApplication()->getUser(); + $username=strtolower($user->getName()); + if(isset($this->_users[$username])) + { + $data=array($username,md5($username.$this->_users[$username])); + $cookie->setValue(serialize($data)); + } + } + + /** + * 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); + } +} + +/** + * TUserManagerPasswordMode class. + * TUserManagerPasswordMode defines the enumerable type for the possible modes + * that user passwords can be specified for a {@link TUserManager}. + * + * The following enumerable values are defined: + * - Clear: the password is in plain text + * - MD5: the password is recorded as the MD5 hash value of the original password + * - SHA1: the password is recorded as the SHA1 hash value of the original password + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Security + * @since 3.0.4 + */ +class TUserManagerPasswordMode extends TEnumerable +{ + const Clear='Clear'; + const MD5='MD5'; + const SHA1='SHA1'; +} + |