diff --git a/inc/auth.php b/inc/auth.php index b11a14d505207d6b37ab32bd169228b335a6037d..aac7a2fcafe0e678866e55bcd2cf378a508995b3 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -45,35 +45,19 @@ function auth_setup(){ $plugins = $plugin_controller->getList('auth'); foreach ($plugin_controller->getList('auth') as $plugin) { if ($conf['authtype'] === $plugin) { - $auth = $plugin_controller->load('auth', $plugin)->getAuth(); + $auth = $plugin_controller->load('auth', $plugin); break; } } - if (!$auth) { - // load the the backend auth functions and instantiate the auth object XXX - if (@file_exists(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php')) { - require_once(DOKU_INC.'inc/auth/basic.class.php'); - require_once(DOKU_INC.'inc/auth/'.$conf['authtype'].'.class.php'); - - $auth_class = "auth_".$conf['authtype']; - if (class_exists($auth_class)) { - $auth = new $auth_class(); - if ($auth->success == false) { - // degrade to unauthenticated user - unset($auth); - auth_logoff(); - msg($lang['authtempfail'], -1); - } - } else { - nice_die($lang['authmodfailed']); - } - } else { - nice_die($lang['authmodfailed']); - } - } + if(!$auth) return; - if(!$auth) return; + if ($auth && $auth->success == false) { + // degrade to unauthenticated user + unset($auth); + auth_logoff(); + msg($lang['authtempfail'], -1); + } // do the login either by cookie or provided credentials XXX if (!isset($_REQUEST['u'])) $_REQUEST['u'] = ''; @@ -102,7 +86,10 @@ function auth_setup(){ } // apply cleaning - $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + if (true === $auth->success) + { + $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + } if(isset($_REQUEST['authtok'])){ // when an authentication token is given, trust the session diff --git a/inc/auth/basic.class.php b/inc/auth/basic.class.php deleted file mode 100644 index c7e7031bfe80ea7f61b28163313c80ad95776f33..0000000000000000000000000000000000000000 --- a/inc/auth/basic.class.php +++ /dev/null @@ -1,403 +0,0 @@ -<?php -/** - * auth/basic.class.php - * - * foundation authorisation class - * all auth classes should inherit from this class - * - * @author Chris Smith <chris@jalakai.co.uk> - */ - -class auth_basic { - - var $success = true; - - - /** - * Posible things an auth backend module may be able to - * do. The things a backend can do need to be set to true - * in the constructor. - */ - var $cando = array ( - 'addUser' => false, // can Users be created? - 'delUser' => false, // can Users be deleted? - 'modLogin' => false, // can login names be changed? - 'modPass' => false, // can passwords be changed? - 'modName' => false, // can real names be changed? - 'modMail' => false, // can emails be changed? - 'modGroups' => false, // can groups be changed? - 'getUsers' => false, // can a (filtered) list of users be retrieved? - '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? - 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) - ); - - - /** - * Constructor. - * - * Carry out sanity checks to ensure the object is - * able to operate. Set capabilities in $this->cando - * array here - * - * Set $this->success to false if checks fail - * - * @author Christopher Smith <chris@jalakai.co.uk> - */ - function auth_basic() { - // the base class constructor does nothing, derived class - // constructors do the real work - } - - /** - * Capability check. [ DO NOT OVERRIDE ] - * - * Checks the capabilities set in the $this->cando array and - * some pseudo capabilities (shortcutting access to multiple - * ones) - * - * ususal capabilities start with lowercase letter - * shortcut capabilities start with uppercase letter - * - * @author Andreas Gohr <andi@splitbrain.org> - * @return bool - */ - function canDo($cap) { - switch($cap){ - case 'Profile': - // can at least one of the user's properties be changed? - return ( $this->cando['modPass'] || - $this->cando['modName'] || - $this->cando['modMail'] ); - break; - case 'UserMod': - // can at least anything be changed? - return ( $this->cando['modPass'] || - $this->cando['modName'] || - $this->cando['modMail'] || - $this->cando['modLogin'] || - $this->cando['modGroups'] || - $this->cando['modMail'] ); - break; - default: - // print a helping message for developers - if(!isset($this->cando[$cap])){ - msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?",-1); - } - return $this->cando[$cap]; - } - } - - /** - * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ] - * - * You should use this function instead of calling createUser, modifyUser or - * deleteUsers directly. The event handlers can prevent the modification, for - * example for enforcing a user name schema. - * - * @author Gabriel Birke <birke@d-scribe.de> - * @param string $type Modification type ('create', 'modify', 'delete') - * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type - * @return mixed Result from the modification function or false if an event handler has canceled the action - */ - function triggerUserMod($type, $params) - { - $validTypes = array( - 'create' => 'createUser', - 'modify' => 'modifyUser', - 'delete' => 'deleteUsers' - ); - if(empty($validTypes[$type])) - return false; - $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null); - $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata); - if ($evt->advise_before(true)) { - $result = call_user_func_array(array($this, $validTypes[$type]), $params); - $evt->data['modification_result'] = $result; - } - $evt->advise_after(); - unset($evt); - return $result; - } - - /** - * Log off the current user [ OPTIONAL ] - * - * Is run in addition to the ususal logoff method. Should - * only be needed when trustExternal is implemented. - * - * @see auth_logoff() - * @author Andreas Gohr <andi@splitbrain.org> - */ - function logOff(){ - } - - /** - * Do all authentication [ OPTIONAL ] - * - * Set $this->cando['external'] = true when implemented - * - * If this function is implemented it will be used to - * authenticate a user - all other DokuWiki internals - * will not be used for authenticating, thus - * implementing the checkPass() function is not needed - * anymore. - * - * The function can be used to authenticate against third - * party cookies or Apache auth mechanisms and replaces - * the auth_login() function - * - * The function will be called with or without a set - * username. If the Username is given it was called - * from the login form and the given credentials might - * need to be checked. If no username was given it - * the function needs to check if the user is logged in - * by other means (cookie, environment). - * - * The function needs to set some globals needed by - * DokuWiki like auth_login() does. - * - * @see auth_login() - * @author Andreas Gohr <andi@splitbrain.org> - * - * @param string $user Username - * @param string $pass Cleartext Password - * @param bool $sticky Cookie should not expire - * @return bool true on successful auth - */ - function trustExternal($user,$pass,$sticky=false){ -# // some example: -# -# global $USERINFO; -# global $conf; -# $sticky ? $sticky = true : $sticky = false; //sanity check -# -# // do the checking here -# -# // set the globals if authed -# $USERINFO['name'] = 'FIXME'; -# $USERINFO['mail'] = 'FIXME'; -# $USERINFO['grps'] = array('FIXME'); -# $_SERVER['REMOTE_USER'] = $user; -# $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; -# $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass; -# $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; -# return true; - } - - /** - * Check user+password [ MUST BE OVERRIDDEN ] - * - * Checks if the given user exists and the given - * plaintext password is correct - * - * May be ommited if trustExternal is used. - * - * @author Andreas Gohr <andi@splitbrain.org> - * @return bool - */ - function checkPass($user,$pass){ - msg("no valid authorisation system in use", -1); - return false; - } - - /** - * Return user info [ MUST BE OVERRIDDEN ] - * - * Returns info about the given user needs to contain - * at least these fields: - * - * name string full name of the user - * mail string email addres of the user - * grps array list of groups the user is in - * - * @author Andreas Gohr <andi@splitbrain.org> - * @return array containing user data or false - */ - function getUserData($user) { - if(!$this->cando['external']) msg("no valid authorisation system in use", -1); - return false; - } - - /** - * Create a new User [implement only where required/possible] - * - * Returns false if the user already exists, null when an error - * occurred and true if everything went well. - * - * The new user HAS TO be added to the default group by this - * function! - * - * Set addUser capability when implemented - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function createUser($user,$pass,$name,$mail,$grps=null){ - msg("authorisation method does not allow creation of new users", -1); - return null; - } - - /** - * Modify user data [implement only where required/possible] - * - * Set the mod* capabilities according to the implemented features - * - * @author Chris Smith <chris@jalakai.co.uk> - * @param $user nick of the user to be changed - * @param $changes array of field/value pairs to be changed (password will be clear text) - * @return bool - */ - function modifyUser($user, $changes) { - msg("authorisation method does not allow modifying of user data", -1); - return false; - } - - /** - * Delete one or more users [implement only where required/possible] - * - * Set delUser capability when implemented - * - * @author Chris Smith <chris@jalakai.co.uk> - * @param array $users - * @return int number of users deleted - */ - function deleteUsers($users) { - msg("authorisation method does not allow deleting of users", -1); - return false; - } - - /** - * Return a count of the number of user which meet $filter criteria - * [should be implemented whenever retrieveUsers is implemented] - * - * Set getUserCount capability when implemented - * - * @author Chris Smith <chris@jalakai.co.uk> - */ - function getUserCount($filter=array()) { - msg("authorisation method does not provide user counts", -1); - return 0; - } - - /** - * Bulk retrieval of user data [implement only where required/possible] - * - * Set getUsers capability when implemented - * - * @author Chris Smith <chris@jalakai.co.uk> - * @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=null) { - msg("authorisation method does not support mass retrieval of user data", -1); - return array(); - } - - /** - * Define a group [implement only where required/possible] - * - * Set addGroup capability when implemented - * - * @author Chris Smith <chris@jalakai.co.uk> - * @return bool - */ - function addGroup($group) { - msg("authorisation method does not support independent group creation", -1); - return false; - } - - /** - * Retrieve groups [implement only where required/possible] - * - * Set getGroups capability when implemented - * - * @author Chris Smith <chris@jalakai.co.uk> - * @return array - */ - function retrieveGroups($start=0,$limit=0) { - msg("authorisation method does not support group list retrieval", -1); - return array(); - } - - /** - * Return case sensitivity of the backend [OPTIONAL] - * - * When your backend is caseinsensitive (eg. you can login with USER and - * user) then you need to overwrite this method and return false - */ - function isCaseSensitive(){ - return true; - } - - /** - * Sanitize a given username [OPTIONAL] - * - * This function is applied to any user name that is given to - * the backend and should also be applied to any user name within - * the backend before returning it somewhere. - * - * This should be used to enforce username restrictions. - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $user - username - * @param string - the cleaned username - */ - function cleanUser($user){ - return $user; - } - - /** - * Sanitize a given groupname [OPTIONAL] - * - * This function is applied to any groupname that is given to - * the backend and should also be applied to any groupname within - * the backend before returning it somewhere. - * - * This should be used to enforce groupname restrictions. - * - * Groupnames are to be passed without a leading '@' here. - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $group - groupname - * @param string - the cleaned groupname - */ - function cleanGroup($group){ - return $group; - } - - - /** - * Check Session Cache validity [implement only where required/possible] - * - * DokuWiki caches user info in the user's session for the timespan defined - * in $conf['auth_security_timeout']. - * - * This makes sure slow authentication backends do not slow down DokuWiki. - * This also means that changes to the user database will not be reflected - * on currently logged in users. - * - * To accommodate for this, the user manager plugin will touch a reference - * file whenever a change is submitted. This function compares the filetime - * of this reference file with the time stored in the session. - * - * This reference file mechanism does not reflect changes done directly in - * the backend's database through other means than the user manager plugin. - * - * Fast backends might want to return always false, to force rechecks on - * each page load. Others might want to use their own checking here. If - * unsure, do not override. - * - * @param string $user - The username - * @author Andreas Gohr <andi@splitbrain.org> - * @return bool - */ - function useSessionCache($user){ - global $conf; - return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge')); - } - -} -//Setup VIM: ex: et ts=2 : diff --git a/inc/auth/pgsql.class.php b/inc/auth/pgsql.class.php deleted file mode 100644 index cf8bf76000282cfab9b71d08d36e9e584229cf4e..0000000000000000000000000000000000000000 --- a/inc/auth/pgsql.class.php +++ /dev/null @@ -1,410 +0,0 @@ -<?php -/** - * PgSQL authentication backend - * - * This class inherits much functionality from the MySQL class - * and just reimplements the Postgres specific parts. - * - * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) - * @author Andreas Gohr <andi@splitbrain.org> - * @author Chris Smith <chris@jalakai.co.uk> - * @author Matthias Grimm <matthias.grimmm@sourceforge.net> -*/ - -require_once(DOKU_INC.'inc/auth/mysql.class.php'); - -class auth_pgsql extends auth_mysql { - - /** - * Constructor - * - * checks if the pgsql interface is available, otherwise it will - * set the variable $success of the basis class to false - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - * @author Andreas Gohr <andi@splitbrain.org> - */ - function auth_pgsql() { - global $conf; - $this->cnf = $conf['auth']['pgsql']; - if(!$this->cnf['port']) $this->cnf['port'] = 5432; - - if (method_exists($this, 'auth_basic')) - parent::auth_basic(); - - if(!function_exists('pg_connect')) { - if ($this->cnf['debug']) - msg("PgSQL err: PHP Postgres extension not found.",-1); - $this->success = false; - return; - } - - $this->defaultgroup = $conf['defaultgroup']; - - // set capabilities based upon config strings set - if (empty($this->cnf['user']) || - empty($this->cnf['password']) || empty($this->cnf['database'])){ - if ($this->cnf['debug']) - msg("PgSQL err: insufficient configuration.",-1,__LINE__,__FILE__); - $this->success = false; - return; - } - - $this->cando['addUser'] = $this->_chkcnf(array('getUserInfo', - 'getGroups', - 'addUser', - 'getUserID', - 'getGroupID', - 'addGroup', - 'addUserGroup')); - $this->cando['delUser'] = $this->_chkcnf(array('getUserID', - 'delUser', - 'delUserRefs')); - $this->cando['modLogin'] = $this->_chkcnf(array('getUserID', - 'updateUser', - 'UpdateTarget')); - $this->cando['modPass'] = $this->cando['modLogin']; - $this->cando['modName'] = $this->cando['modLogin']; - $this->cando['modMail'] = $this->cando['modLogin']; - $this->cando['modGroups'] = $this->_chkcnf(array('getUserID', - 'getGroups', - 'getGroupID', - 'addGroup', - 'addUserGroup', - 'delGroup', - 'getGroupID', - 'delUserGroup')); - /* getGroups is not yet supported - $this->cando['getGroups'] = $this->_chkcnf(array('getGroups', - 'getGroupID')); */ - $this->cando['getUsers'] = $this->_chkcnf(array('getUsers', - 'getUserInfo', - 'getGroups')); - $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers')); - } - - /** - * Check if the given config strings are set - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - * @return bool - */ - function _chkcnf($keys, $wop=false){ - foreach ($keys as $key){ - if (empty($this->cnf[$key])) return false; - } - return true; - } - - // @inherit function checkPass($user,$pass) - // @inherit function getUserData($user) - // @inherit function createUser($user,$pwd,$name,$mail,$grps=null) - // @inherit function modifyUser($user, $changes) - // @inherit function deleteUsers($users) - - - /** - * [public function] - * - * Counts users which meet certain $filter criteria. - * - * @param array $filter filter criteria in item/pattern pairs - * @return count of found users. - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function getUserCount($filter=array()) { - $rc = 0; - - if($this->_openDB()) { - $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); - - // no equivalent of SQL_CALC_FOUND_ROWS in pgsql? - if (($result = $this->_queryDB($sql))){ - $rc = count($result); - } - $this->_closeDB(); - } - return $rc; - } - - /** - * Bulk retrieval of user data. [public function] - * - * @param first index of first user to be returned - * @param limit max number of users to be returned - * @param filter array of field/pattern pairs - * @return array of userinfo (refer getUserData for internal userinfo details) - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function retrieveUsers($first=0,$limit=10,$filter=array()) { - $out = array(); - - if($this->_openDB()) { - $this->_lockTables("READ"); - $sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter); - $sql .= " ".$this->cnf['SortOrder']." LIMIT $limit OFFSET $first"; - $result = $this->_queryDB($sql); - - foreach ($result as $user) - if (($info = $this->_getUserInfo($user['user']))) - $out[$user['user']] = $info; - - $this->_unlockTables(); - $this->_closeDB(); - } - return $out; - } - - // @inherit function joinGroup($user, $group) - // @inherit function leaveGroup($user, $group) { - - /** - * Adds a user to a group. - * - * If $force is set to '1' non existing groups would be created. - * - * The database connection must already be established. Otherwise - * this function does nothing and returns 'false'. - * - * @param $user user to add to a group - * @param $group name of the group - * @param $force '1' create missing groups - * @return bool 'true' on success, 'false' on error - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - * @author Andreas Gohr <andi@splitbrain.org> - */ - function _addUserToGroup($user, $group, $force=0) { - $newgroup = 0; - - if (($this->dbcon) && ($user)) { - $gid = $this->_getGroupID($group); - if (!$gid) { - if ($force) { // create missing groups - $sql = str_replace('%{group}',addslashes($group),$this->cnf['addGroup']); - $this->_modifyDB($sql); - //group should now exists try again to fetch it - $gid = $this->_getGroupID($group); - $newgroup = 1; // group newly created - } - } - if (!$gid) return false; // group didn't exist and can't be created - - $sql = $this->cnf['addUserGroup']; - if(strpos($sql,'%{uid}') !== false){ - $uid = $this->_getUserID($user); - $sql = str_replace('%{uid}', addslashes($uid), $sql); - } - $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 ($newgroup) { // remove previously created group on error - $sql = str_replace('%{gid}', addslashes($gid),$this->cnf['delGroup']); - $sql = str_replace('%{group}',addslashes($group),$sql); - $this->_modifyDB($sql); - } - } - return false; - } - - // @inherit function _delUserFromGroup($user $group) - // @inherit function _getGroups($user) - // @inherit function _getUserID($user) - - /** - * Adds a new User to the database. - * - * The database connection must already be established - * for this function to work. Otherwise it will return - * 'false'. - * - * @param $user login of the user - * @param $pwd encrypted password - * @param $name full name of the user - * @param $mail email address - * @param $grps array of groups the user should become member of - * @return bool - * - * @author Andreas Gohr <andi@splitbrain.org> - * @author Chris Smith <chris@jalakai.co.uk> - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function _addUser($user,$pwd,$name,$mail,$grps){ - if($this->dbcon && is_array($grps)) { - $sql = str_replace('%{user}', addslashes($user),$this->cnf['addUser']); - $sql = str_replace('%{pass}', addslashes($pwd),$sql); - $sql = str_replace('%{name}', addslashes($name),$sql); - $sql = str_replace('%{email}',addslashes($mail),$sql); - if($this->_modifyDB($sql)){ - $uid = $this->_getUserID($user); - }else{ - return false; - } - - if ($uid) { - foreach($grps as $group) { - $gid = $this->_addUserToGroup($user, $group, 1); - if ($gid === false) break; - } - - if ($gid) return true; - else { - /* remove the new user and all group relations if a group can't - * be assigned. Newly created groups will remain in the database - * and won't be removed. This might create orphaned groups but - * is not a big issue so we ignore this problem here. - */ - $this->_delUser($user); - if ($this->cnf['debug']) - msg("PgSQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__); - } - } - } - return false; - } - - // @inherit function _delUser($user) - // @inherit function _getUserInfo($user) - // @inherit function _updateUserInfo($changes, $uid) - // @inherit function _getGroupID($group) - - /** - * Opens a connection to a database and saves the handle for further - * usage in the object. The successful call to this functions is - * essential for most functions in this object. - * - * @return bool - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function _openDB() { - if (!$this->dbcon) { - $dsn = $this->cnf['server'] ? 'host='.$this->cnf['server'] : ''; - $dsn .= ' port='.$this->cnf['port']; - $dsn .= ' dbname='.$this->cnf['database']; - $dsn .= ' user='.$this->cnf['user']; - $dsn .= ' password='.$this->cnf['password']; - - $con = @pg_connect($dsn); - if ($con) { - $this->dbcon = $con; - return true; // connection and database successfully opened - } else if ($this->cnf['debug']){ - msg ("PgSQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.", - -1,__LINE__,__FILE__); - } - return false; // connection failed - } - return true; // connection already open - } - - /** - * Closes a database connection. - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function _closeDB() { - if ($this->dbcon) { - pg_close ($this->dbcon); - $this->dbcon = 0; - } - } - - /** - * Sends a SQL query to the database and transforms the result into - * an associative array. - * - * This function is only able to handle queries that returns a - * table such as SELECT. - * - * @param $query SQL string that contains the query - * @return array with the result table - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function _queryDB($query) { - if ($this->dbcon) { - $result = @pg_query($this->dbcon,$query); - if ($result) { - while (($t = pg_fetch_assoc($result)) !== false) - $resultarray[]=$t; - pg_free_result ($result); - return $resultarray; - }elseif ($this->cnf['debug']) - msg('PgSQL err: '.pg_last_error($this->dbcon),-1,__LINE__,__FILE__); - } - return false; - } - - /** - * Executes an update or insert query. This differs from the - * MySQL one because it does NOT return the last insertID - * - * @author Andreas Gohr - */ - function _modifyDB($query) { - if ($this->dbcon) { - $result = @pg_query($this->dbcon,$query); - if ($result) { - pg_free_result ($result); - return true; - } - if ($this->cnf['debug']){ - msg('PgSQL err: '.pg_last_error($this->dbcon),-1,__LINE__,__FILE__); - } - } - return false; - } - - /** - * Start a transaction - * - * @param $mode could be 'READ' or 'WRITE' - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function _lockTables($mode) { - if ($this->dbcon) { - $this->_modifyDB('BEGIN'); - return true; - } - return false; - } - - /** - * Commit a transaction - * - * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> - */ - function _unlockTables() { - if ($this->dbcon) { - $this->_modifyDB('COMMIT'); - return true; - } - return false; - } - - // @inherit function _createSQLFilter($sql, $filter) - - - /** - * Escape a string for insertion into the database - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $string The string to escape - * @param boolean $like Escape wildcard chars as well? - */ - function _escape($string,$like=false){ - $string = pg_escape_string($string); - if($like){ - $string = addcslashes($string,'%_'); - } - return $string; - } - -} - -//Setup VIM: ex: et ts=2 : diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php index 3ec64018c13af7aec0068bf476e367aed9b6c4da..59631143f4061d71ee8835f0c67c08bdab49ed67 100644 --- a/lib/plugins/auth.php +++ b/lib/plugins/auth.php @@ -9,17 +9,421 @@ if(!defined('DOKU_INC')) die(); /** - * All plugins that provide Authentication should inherit from this class and implement - * the getAuth() method to make its Auth-System available. + * auth/basic.class.php * - * @author Jan Schumann <js@jschumann-it.com> + * foundation authorisation class + * all auth classes should inherit from this class + * + * @author Chris Smith <chris@jalakai.co.uk> + * @author Jan Schumann <js@jschumann-it.com> */ class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { - /** - * Retrieves the authentication system - */ - function getAuth() { - trigger_error('getAuth() not implemented in '.get_class($this), E_USER_WARNING); + var $success = true; + + + /** + * Posible things an auth backend module may be able to + * do. The things a backend can do need to be set to true + * in the constructor. + */ + var $cando = array ( + 'addUser' => false, // can Users be created? + 'delUser' => false, // can Users be deleted? + 'modLogin' => false, // can login names be changed? + 'modPass' => false, // can passwords be changed? + 'modName' => false, // can real names be changed? + 'modMail' => false, // can emails be changed? + 'modGroups' => false, // can groups be changed? + 'getUsers' => false, // can a (filtered) list of users be retrieved? + '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? + 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) + ); + + + /** + * Constructor. + * + * Carry out sanity checks to ensure the object is + * able to operate. Set capabilities in $this->cando + * array here + * + * Set $this->success to false if checks fail + * + * @author Christopher Smith <chris@jalakai.co.uk> + */ + function auth_basic() { + // the base class constructor does nothing, derived class + // constructors do the real work + } + + /** + * Capability check. [ DO NOT OVERRIDE ] + * + * Checks the capabilities set in the $this->cando array and + * some pseudo capabilities (shortcutting access to multiple + * ones) + * + * ususal capabilities start with lowercase letter + * shortcut capabilities start with uppercase letter + * + * @author Andreas Gohr <andi@splitbrain.org> + * @return bool + */ + function canDo($cap) { + switch($cap){ + case 'Profile': + // can at least one of the user's properties be changed? + return ( $this->cando['modPass'] || + $this->cando['modName'] || + $this->cando['modMail'] ); + break; + case 'UserMod': + // can at least anything be changed? + return ( $this->cando['modPass'] || + $this->cando['modName'] || + $this->cando['modMail'] || + $this->cando['modLogin'] || + $this->cando['modGroups'] || + $this->cando['modMail'] ); + break; + default: + // print a helping message for developers + if(!isset($this->cando[$cap])){ + msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?",-1); + } + return $this->cando[$cap]; + } + } + + /** + * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ] + * + * You should use this function instead of calling createUser, modifyUser or + * deleteUsers directly. The event handlers can prevent the modification, for + * example for enforcing a user name schema. + * + * @author Gabriel Birke <birke@d-scribe.de> + * @param string $type Modification type ('create', 'modify', 'delete') + * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type + * @return mixed Result from the modification function or false if an event handler has canceled the action + */ + function triggerUserMod($type, $params) + { + $validTypes = array( + 'create' => 'createUser', + 'modify' => 'modifyUser', + 'delete' => 'deleteUsers' + ); + if(empty($validTypes[$type])) + return false; + $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null); + $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata); + if ($evt->advise_before(true)) { + $result = call_user_func_array(array($this, $validTypes[$type]), $params); + $evt->data['modification_result'] = $result; } + $evt->advise_after(); + unset($evt); + return $result; + } + + /** + * Log off the current user [ OPTIONAL ] + * + * Is run in addition to the ususal logoff method. Should + * only be needed when trustExternal is implemented. + * + * @see auth_logoff() + * @author Andreas Gohr <andi@splitbrain.org> + */ + function logOff(){ + } + + /** + * Do all authentication [ OPTIONAL ] + * + * Set $this->cando['external'] = true when implemented + * + * If this function is implemented it will be used to + * authenticate a user - all other DokuWiki internals + * will not be used for authenticating, thus + * implementing the checkPass() function is not needed + * anymore. + * + * The function can be used to authenticate against third + * party cookies or Apache auth mechanisms and replaces + * the auth_login() function + * + * The function will be called with or without a set + * username. If the Username is given it was called + * from the login form and the given credentials might + * need to be checked. If no username was given it + * the function needs to check if the user is logged in + * by other means (cookie, environment). + * + * The function needs to set some globals needed by + * DokuWiki like auth_login() does. + * + * @see auth_login() + * @author Andreas Gohr <andi@splitbrain.org> + * + * @param string $user Username + * @param string $pass Cleartext Password + * @param bool $sticky Cookie should not expire + * @return bool true on successful auth + */ + function trustExternal($user,$pass,$sticky=false){ +# // some example: +# +# global $USERINFO; +# global $conf; +# $sticky ? $sticky = true : $sticky = false; //sanity check +# +# // do the checking here +# +# // set the globals if authed +# $USERINFO['name'] = 'FIXME'; +# $USERINFO['mail'] = 'FIXME'; +# $USERINFO['grps'] = array('FIXME'); +# $_SERVER['REMOTE_USER'] = $user; +# $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; +# $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass; +# $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; +# return true; + } + + /** + * Check user+password [ MUST BE OVERRIDDEN ] + * + * Checks if the given user exists and the given + * plaintext password is correct + * + * May be ommited if trustExternal is used. + * + * @author Andreas Gohr <andi@splitbrain.org> + * @return bool + */ + function checkPass($user,$pass){ + msg("no valid authorisation system in use", -1); + return false; + } + + /** + * Return user info [ MUST BE OVERRIDDEN ] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @author Andreas Gohr <andi@splitbrain.org> + * @return array containing user data or false + */ + function getUserData($user) { + if(!$this->cando['external']) msg("no valid authorisation system in use", -1); + return false; + } + + /** + * Create a new User [implement only where required/possible] + * + * Returns false if the user already exists, null when an error + * occurred and true if everything went well. + * + * The new user HAS TO be added to the default group by this + * function! + * + * Set addUser capability when implemented + * + * @author Andreas Gohr <andi@splitbrain.org> + */ + function createUser($user,$pass,$name,$mail,$grps=null){ + msg("authorisation method does not allow creation of new users", -1); + return null; + } + + /** + * Modify user data [implement only where required/possible] + * + * Set the mod* capabilities according to the implemented features + * + * @author Chris Smith <chris@jalakai.co.uk> + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed (password will be clear text) + * @return bool + */ + function modifyUser($user, $changes) { + msg("authorisation method does not allow modifying of user data", -1); + return false; + } + + /** + * Delete one or more users [implement only where required/possible] + * + * Set delUser capability when implemented + * + * @author Chris Smith <chris@jalakai.co.uk> + * @param array $users + * @return int number of users deleted + */ + function deleteUsers($users) { + msg("authorisation method does not allow deleting of users", -1); + return false; + } + + /** + * Return a count of the number of user which meet $filter criteria + * [should be implemented whenever retrieveUsers is implemented] + * + * Set getUserCount capability when implemented + * + * @author Chris Smith <chris@jalakai.co.uk> + */ + function getUserCount($filter=array()) { + msg("authorisation method does not provide user counts", -1); + return 0; + } + + /** + * Bulk retrieval of user data [implement only where required/possible] + * + * Set getUsers capability when implemented + * + * @author Chris Smith <chris@jalakai.co.uk> + * @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=null) { + msg("authorisation method does not support mass retrieval of user data", -1); + return array(); + } + + /** + * Define a group [implement only where required/possible] + * + * Set addGroup capability when implemented + * + * @author Chris Smith <chris@jalakai.co.uk> + * @return bool + */ + function addGroup($group) { + msg("authorisation method does not support independent group creation", -1); + return false; + } + + /** + * Retrieve groups [implement only where required/possible] + * + * Set getGroups capability when implemented + * + * @author Chris Smith <chris@jalakai.co.uk> + * @return array + */ + function retrieveGroups($start=0,$limit=0) { + msg("authorisation method does not support group list retrieval", -1); + return array(); + } + + /** + * Return case sensitivity of the backend [OPTIONAL] + * + * When your backend is caseinsensitive (eg. you can login with USER and + * user) then you need to overwrite this method and return false + */ + function isCaseSensitive(){ + return true; + } + + /** + * Sanitize a given username [OPTIONAL] + * + * This function is applied to any user name that is given to + * the backend and should also be applied to any user name within + * the backend before returning it somewhere. + * + * This should be used to enforce username restrictions. + * + * @author Andreas Gohr <andi@splitbrain.org> + * @param string $user - username + * @param string - the cleaned username + */ + function cleanUser($user){ + return $user; + } + + /** + * Sanitize a given groupname [OPTIONAL] + * + * This function is applied to any groupname that is given to + * the backend and should also be applied to any groupname within + * the backend before returning it somewhere. + * + * This should be used to enforce groupname restrictions. + * + * Groupnames are to be passed without a leading '@' here. + * + * @author Andreas Gohr <andi@splitbrain.org> + * @param string $group - groupname + * @param string - the cleaned groupname + */ + function cleanGroup($group){ + return $group; + } + + + /** + * Check Session Cache validity [implement only where required/possible] + * + * DokuWiki caches user info in the user's session for the timespan defined + * in $conf['auth_security_timeout']. + * + * This makes sure slow authentication backends do not slow down DokuWiki. + * This also means that changes to the user database will not be reflected + * on currently logged in users. + * + * To accommodate for this, the user manager plugin will touch a reference + * file whenever a change is submitted. This function compares the filetime + * of this reference file with the time stored in the session. + * + * This reference file mechanism does not reflect changes done directly in + * the backend's database through other means than the user manager plugin. + * + * Fast backends might want to return always false, to force rechecks on + * each page load. Others might want to use their own checking here. If + * unsure, do not override. + * + * @param string $user - The username + * @author Andreas Gohr <andi@splitbrain.org> + * @return bool + */ + function useSessionCache($user){ + global $conf; + return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge')); + } + + + /** + * loadConfig() + * merges the plugin's default settings with any local settings + * this function is automatically called through getConf() + */ + function loadConfig(){ + global $conf; + + parent::loadConfig(); + + $this->conf['debug'] = $conf['debug']; + $this->conf['useacl'] = $conf['useacl']; + $this->conf['disableactions'] = $conf['disableactions']; + $this->conf['autopasswd'] = $conf['autopasswd']; + $this->conf['passcrypt'] = $conf['ssha']; + } + } diff --git a/inc/auth/ad.class.php b/lib/plugins/authad/auth.php similarity index 90% rename from inc/auth/ad.class.php rename to lib/plugins/authad/auth.php index 1fddad243ef59efc9898e7a0bd7b51409f448a75..70d3cfb8c4b7345f7126a9d1872847b61604b328 100644 --- a/inc/auth/ad.class.php +++ b/lib/plugins/authad/auth.php @@ -1,4 +1,15 @@ <?php +/** + * Plugin auth provider + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Jan Schumann <js@schumann-it.com> + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +require_once(DOKU_INC.'inc/adLDAP.php'); + /** * Active Directory authentication backend for DokuWiki * @@ -11,35 +22,34 @@ * $conf['useacl'] = 1; * $conf['disableactions'] = 'register'; * $conf['autopasswd'] = 0; - * $conf['authtype'] = 'ad'; + * $conf['authtype'] = 'authad'; * $conf['passcrypt'] = 'ssha'; * - * $conf['auth']['ad']['account_suffix'] = '@my.domain.org'; - * $conf['auth']['ad']['base_dn'] = 'DC=my,DC=domain,DC=org'; - * $conf['auth']['ad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org'; + * $conf['plugin']['authad']['account_suffix'] = '@my.domain.org'; + * $conf['plugin']['authad']['base_dn'] = 'DC=my,DC=domain,DC=org'; + * $conf['plugin']['authad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org'; * * //optional: - * $conf['auth']['ad']['sso'] = 1; - * $conf['auth']['ad']['ad_username'] = 'root'; - * $conf['auth']['ad']['ad_password'] = 'pass'; - * $conf['auth']['ad']['real_primarygroup'] = 1; - * $conf['auth']['ad']['use_ssl'] = 1; - * $conf['auth']['ad']['use_tls'] = 1; - * $conf['auth']['ad']['debug'] = 1; + * $conf['plugin']['authad']['sso'] = 1; + * $conf['plugin']['authad']['ad_username'] = 'root'; + * $conf['plugin']['authad']['ad_password'] = 'pass'; + * $conf['plugin']['authad']['real_primarygroup'] = 1; + * $conf['plugin']['authad']['use_ssl'] = 1; + * $conf['plugin']['authad']['use_tls'] = 1; + * $conf['plugin']['authad']['debug'] = 1; * * // get additional information to the userinfo array * // add a list of comma separated ldap contact fields. - * $conf['auth']['ad']['additional'] = 'field1,field2'; + * $conf['plugin']['authad']['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/ * @author Andreas Gohr <andi@splitbrain.org> + * @author Jan Schumann <js@schumann-it.com> */ - -require_once(DOKU_INC.'inc/adLDAP.php'); - -class auth_ad extends auth_basic { +class auth_plugin_authad extends DokuWiki_Auth_Plugin +{ var $cnf = null; var $opts = null; var $adldap = null; @@ -48,7 +58,7 @@ class auth_ad extends auth_basic { /** * Constructor */ - function auth_ad() { + function auth_plugin_authad() { global $conf; $this->cnf = $conf['auth']['ad']; @@ -346,6 +356,4 @@ class auth_ad extends auth_basic { $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters } } -} - -//Setup VIM: ex: et ts=4 : +} \ No newline at end of file diff --git a/lib/plugins/authad/plugin.info.txt b/lib/plugins/authad/plugin.info.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad565b853ebc38a93243544b985790ba5c20b3e3 --- /dev/null +++ b/lib/plugins/authad/plugin.info.txt @@ -0,0 +1,7 @@ +base authad +author +email +date +name active directory auth plugin +desc Provides authentication against a Microsoft Active Directory +url diff --git a/inc/auth/ldap.class.php b/lib/plugins/authldap/auth.php similarity index 98% rename from inc/auth/ldap.class.php rename to lib/plugins/authldap/auth.php index 8eb4119955d16d39b21fee249d08aa78a2f5b2b9..723685f94c2383cf55059bf4017fff327f2bf3f0 100644 --- a/inc/auth/ldap.class.php +++ b/lib/plugins/authldap/auth.php @@ -1,13 +1,23 @@ <?php +/** + * Plugin auth provider + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Jan Schumann <js@schumann-it.com> + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + /** * LDAP authentication backend * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Andreas Gohr <andi@splitbrain.org> * @author Chris Smith <chris@jalakaic.co.uk> + * @author Jan Schumann <js@schumann-it.com> */ - -class auth_ldap extends auth_basic { +class auth_plugin_authldap extends DokuWiki_Auth_Plugin +{ var $cnf = null; var $con = null; var $bound = 0; // 0: anonymous, 1: user, 2: superuser @@ -15,7 +25,7 @@ class auth_ldap extends auth_basic { /** * Constructor */ - function auth_ldap(){ + function auth_plugin_authldap(){ global $conf; $this->cnf = $conf['auth']['ldap']; @@ -458,6 +468,4 @@ class auth_ldap extends auth_basic { $attrsonly, $sizelimit, $timelimit, $deref); } } -} - -//Setup VIM: ex: et ts=4 : +} \ No newline at end of file diff --git a/lib/plugins/authldap/plugin.info.txt b/lib/plugins/authldap/plugin.info.txt new file mode 100644 index 0000000000000000000000000000000000000000..c363852240aafeefe2572470216bd2e3551d6a73 --- /dev/null +++ b/lib/plugins/authldap/plugin.info.txt @@ -0,0 +1,7 @@ +base authldap +author +email +date +name ldap auth plugin +desc Provides authentication against am LDAP server +url diff --git a/inc/auth/mysql.class.php b/lib/plugins/authmysql/auth.php similarity index 98% rename from inc/auth/mysql.class.php rename to lib/plugins/authmysql/auth.php index 653c725a3664a2f01582006fc9bc9a89e1d1076b..9150d3939a95df13c6ab6a6f6851466cff981826 100644 --- a/inc/auth/mysql.class.php +++ b/lib/plugins/authmysql/auth.php @@ -1,4 +1,13 @@ <?php +/** + * Plugin auth provider + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Jan Schumann <js@schumann-it.com> + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + /** * MySQLP authentication backend * @@ -6,10 +15,10 @@ * @author Andreas Gohr <andi@splitbrain.org> * @author Chris Smith <chris@jalakai.co.uk> * @author Matthias Grimm <matthias.grimmm@sourceforge.net> -*/ - -class auth_mysql extends auth_basic { - + * @author Jan Schumann <js@schumann-it.com> + */ +class auth_plugin_authmysql extends DokuWiki_Auth_Plugin +{ var $dbcon = 0; var $dbver = 0; // database version var $dbrev = 0; // database revision @@ -25,7 +34,7 @@ class auth_mysql extends auth_basic { * * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> */ - function auth_mysql() { + function auth_plugin_authmysql() { global $conf; $this->cnf = $conf['auth']['mysql']; @@ -934,6 +943,4 @@ class auth_mysql extends auth_basic { } return $string; } -} - -//Setup VIM: ex: et ts=2 : +} \ No newline at end of file diff --git a/lib/plugins/authmysql/plugin.info.txt b/lib/plugins/authmysql/plugin.info.txt new file mode 100644 index 0000000000000000000000000000000000000000..d08d4a7ef26cf63af1c9e65a0fef2ff70891c8b3 --- /dev/null +++ b/lib/plugins/authmysql/plugin.info.txt @@ -0,0 +1,7 @@ +base authmysql +author +email +date +name mysql auth plugin +desc Provides authentication against a MySQL Server +url diff --git a/lib/plugins/authpgsql/auth.php b/lib/plugins/authpgsql/auth.php new file mode 100644 index 0000000000000000000000000000000000000000..824a77882da41f6599a62f39dd0a3712e57e6945 --- /dev/null +++ b/lib/plugins/authpgsql/auth.php @@ -0,0 +1,331 @@ +<?php +/** + * Plugin auth provider + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Jan Schumann <js@schumann-it.com> + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + +/** + * PgSQL authentication backend + * + * This class inherits much functionality from the MySQL class + * and just reimplements the Postgres specific parts. + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr <andi@splitbrain.org> + * @author Chris Smith <chris@jalakai.co.uk> + * @author Matthias Grimm <matthias.grimmm@sourceforge.net> + * @author Jan Schumann <js@schumann-it.com> +*/ +class auth_plugin_authpgsql extends auth_plugin_authmysql +{ + var $cnf = null; + var $opts = null; + var $adldap = null; + var $users = null; + + /** + * Constructor + */ + function auth_plugin_authpgsql() { + 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']) + msg("AD Auth: PHP LDAP extension not found.",-1); + $this->success = false; + return; + } + + // Prepare SSO + if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){ + // remove possible NTLM domain + list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2); + if(!$usr) $usr = $dom; + + // remove possible Kerberos domain + list($usr,$dom) = explode('@',$usr); + + $dom = strtolower($dom); + $_SERVER['REMOTE_USER'] = $usr; + + // we need to simulate a login + if(empty($_COOKIE[DOKU_COOKIE])){ + $_REQUEST['u'] = $_SERVER['REMOTE_USER']; + $_REQUEST['p'] = 'sso_only'; + } + } + + // prepare adLDAP standard configuration + $this->opts = $this->cnf; + + // add possible domain specific configuration + if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){ + $this->opts[$key] = $val; + } + + // handle multiple AD servers + $this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']); + $this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']); + $this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']); + + // we can change the password if SSL is set + if($this->opts['use_ssl'] || $this->opts['use_tls']){ + $this->cando['modPass'] = true; + } + $this->cando['modName'] = true; + $this->cando['modMail'] = true; + } + + /** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct by trying to bind + * to the LDAP server + * + * @author James Van Lommel <james@nosq.com> + * @return bool + */ + function checkPass($user, $pass){ + if($_SERVER['REMOTE_USER'] && + $_SERVER['REMOTE_USER'] == $user && + $this->cnf['sso']) return true; + + if(!$this->_init()) return false; + return $this->adldap->authenticate($user, $pass); + } + + /** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email address of the user + * grps array list of groups the user is in + * + * This LDAP specific function returns the following + * addional fields: + * + * dn string distinguished name (DN) + * uid string Posix User ID + * + * @author James Van Lommel <james@nosq.com> + */ + function getUserData($user){ + global $conf; + if(!$this->_init()) return false; + + $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 information + 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']); + + if (is_array($info['grps'])) { + foreach ($info['grps'] as $ndx => $group) { + $info['grps'][$ndx] = $this->cleanGroup($group); + } + } + + // always add the default group to the list of groups + if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){ + $info['grps'][] = $conf['defaultgroup']; + } + + return $info; + } + + /** + * Make AD group names usable by DokuWiki. + * + * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores. + * + * @author James Van Lommel (jamesvl@gmail.com) + */ + function cleanGroup($name) { + $sName = str_replace('\\', '', $name); + $sName = str_replace('#', '', $sName); + $sName = preg_replace('[\s]', '_', $sName); + return $sName; + } + + /** + * Sanitize user names + */ + function cleanUser($name) { + return $this->cleanGroup($name); + } + + /** + * Most values in LDAP are case-insensitive + */ + function isCaseSensitive(){ + return false; + } + + /** + * 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; + } + + /** + * Modify user data + * + * @param $user nick of the user to be changed + * @param $changes array of field/value pairs to be changed + * @return bool + */ + function modifyUser($user, $changes) { + $return = true; + + // password changing + if(isset($changes['pass'])){ + try { + $return = $this->adldap->user_password($user,$changes['pass']); + } catch (adLDAPException $e) { + if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = false; + } + if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1); + } + + // changing user data + $adchanges = array(); + if(isset($changes['name'])){ + // get first and last name + $parts = explode(' ',$changes['name']); + $adchanges['surname'] = array_pop($parts); + $adchanges['firstname'] = join(' ',$parts); + $adchanges['display_name'] = $changes['name']; + } + if(isset($changes['mail'])){ + $adchanges['email'] = $changes['mail']; + } + if(count($adchanges)){ + try { + $return = $return & $this->adldap->user_modify($user,$adchanges); + } catch (adLDAPException $e) { + if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1); + $return = false; + } + } + + return $return; + } + + /** + * Initialize the AdLDAP library and connect to the server + */ + function _init(){ + if(!is_null($this->adldap)) return true; + + // 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('AD Auth: '.$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 + } + } +} \ No newline at end of file diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad565b853ebc38a93243544b985790ba5c20b3e3 --- /dev/null +++ b/lib/plugins/authpgsql/plugin.info.txt @@ -0,0 +1,7 @@ +base authad +author +email +date +name active directory auth plugin +desc Provides authentication against a Microsoft Active Directory +url diff --git a/inc/auth/plain.class.php b/lib/plugins/authplain/auth.php similarity index 96% rename from inc/auth/plain.class.php rename to lib/plugins/authplain/auth.php index 3941190e999e4cebb8fd05e3715a9821b8fc1490..4be0e0c192a4b982303f8ce282b4e7af43b62ef1 100644 --- a/inc/auth/plain.class.php +++ b/lib/plugins/authplain/auth.php @@ -1,14 +1,23 @@ <?php +/** + * Plugin auth provider + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Jan Schumann <js@schumann-it.com> + */ +// must be run within Dokuwiki +if(!defined('DOKU_INC')) die(); + /** * Plaintext authentication backend * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Andreas Gohr <andi@splitbrain.org> * @author Chris Smith <chris@jalakai.co.uk> + * @author Jan Schumann <js@schumann-it.com> */ - -class auth_plain extends auth_basic { - +class auth_plugin_authplain extends DokuWiki_Auth_Plugin +{ var $users = null; var $_pattern = array(); @@ -20,7 +29,7 @@ class auth_plain extends auth_basic { * * @author Christopher Smith <chris@jalakai.co.uk> */ - function auth_plain() { + function auth_plugin_authplain() { global $config_cascade; if (!@is_readable($config_cascade['plainauth.users']['default'])){ @@ -322,7 +331,5 @@ class auth_plain extends auth_basic { // $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=2 : + } +} \ No newline at end of file diff --git a/lib/plugins/authplain/plugin.info.txt b/lib/plugins/authplain/plugin.info.txt new file mode 100644 index 0000000000000000000000000000000000000000..3273e21d71496ca51b07b75a1c1153018bcb2ef5 --- /dev/null +++ b/lib/plugins/authplain/plugin.info.txt @@ -0,0 +1,7 @@ +base authplain +author +email +date +name auth plugin +desc Provides authentication against local password storage +url diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php index cee3c6b200716e56d6c4025cd83926746fdd30b9..f6adf1c1897f31f77c282d2fb2880ccc8236925a 100644 --- a/lib/plugins/config/settings/extra.class.php +++ b/lib/plugins/config/settings/extra.class.php @@ -45,22 +45,52 @@ if (!class_exists('setting_authtype')) { function initialize($default,$local,$protected) { global $plugin_controller; - // populate $this->_choices with a list of available auth mechanisms - $authtypes = glob(DOKU_INC.'inc/auth/*.class.php'); - $authtypes = preg_replace('#^.*/([^/]*)\.class\.php$#i','$1', $authtypes); - $authtypes = array_diff($authtypes, array('basic')); - // retrive auth types provided by plugins foreach ($plugin_controller->getList('auth') as $plugin) { - $authtypes[] = $plugin; + $this->_choices[] = $plugin; } - $authtypes = array_unique($authtypes); - - $this->_choices = $authtypes; - parent::initialize($default,$local,$protected); } + + function update($input) { + global $plugin_controller; + + // is an update posible? + $mayUpdate = parent::update($input); + + // is it an auth plugin? + if (in_array($input, $plugin_controller->getList('auth'))) { + // reject disabled plugins + if ($plugin_controller->isdisabled($input)) { + $this->_error = true; + msg('Auth type ' . $input . ' is disabled.'); + return false; + } + + // load the plugin + $auth_plugin = $plugin_controller->load('auth', $input); + + // @TODO: throw an error in plugin controller instead of returning null + if (is_null($auth_plugin)) { + $this->_error = true; + msg('Cannot load Auth Plugin "' . $input . '"'); + return false; + } + + // verify proper instanciation (is this really a plugin?) @TODO use instanceof? impement interface? + if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) { + $this->_error = true; + msg('Cannot create Auth Plugin "' . $input . '"'); + return false; + } + } + + msg('Successfully changed auth system. Please re-login.'); + auth_logoff(); + + return true; + } } }