diff options
Diffstat (limited to 'inc/auth')
-rw-r--r-- | inc/auth/ad.class.php | 98 | ||||
-rw-r--r-- | inc/auth/basic.class.php | 2 | ||||
-rw-r--r-- | inc/auth/ldap.class.php | 111 | ||||
-rw-r--r-- | inc/auth/mysql.class.php | 3 | ||||
-rw-r--r-- | inc/auth/pgsql.class.php | 3 | ||||
-rw-r--r-- | inc/auth/plain.class.php | 29 |
6 files changed, 221 insertions, 25 deletions
diff --git a/inc/auth/ad.class.php b/inc/auth/ad.class.php index 9915b9f11..9ae6dbbd1 100644 --- a/inc/auth/ad.class.php +++ b/inc/auth/ad.class.php @@ -26,6 +26,10 @@ * $conf['auth']['ad']['use_ssl'] = 1; * $conf['auth']['ad']['debug'] = 1; * + * // get additional informations to the userinfo array + * // add a list of comma separated ldap contact fields. + * $conf['auth']['ad']['additional'] = 'field1,field2'; + * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author James Van Lommel <jamesvl@gmail.com> * @link http://www.nosq.com/blog/2005/08/ldap-activedirectory-and-dokuwiki/ @@ -38,6 +42,7 @@ class auth_ad extends auth_basic { var $cnf = null; var $opts = null; var $adldap = null; + var $users = null; /** * Constructor @@ -46,6 +51,12 @@ class auth_ad extends auth_basic { global $conf; $this->cnf = $conf['auth']['ad']; + // additional information fields + if (isset($this->cnf['additional'])) { + $this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']); + $this->cnf['additional'] = explode(',', $this->cnf['additional']); + } else $this->cnf['additional'] = array(); + // ldap extension is needed if (!function_exists('ldap_connect')) { if ($this->cnf['debug']) @@ -130,15 +141,27 @@ class auth_ad extends auth_basic { global $conf; if(!$this->_init()) return false; - //get info for given user - $result = $this->adldap->user_info($user); + $fields = array('mail','displayname','samaccountname'); + // add additional fields to read + $fields = array_merge($fields, $this->cnf['additional']); + $fields = array_unique($fields); + + //get info for given user + $result = $this->adldap->user_info($user, $fields); //general user info $info['name'] = $result[0]['displayname'][0]; $info['mail'] = $result[0]['mail'][0]; $info['uid'] = $result[0]['samaccountname'][0]; $info['dn'] = $result[0]['dn']; + // additional informations + foreach ($this->cnf['additional'] as $field) { + if (isset($result[0][strtolower($field)])) { + $info[$field] = $result[0][strtolower($field)][0]; + } + } + // handle ActiveDirectory memberOf $info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']); @@ -185,6 +208,45 @@ class auth_ad extends auth_basic { } /** + * Bulk retrieval of user data + * + * @author Dominik Eckelmann <dokuwiki@cosmocode.de> + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs, null for no filter + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=-1,$filter=array()) { + if(!$this->_init()) return false; + + if ($this->users === null) { + //get info for given user + $result = $this->adldap->all_users(); + if (!$result) return array(); + $this->users = array_fill_keys($result, false); + } + + $i = 0; + $count = 0; + $this->_constructPattern($filter); + $result = array(); + + foreach ($this->users as $user => &$info) { + if ($i++ < $start) { + continue; + } + if ($info === false) { + $info = $this->getUserData($user); + } + if ($this->_filter($user, $info)) { + $result[$user] = $info; + if (($limit >= 0) && (++$count >= $limit)) break; + } + } + return $result; + } + + /** * Initialize the AdLDAP library and connect to the server */ function _init(){ @@ -193,13 +255,45 @@ class auth_ad extends auth_basic { // connect try { $this->adldap = new adLDAP($this->opts); + if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) { + $this->canDo['getUsers'] = true; + } return true; } catch (adLDAPException $e) { + if ($this->cnf['debug']) { + msg($e->getMessage(), -1); + } $this->success = false; $this->adldap = null; } return false; } + + /** + * return 1 if $user + $info match $filter criteria, 0 otherwise + * + * @author Chris Smith <chris@jalakai.co.uk> + */ + function _filter($user, $info) { + foreach ($this->_pattern as $item => $pattern) { + if ($item == 'user') { + if (!preg_match($pattern, $user)) return 0; + } else if ($item == 'grps') { + if (!count(preg_grep($pattern, $info['grps']))) return 0; + } else { + if (!preg_match($pattern, $info[$item])) return 0; + } + } + return 1; + } + + function _constructPattern($filter) { + $this->_pattern = array(); + foreach ($filter as $item => $pattern) { +// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters + $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + } + } } //Setup VIM: ex: et ts=4 enc=utf-8 : diff --git a/inc/auth/basic.class.php b/inc/auth/basic.class.php index c08422488..fa38970ae 100644 --- a/inc/auth/basic.class.php +++ b/inc/auth/basic.class.php @@ -30,7 +30,7 @@ class auth_basic { 'getUserCount'=> false, // can the number of users be retrieved? 'getGroups' => false, // can a list of available groups be retrieved? 'external' => false, // does the module do external auth checking? - 'logoff' => false, // has the module some special logoff method? + 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) ); diff --git a/inc/auth/ldap.class.php b/inc/auth/ldap.class.php index c51924135..5cc186ce2 100644 --- a/inc/auth/ldap.class.php +++ b/inc/auth/ldap.class.php @@ -27,7 +27,9 @@ class auth_ldap extends auth_basic { return; } - if(empty($this->cnf['groupkey'])) $this->cnf['groupkey'] = 'cn'; + if(empty($this->cnf['groupkey'])) $this->cnf['groupkey'] = 'cn'; + if(empty($this->cnf['userscope'])) $this->cnf['userscope'] = 'sub'; + if(empty($this->cnf['groupscope'])) $this->cnf['groupscope'] = 'sub'; // auth_ldap currently just handles authentication, so no // capabilities are set @@ -171,7 +173,7 @@ class auth_ldap extends auth_basic { $filter = "(ObjectClass=*)"; } - $sr = @ldap_search($this->con, $base, $filter); + $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['userscope']); $result = @ldap_get_entries($this->con, $sr); if($this->cnf['debug']){ msg('LDAP user search: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__); @@ -216,10 +218,10 @@ class auth_ldap extends auth_basic { $user_result = array_merge($info,$user_result); //get groups for given user if grouptree is given - if ($this->cnf['grouptree'] && $this->cnf['groupfilter']) { + if ($this->cnf['grouptree'] || $this->cnf['groupfilter']) { $base = $this->_makeFilter($this->cnf['grouptree'], $user_result); $filter = $this->_makeFilter($this->cnf['groupfilter'], $user_result); - $sr = @ldap_search($this->con, $base, $filter, array($this->cnf['groupkey'])); + $sr = $this->_ldapsearch($this->con, $base, $filter, $this->cnf['groupscope'], array($this->cnf['groupkey'])); if(!$sr){ msg("LDAP: Reading group memberships failed",-1); if($this->cnf['debug']){ @@ -255,6 +257,58 @@ class auth_ldap extends auth_basic { } /** + * Bulk retrieval of user data + * + * @author Dominik Eckelmann <dokuwiki@cosmocode.de> + * @param start index of first user to be returned + * @param limit max number of users to be returned + * @param filter array of field/pattern pairs, null for no filter + * @return array of userinfo (refer getUserData for internal userinfo details) + */ + function retrieveUsers($start=0,$limit=-1,$filter=array()) { + if(!$this->_openLDAP()) return false; + + if (!isset($this->users)) { + // Perform the search and grab all their details + if(!empty($this->cnf['userfilter'])) { + $all_filter = str_replace('%{user}', '*', $this->cnf['userfilter']); + } else { + $all_filter = "(ObjectClass=*)"; + } + $sr=ldap_search($this->con,$this->cnf['usertree'],$all_filter); + $entries = ldap_get_entries($this->con, $sr); + $users_array = array(); + for ($i=0; $i<$entries["count"]; $i++){ + array_push($users_array, $entries[$i]["uid"][0]); + } + asort($users_array); + $result = $users_array; + if (!$result) return array(); + $this->users = array_fill_keys($result, false); + } + $i = 0; + $count = 0; + $this->_constructPattern($filter); + $result = array(); + + foreach ($this->users as $user => &$info) { + if ($i++ < $start) { + continue; + } + if ($info === false) { + $info = $this->getUserData($user); + } + if ($this->_filter($user, $info)) { + $result[$user] = $info; + if (($limit >= 0) && (++$count >= $limit)) break; + } + } + return $result; + + + } + + /** * Make LDAP filter strings. * * Used by auth_getUserData to make the filter @@ -283,6 +337,32 @@ class auth_ldap extends auth_basic { } /** + * return 1 if $user + $info match $filter criteria, 0 otherwise + * + * @author Chris Smith <chris@jalakai.co.uk> + */ + function _filter($user, $info) { + foreach ($this->_pattern as $item => $pattern) { + if ($item == 'user') { + if (!preg_match($pattern, $user)) return 0; + } else if ($item == 'grps') { + if (!count(preg_grep($pattern, $info['grps']))) return 0; + } else { + if (!preg_match($pattern, $info[$item])) return 0; + } + } + return 1; + } + + function _constructPattern($filter) { + $this->_pattern = array(); + foreach ($filter as $item => $pattern) { +// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters + $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters + } + } + + /** * Escape a string to be used in a LDAP filter * * Ported from Perl's Net::LDAP::Util escape_filter_value @@ -350,8 +430,31 @@ class auth_ldap extends auth_basic { } } + $this->canDo['getUsers'] = true; return true; } + + /** + * Wraps around ldap_search, ldap_list or ldap_read depending on $scope + * + * @param $scope string - can be 'base', 'one' or 'sub' + * @author Andreas Gohr <andi@splitbrain.org> + */ + function _ldapsearch($link_identifier, $base_dn, $filter, $scope='sub', $attributes=null, + $attrsonly=0, $sizelimit=0, $timelimit=0, $deref=LDAP_DEREF_NEVER){ + if(is_null($attributes)) $attributes = array(); + + if($scope == 'base'){ + return @ldap_read($link_identifier, $base_dn, $filter, $attributes, + $attrsonly, $sizelimit, $timelimit, $deref); + }elseif($scope == 'one'){ + return @ldap_list($link_identifier, $base_dn, $filter, $attributes, + $attrsonly, $sizelimit, $timelimit, $deref); + }else{ + return @ldap_search($link_identifier, $base_dn, $filter, $attributes, + $attrsonly, $sizelimit, $timelimit, $deref); + } + } } //Setup VIM: ex: et ts=4 enc=utf-8 : diff --git a/inc/auth/mysql.class.php b/inc/auth/mysql.class.php index b1c6a3a52..ca607ced5 100644 --- a/inc/auth/mysql.class.php +++ b/inc/auth/mysql.class.php @@ -8,9 +8,6 @@ * @author Matthias Grimm <matthias.grimmm@sourceforge.net> */ -define('DOKU_AUTH', dirname(__FILE__)); -require_once(DOKU_AUTH.'/basic.class.php'); - class auth_mysql extends auth_basic { var $dbcon = 0; diff --git a/inc/auth/pgsql.class.php b/inc/auth/pgsql.class.php index a6da56af5..8e68e865e 100644 --- a/inc/auth/pgsql.class.php +++ b/inc/auth/pgsql.class.php @@ -11,8 +11,7 @@ * @author Matthias Grimm <matthias.grimmm@sourceforge.net> */ -define('DOKU_AUTH', dirname(__FILE__)); -require_once(DOKU_AUTH.'/mysql.class.php'); +require_once(DOKU_INC.'inc/auth/mysql.class.php'); class auth_pgsql extends auth_mysql { diff --git a/inc/auth/plain.class.php b/inc/auth/plain.class.php index 96649e3c4..ec9e52beb 100644 --- a/inc/auth/plain.class.php +++ b/inc/auth/plain.class.php @@ -7,11 +7,6 @@ * @author Chris Smith <chris@jalakai.co.uk> */ -define('DOKU_AUTH', dirname(__FILE__)); -require_once(DOKU_AUTH.'/basic.class.php'); - -define('AUTH_USERFILE',DOKU_CONF.'users.auth.php'); - class auth_plain extends auth_basic { var $users = null; @@ -26,10 +21,12 @@ class auth_plain extends auth_basic { * @author Christopher Smith <chris@jalakai.co.uk> */ function auth_plain() { - if (!@is_readable(AUTH_USERFILE)){ + global $config_cascade; + + if (!@is_readable($config_cascade['plainauth.users']['default'])){ $this->success = false; }else{ - if(@is_writable(AUTH_USERFILE)){ + if(@is_writable($config_cascade['plainauth.users']['default'])){ $this->cando['addUser'] = true; $this->cando['delUser'] = true; $this->cando['modLogin'] = true; @@ -92,6 +89,7 @@ class auth_plain extends auth_basic { */ function createUser($user,$pwd,$name,$mail,$grps=null){ global $conf; + global $config_cascade; // user mustn't already exist if ($this->getUserData($user) !== false) return false; @@ -105,12 +103,13 @@ class auth_plain extends auth_basic { $groups = join(',',$grps); $userline = join(':',array($user,$pass,$name,$mail,$groups))."\n"; - if (io_saveFile(AUTH_USERFILE,$userline,true)) { + if (io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) { $this->users[$user] = compact('pass','name','mail','grps'); return $pwd; } - msg('The '.AUTH_USERFILE.' file is not writable. Please inform the Wiki-Admin',-1); + msg('The '.$config_cascade['plainauth.users']['default']. + ' file is not writable. Please inform the Wiki-Admin',-1); return null; } @@ -126,6 +125,7 @@ class auth_plain extends auth_basic { global $conf; global $ACT; global $INFO; + global $config_cascade; // sanity checks, user must already exist and there must be something to change if (($userinfo = $this->getUserData($user)) === false) return false; @@ -150,7 +150,7 @@ class auth_plain extends auth_basic { return false; } - if (!io_saveFile(AUTH_USERFILE,$userline,true)) { + if (!io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) { msg('There was an error modifying your user data. You should register again.',-1); // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page $ACT == 'register'; @@ -169,6 +169,7 @@ class auth_plain extends auth_basic { * @return int the number of users deleted */ function deleteUsers($users) { + global $config_cascade; if (!is_array($users) || empty($users)) return 0; @@ -183,7 +184,7 @@ class auth_plain extends auth_basic { $pattern = '/^('.join('|',$deleted).'):/'; - if (io_deleteFromFile(AUTH_USERFILE,$pattern,true)) { + if (io_deleteFromFile($config_cascade['plainauth.users']['default'],$pattern,true)) { foreach ($deleted as $user) unset($this->users[$user]); return count($deleted); } @@ -274,11 +275,13 @@ class auth_plain extends auth_basic { * @author Andreas Gohr <andi@splitbrain.org> */ function _loadUserData(){ + global $config_cascade; + $this->users = array(); - if(!@file_exists(AUTH_USERFILE)) return; + if(!@file_exists($config_cascade['plainauth.users']['default'])) return; - $lines = file(AUTH_USERFILE); + $lines = file($config_cascade['plainauth.users']['default']); foreach($lines as $line){ $line = preg_replace('/#.*$/','',$line); //ignore comments $line = trim($line); |