Skip to content

Commit

Permalink
Allow user info to be retrieved without groups
Browse files Browse the repository at this point in the history
Some parts of dokuwiki (e.g. recent changes, old revisions) can
requests lots of user info (to provide editor names) without
requiring any group information.

This change also implements caching of user info by authmysql &
authpgsql plugins to avoid repeated querying of the DB to retrieve
the same user information.
  • Loading branch information
Chris--S committed Mar 12, 2014
1 parent d397e6d commit 2046a65
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 31 deletions.
6 changes: 3 additions & 3 deletions inc/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ function auth_sendPassword($user, $password) {
if(!$auth) return false;

$user = $auth->cleanUser($user);
$userinfo = $auth->getUserData($user);
$userinfo = $auth->getUserData($user, DokuWiki_Auth_Plugin::IGNORE_GROUPS);

if(!$userinfo['mail']) return false;

Expand Down Expand Up @@ -1184,7 +1184,7 @@ function act_resendpwd() {
}

$user = io_readfile($tfile);
$userinfo = $auth->getUserData($user);
$userinfo = $auth->getUserData($user, DokuWiki_Auth_Plugin::IGNORE_GROUPS);
if(!$userinfo['mail']) {
msg($lang['resendpwdnouser'], -1);
return false;
Expand Down Expand Up @@ -1236,7 +1236,7 @@ function act_resendpwd() {
$user = trim($auth->cleanUser($INPUT->post->str('login')));
}

$userinfo = $auth->getUserData($user);
$userinfo = $auth->getUserData($user, DokuWiki_Auth_Plugin::IGNORE_GROUPS);
if(!$userinfo['mail']) {
msg($lang['resendpwdnouser'], -1);
return false;
Expand Down
2 changes: 1 addition & 1 deletion inc/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -1467,7 +1467,7 @@ function editorinfo($username) {
case 'username':
case 'email':
case 'email_link':
if($auth) $info = $auth->getUserData($username);
if($auth) $info = $auth->getUserData($username, DokuWiki_Auth_Plugin::IGNORE_GROUPS);
break;
default:
return hsc($username);
Expand Down
6 changes: 5 additions & 1 deletion lib/plugins/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
public $success = true;

const IGNORE_GROUPS = false;
const REQUIRE_GROUPS = true;

/**
* Possible things an auth backend module may be able to
* do. The things a backend can do need to be set to true
Expand Down Expand Up @@ -234,9 +237,10 @@ public function checkPass($user, $pass) {
*
* @author Andreas Gohr <[email protected]>
* @param string $user the user name
* @param bool $requireGroups whether or not the returned data must include groups
* @return array containing user data or false
*/
public function getUserData($user) {
public function getUserData($user, $requireGroups=true) {
if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/plugins/authad/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,10 @@ public function checkPass($user, $pass) {
*
* @author James Van Lommel <[email protected]>
* @param string $user
* @param bool $requireGroups (optional) - ignored, groups are always supplied by this plugin
* @return array
*/
public function getUserData($user) {
public function getUserData($user, $requireGroups=true) {
global $conf;
global $lang;
global $ID;
Expand Down
3 changes: 2 additions & 1 deletion lib/plugins/authldap/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,10 @@ public function checkPass($user, $pass) {
* @author Steffen Schoch <[email protected]>
*
* @param string $user
* @param bool $requireGroups (optional) - ignored, groups are always supplied by this plugin
* @return array containing user data or false
*/
public function getUserData($user) {
public function getUserData($user, $requireGroups=true) {
return $this->_getUserData($user);
}

Expand Down
147 changes: 126 additions & 21 deletions lib/plugins/authmysql/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
/** @var int database subrevision */
protected $dbsub = 0;

/** @var array cache to avoid re-reading user info data */
protected $cacheUserInfo = array();

/**
* Constructor
*
Expand Down Expand Up @@ -174,12 +177,18 @@ public function checkPass($user, $pass) {
* @author Matthias Grimm <[email protected]>
*
* @param string $user user login to get data for
* @param bool $requireGroups when true, group membership information should be included in the returned array;
* when false, it maybe included, but is not required by the caller
* @return array|bool
*/
public function getUserData($user) {
public function getUserData($user, $requireGroups=true) {
if($this->_cacheExists($user, $requireGroups)) {
return $this->cacheUserInfo[$user];
}

if($this->_openDB()) {
$this->_lockTables("READ");
$info = $this->_getUserInfo($user);
$info = $this->_getUserInfo($user, $requireGroups);
$this->_unlockTables();
$this->_closeDB();
} else
Expand Down Expand Up @@ -262,21 +271,23 @@ public function modifyUser($user, $changes) {
if($this->_openDB()) {
$this->_lockTables("WRITE");

if(($uid = $this->_getUserID($user))) {
$rc = $this->_updateUserInfo($changes, $uid);
$rc = $this->_updateUserInfo($user, $changes);

if($rc && isset($changes['grps']) && $this->cando['modGroups']) {
$groups = $this->_getGroups($user);
$grpadd = array_diff($changes['grps'], $groups);
$grpdel = array_diff($groups, $changes['grps']);
if($rc && isset($changes['grps']) && $this->cando['modGroups']) {
$groups = $this->_getGroups($user);
$grpadd = array_diff($changes['grps'], $groups);
$grpdel = array_diff($groups, $changes['grps']);

foreach($grpadd as $group)
if(($this->_addUserToGroup($user, $group, 1)) == false)
$rc = false;
foreach($grpadd as $group) {
if(($this->_addUserToGroup($user, $group, 1)) == false) {
$rc = false;
}
}

foreach($grpdel as $group)
if(($this->_delUserFromGroup($user, $group)) == false)
$rc = false;
foreach($grpdel as $group) {
if(($this->_delUserFromGroup($user, $group)) == false) {
$rc = false;
}
}
}

Expand Down Expand Up @@ -466,7 +477,10 @@ protected function _addUserToGroup($user, $group, $force = false) {
$sql = str_replace('%{user}', $this->_escape($user), $sql);
$sql = str_replace('%{gid}', $this->_escape($gid), $sql);
$sql = str_replace('%{group}', $this->_escape($group), $sql);
if($this->_modifyDB($sql) !== false) return true;
if($this->_modifyDB($sql) !== false) {
$this->_flushUserInfoCache($user);
return true;
}

if($newgroup) { // remove previously created group on error
$sql = str_replace('%{gid}', $this->_escape($gid), $this->getConf('delGroup'));
Expand Down Expand Up @@ -501,6 +515,10 @@ protected function _delUserFromGroup($user, $group) {
$sql = str_replace('%{gid}', $this->_escape($gid), $sql);
$sql = str_replace('%{group}', $this->_escape($group), $sql);
$rc = $this->_modifyDB($sql) == 0 ? true : false;

if ($rc) {
$this->_flushUserInfoCache($user);
}
}
}
return $rc;
Expand Down Expand Up @@ -590,6 +608,7 @@ protected function _addUser($user, $pwd, $name, $mail, $grps) {
}

if($gid !== false){
$this->_flushUserInfoCache($user);
return true;
} else {
/* remove the new user and all group relations if a group can't
Expand Down Expand Up @@ -626,16 +645,96 @@ protected function _delUser($user) {
$sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUser'));
$sql = str_replace('%{user}', $this->_escape($user), $sql);
$this->_modifyDB($sql);
$this->_flushUserInfoCache($user);
return true;
}
}
return false;
}

/**
* Flush cached user information
*
* @author Christopher Smith <[email protected]>
*
* @param string $user username of the user whose data is to be removed from the cache
* if null, empty the whole cache
* @return none
*/
protected function _flushUserInfoCache($user=null) {
if (is_null($user)) {
$this->cacheUserInfo = array();
} else {
unset($this->cacheUserInfo[$user]);
}
}

/**
* Quick lookup to see if a user's information has been cached
*
* This test does not need a database connection or read lock
*
* @author Christopher Smith <[email protected]>
*
* @param string $user username to be looked up in the cache
* @param bool $requireGroups true, if cached info should include group memberships
*
* @return bool existence of required user information in the cache
*/
protected function _cacheExists($user, $requireGroups=true) {
if (isset($this->cacheUserInfo[$user])) {
if (!is_array($this->cacheUserInfo[$user])) {
return true; // user doesn't exist
}

if (!$requireGroups || isset($this->cacheUserInfo[$user]['grps'])) {
return true;
}
}

return false;
}

/**
* getUserInfo
* Get a user's information
*
* The database connection must already be established for this function to work.
*
* @author Christopher Smith <[email protected]>
*
* @param string $user username of the user whose information is being reterieved
* @param bool $requireGroups true if group memberships should be included
* @param bool $useCache true if ok to return cached data & to cache returned data
*
* @return mixed false|array false if the user doesn't exist
* array containing user information if user does exist
*/
protected function _getUserInfo($user, $requireGroups=true, $useCache=true) {
$info = null;

if ($useCache && isset($this->cacheUserInfo[$user])) {
$info = $this->cacheUserInfo[$user];
}

if (is_null($info)) {
$info = $this->_retrieveUserInfo($user);
}

if ($requireGroups && $info && !isset($info['grps'])) {
$info['grps'] = $this->_getGroups($user);
}

if ($useCache) {
$this->cacheUserInfo[$user] = $info;
}

return $info;
}

/**
* retrieveUserInfo
*
* Gets the data for a specific user The database connection
* Gets the data for a specific user. The database connection
* must already be established for this function to work.
* Otherwise it will return 'false'.
*
Expand All @@ -644,12 +743,11 @@ protected function _delUser($user) {
* @param string $user user's nick to get data for
* @return bool|array false on error, user info on success
*/
protected function _getUserInfo($user) {
protected function _retrieveUserInfo($user) {
$sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserInfo'));
$result = $this->_queryDB($sql);
if($result !== false && count($result)) {
$info = $result[0];
$info['grps'] = $this->_getGroups($user);
return $info;
}
return false;
Expand All @@ -666,20 +764,26 @@ protected function _getUserInfo($user) {
* The database connection has already to be established for this
* function to work. Otherwise it will return 'false'.
*
* The password will be crypted if necessary.
* The password will be encrypted if necessary.
*
* @param string $user user's nick being updated
* @param array $changes array of items to change as pairs of item and value
* @param mixed $uid user id of dataset to change, must be unique in DB
* @return bool true on success or false on error
*
* @author Matthias Grimm <[email protected]>
*/
protected function _updateUserInfo($changes, $uid) {
protected function _updateUserInfo($user, $changes) {
$sql = $this->getConf('updateUser')." ";
$cnt = 0;
$err = 0;

if($this->dbcon) {
$uid = $this->_getUserID($user);
if ($uid === false) {
return false;
}

foreach($changes as $item => $value) {
if($item == 'user') {
if(($this->_getUserID($changes['user']))) {
Expand Down Expand Up @@ -707,6 +811,7 @@ protected function _updateUserInfo($changes, $uid) {
$sql .= " ".str_replace('%{uid}', $uid, $this->getConf('UpdateTarget'));
if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp.
$this->_modifyDB($sql);
$this->_flushUserInfoCache($user);
}
return true;
}
Expand Down
8 changes: 6 additions & 2 deletions lib/plugins/authpgsql/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public function retrieveUsers($first = 0, $limit = 0, $filter = array()) {
$result = $this->_queryDB($sql);

foreach($result as $user)
if(($info = $this->_getUserInfo($user['user'])))
if(($info = $this->_getCachedUserInfo($user['user'])))
$out[$user['user']] = $info;

$this->_unlockTables();
Expand Down Expand Up @@ -212,7 +212,10 @@ protected function _addUserToGroup($user, $group, $force = false) {
$sql = str_replace('%{user}', addslashes($user), $sql);
$sql = str_replace('%{gid}', addslashes($gid), $sql);
$sql = str_replace('%{group}', addslashes($group), $sql);
if($this->_modifyDB($sql) !== false) return true;
if($this->_modifyDB($sql) !== false) {
$this->_flushUserInfoCache($user);
return true;
}

if($newgroup) { // remove previously created group on error
$sql = str_replace('%{gid}', addslashes($gid), $this->conf['delGroup']);
Expand Down Expand Up @@ -267,6 +270,7 @@ protected function _addUser($user, $pwd, $name, $mail, $grps) {
}

if($gid !== false){
$this->_flushUserInfoCache($user);
return true;
} else {
/* remove the new user and all group relations if a group can't
Expand Down
3 changes: 2 additions & 1 deletion lib/plugins/authplain/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ public function checkPass($user, $pass) {
*
* @author Andreas Gohr <[email protected]>
* @param string $user
* @param bool $requireGroups (optional) ignored by this plugin, grps info always supplied
* @return array|bool
*/
public function getUserData($user) {
public function getUserData($user, $requireGroups=true) {
if($this->users === null) $this->_loadUserData();
return isset($this->users[$user]) ? $this->users[$user] : false;
}
Expand Down

0 comments on commit 2046a65

Please sign in to comment.