core =& $core; $this->con =& $core->con; $this->blog_table = $core->prefix.'blog'; $this->user_table = $core->prefix.'user'; $this->perm_table = $core->prefix.'permissions'; $this->perm_types = array( 'admin' => __('administrator'), 'usage' => __('manage their own entries and comments'), 'publish' => __('publish entries and comments'), 'delete' => __('delete entries and comments'), 'contentadmin' => __('manage all entries and comments'), 'categories' => __('manage categories'), 'media' => __('manage their own media items'), 'media_admin' => __('manage all media items') ); } /// @name Credentials and user permissions //@{ /** * Checks if user exists and can log in. $pwd argument is optionnal * while you may need to check user without password. This method will create * credentials and populate all needed object properties. * * @param string $user_id User ID * @param string $pwd User password * @param string $user_key User key check * @param boolean $check_blog checks if user is associated to a blog or not. * @return boolean */ public function checkUser($user_id, $pwd=null, $user_key=null, $check_blog=true) { # Check user and password $strReq = 'SELECT user_id, user_super, user_pwd, user_change_pwd, '. 'user_name, user_firstname, user_displayname, user_email, '. 'user_url, user_default_blog, user_options, '. 'user_lang, user_tz, user_post_status, user_creadt, user_upddt '. 'FROM '.$this->con->escapeSystem($this->user_table).' '. "WHERE user_id = '".$this->con->escape($user_id)."' "; try { $rs = $this->con->select($strReq); } catch (Exception $e) { $err = $e->getMessage(); return false; } if ($rs->isEmpty()) { sleep(rand(2,5)); return false; } $rs->extend('rsExtUser'); if ($pwd != '') { if ($this->crypt($pwd) != $rs->user_pwd) { sleep(rand(2,5)); return false; } } elseif ($user_key != '') { if (http::browserUID(DC_MASTER_KEY.$rs->user_id.$rs->user_pwd) != $user_key) { return false; } } $this->user_id = $rs->user_id; $this->user_change_pwd = (boolean) $rs->user_change_pwd; $this->user_admin = (boolean) $rs->user_super; $this->user_info['user_pwd'] = $rs->user_pwd; $this->user_info['user_name'] = $rs->user_name; $this->user_info['user_firstname'] = $rs->user_firstname; $this->user_info['user_displayname'] = $rs->user_displayname; $this->user_info['user_email'] = $rs->user_email; $this->user_info['user_url'] = $rs->user_url; $this->user_info['user_default_blog'] = $rs->user_default_blog; $this->user_info['user_lang'] = $rs->user_lang; $this->user_info['user_tz'] = $rs->user_tz; $this->user_info['user_post_status'] = $rs->user_post_status; $this->user_info['user_creadt'] = $rs->user_creadt; $this->user_info['user_upddt'] = $rs->user_upddt; $this->user_info['user_cn'] = dcUtils::getUserCN($rs->user_id, $rs->user_name, $rs->user_firstname, $rs->user_displayname); $this->user_options = array_merge($this->core->userDefaults(),$rs->options()); $this->user_prefs = new dcPrefs($this->core,$this->user_id); # Get permissions on blogs if ($check_blog && ($this->findUserBlog() === false)) { return false; } return true; } /** * This method crypt given string (password, session_id, …). * * @param string $pwd string to be crypted * @return string crypted value */ public function crypt($pwd) { return crypt::hmac(DC_MASTER_KEY,$pwd,DC_CRYPT_ALGO); } /** * This method only check current user password. * * @param string $pwd User password * @return boolean */ public function checkPassword($pwd) { if (!empty($this->user_info['user_pwd'])) { return $pwd == $this->user_info['user_pwd']; } return false; } /** * This method checks if user session cookie exists * * @return boolean */ public function sessionExists() { return isset($_COOKIE[DC_SESSION_NAME]); } /** * This method checks user session validity. * * @return boolean */ public function checkSession($uid=null) { $this->core->session->start(); # If session does not exist, logout. if (!isset($_SESSION['sess_user_id'])) { $this->core->session->destroy(); return false; } # Check here for user and IP address $this->checkUser($_SESSION['sess_user_id']); $uid = $uid ? $uid : http::browserUID(DC_MASTER_KEY); $user_can_log = $this->userID() !== null && $uid == $_SESSION['sess_browser_uid']; if (!$user_can_log) { $this->core->session->destroy(); return false; } return true; } /** * Checks if user must change his password in order to login. * * @return boolean */ public function mustChangePassword() { return $this->user_change_pwd; } /** * Checks if user is super admin * * @return boolean */ public function isSuperAdmin() { return $this->user_admin; } /** * Checks if user has permissions given in $permissions for blog * $blog_id. $permissions is a coma separated list of * permissions. * * @param string $permissions Permissions list * @param string $blog_id Blog ID * @return boolean */ public function check($permissions,$blog_id) { if ($this->user_admin) { return true; } $p = array_map('trim',explode(',',$permissions)); $b = $this->getPermissions($blog_id); if ($b != false) { if (isset($b['admin'])) { return true; } foreach ($p as $v) { if (isset($b[$v])) { return true; } } } return false; } /** * Returns true if user is allowed to change its password. * * @return boolean */ public function allowPassChange() { return $this->allow_pass_change; } //@} /// @name User code handlers //@{ public function getUserCode() { $code = pack('a32',$this->userID()). pack('H*',$this->crypt($this->getInfo('user_pwd'))); return bin2hex($code); } public function checkUserCode($code) { $code = @pack('H*',$code); $user_id = trim(@pack('a32',substr($code,0,32))); $pwd = @unpack('H*hex',substr($code,32)); if ($user_id === false || $pwd === false) { return false; } $pwd = $pwd['hex']; $strReq = 'SELECT user_id, user_pwd '. 'FROM '.$this->user_table.' '. "WHERE user_id = '".$this->con->escape($user_id)."' "; $rs = $this->con->select($strReq); if ($rs->isEmpty()) { return false; } if ($this->crypt($rs->user_pwd) != $pwd) { return false; } return $rs->user_id; } //@} /// @name Sudo //@{ /** * Calls $f function with super admin rights. * Returns the function result. * * @param callback $f Callback function * @return mixed */ public function sudo($f) { if (!is_callable($f)) { throw new Exception($f.' function doest not exist'); } $args = func_get_args(); array_shift($args); if ($this->user_admin) { $res = call_user_func_array($f,$args); } else { $this->user_admin = true; try { $res = call_user_func_array($f,$args); $this->user_admin = false; } catch (Exception $e) { $this->user_admin = false; throw $e; } } return $res; } //@} /// @name User information and options //@{ /** * Returns user permissions for a blog as an array which looks like: * * - [blog_id] * - [permission] => true * - ... * * @param string $blog_id Blog ID * @return array */ public function getPermissions($blog_id) { if (isset($this->blogs[$blog_id])) { return $this->blogs[$blog_id]; } if ($this->user_admin) { $strReq = 'SELECT blog_id '. 'from '.$this->blog_table.' '. "WHERE blog_id = '".$this->con->escape($blog_id)."' "; $rs = $this->con->select($strReq); $this->blogs[$blog_id] = $rs->isEmpty() ? false : array('admin' => true); return $this->blogs[$blog_id]; } $strReq = 'SELECT permissions '. 'FROM '.$this->perm_table.' '. "WHERE user_id = '".$this->con->escape($this->user_id)."' ". "AND blog_id = '".$this->con->escape($blog_id)."' ". "AND (permissions LIKE '%|usage|%' OR permissions LIKE '%|admin|%' OR permissions LIKE '%|contentadmin|%') "; $rs = $this->con->select($strReq); $this->blogs[$blog_id] = $rs->isEmpty() ? false : $this->parsePermissions($rs->permissions); return $this->blogs[$blog_id]; } public function getBlogCount() { if ($this->blog_count === null) { $this->blog_count = $this->core->getBlogs(array(),true)->f(0); } return $this->blog_count; } public function findUserBlog($blog_id=null) { if ($blog_id && $this->getPermissions($blog_id) !== false) { return $blog_id; } else { if ($this->user_admin) { $strReq = 'SELECT blog_id '. 'FROM '.$this->blog_table.' '. 'ORDER BY blog_id ASC '. $this->con->limit(1); } else { $strReq = 'SELECT blog_id '. 'FROM '.$this->perm_table.' '. "WHERE user_id = '".$this->con->escape($this->user_id)."' ". "AND (permissions LIKE '%|usage|%' OR permissions LIKE '%|admin|%' OR permissions LIKE '%|contentadmin|%') ". 'ORDER BY blog_id ASC '. $this->con->limit(1); } $rs = $this->con->select($strReq); if (!$rs->isEmpty()) { return $rs->blog_id; } } return false; } /** * Returns current user ID * * @return string */ public function userID() { return $this->user_id; } /** * Returns information about a user . * * @param string $n Information name * @return string */ public function getInfo($n) { if (isset($this->user_info[$n])) { return $this->user_info[$n]; } return null; } /** * Returns a specific user option * * @param string $n Option name * @return string */ public function getOption($n) { if (isset($this->user_options[$n])) { return $this->user_options[$n]; } return null; } /** * Returns all user options in an associative array. * * @return array */ public function getOptions() { return $this->user_options; } //@} /// @name Permissions //@{ /** * Returns an array with permissions parsed from the string $level * * @param string $level Permissions string * @return array */ public function parsePermissions($level) { $level = preg_replace('/^\|/','',$level); $level = preg_replace('/\|$/','',$level); $res = array(); foreach (explode('|',$level) as $v) { $res[$v] = true; } return $res; } /** * Returns perm_types property content. * * @return array */ public function getPermissionsTypes() { return $this->perm_types; } /** * Adds a new permission type. * * @param string $name Permission name * @param string $title Permission title */ public function setPermissionType($name,$title) { $this->perm_types[$name] = $title; } //@} /// @name Password recovery //@{ /** * Add a recover key to a specific user identified by its email and * password. * * @param string $user_id User ID * @param string $user_email User Email * @return string */ public function setRecoverKey($user_id,$user_email) { $strReq = 'SELECT user_id '. 'FROM '.$this->user_table.' '. "WHERE user_id = '".$this->con->escape($user_id)."' ". "AND user_email = '".$this->con->escape($user_email)."' "; $rs = $this->con->select($strReq); if ($rs->isEmpty()) { throw new Exception(__('That user does not exist in the database.')); } $key = md5(uniqid()); $cur = $this->con->openCursor($this->user_table); $cur->user_recover_key = $key; $cur->update("WHERE user_id = '".$this->con->escape($user_id)."'"); return $key; } /** * Creates a new user password using recovery key. Returns an array: * * - user_email * - user_id * - new_pass * * @param string $recover_key Recovery key * @return array */ public function recoverUserPassword($recover_key) { $strReq = 'SELECT user_id, user_email '. 'FROM '.$this->user_table.' '. "WHERE user_recover_key = '".$this->con->escape($recover_key)."' "; $rs = $this->con->select($strReq); if ($rs->isEmpty()) { throw new Exception(__('That key does not exist in the database.')); } $new_pass = crypt::createPassword(); $cur = $this->con->openCursor($this->user_table); $cur->user_pwd = $this->crypt($new_pass); $cur->user_recover_key = null; $cur->update("WHERE user_recover_key = '".$this->con->escape($recover_key)."'"); return array('user_email' => $rs->user_email, 'user_id' => $rs->user_id, 'new_pass' => $new_pass); } //@} /** @name User management callbacks This 3 functions only matter if you extend this class and use DC_AUTH_CLASS constant. These are called after core user management functions. Could be useful if you need to add/update/remove stuff in your LDAP directory or other third party authentication database. */ //@{ /** * Called after core->addUser * @see dcCore::addUser * @param cursor $cur User cursor */ public function afterAddUser($cur) {} /** * Called after core->updUser * @see dcCore::updUser * @param string $id User ID * @param cursor $cur User cursor */ public function afterUpdUser($id,$cur) {} /** * Called after core->delUser * @see dcCore::delUser * @param string $id User ID */ public function afterDelUser($id) {} //@} }