Adding the following file allows authentication based on Apache AUTH Basic (module mod_auth_basic).
Ensure this file is loaded at the end of conf/local.php
$conf['authtype'] = 'http'; $conf['htpasswdfile'] = '/var/lib/httpd/auth/htpasswd'; $conf['htgroupfile'] = '/var/lib/httpd/auth/htgroup'; #$conf['httpauth_logout'] = '/logout/'; $conf['httpauth_realm'] = "Private Realm";
<?php /** * HTTP Basic authentication backend * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Simon Heimlicher */ //define('SH_HTTP_DEBUG',1); if (defined('SH_HTTP_DEBUG')) msg("HTTP AUTH Debug Mode enabled",1); function auth_http_contactDetails($ret = false) { if (isset($conf['registernotify'])) { $email = $conf['registernotify']; } else if (isset($_REQUEST['HTTP_HOST'])) { $email = 'webmaster@'.$_REQUEST['HTTP_HOST']; } else { $email = 'unknown@example.com'; } if ($ret) { return("Please contact the wiki administrator at $email"); } msg("Please contact the wiki administrator at $email",-1); } function auth_http_print_array($a, $ret = true) { $s = print_r($a, true); $s = preg_replace("{Array\n(\s*)\(}","$1", $s); $s = preg_replace("{\)\n\n}","\n", $s); $s = preg_replace("{\)\n}",'', $s); $s = preg_replace("{\n}",'<br>', $s); $s = preg_replace("{ }",' ', $s); $s = "Array:".$s; if (! $ret) echo($s); else return $s; } /** * Removes an item from an array of strings * @author: Simon Heimlicher */ function array_remove($a, $s) { if (is_array($a) && !empty($a) && count($a) > 0 && isset($s) && ! empty($s) ) { foreach ($a as $index => $value) { if (!$value) { continue; } if ($value === $s) { // Need to remove this entry unset($a[$index]); $a = array_values($a); } } } return $a; } // Sanitization -- only let the good characters through function sanitize_username($string, $min='', $max='') { // Strip whitepsace $string = trim($string); if (! preg_match('/^[A-Za-z]/', $string)) return false; $string = preg_replace("/[^-_.a-zA-Z0-9]/", "/_/", $string); $len = strlen($string); if((($min != '') && ($len < $min)) || (($max != '') && ($len > $max))) return false; return $string; } // Sanitization -- only let the good characters through function sanitize_grouplist($list, $min='', $max='') { $sanitized_list = array(); foreach ($list as $item) { // Strip whitepsace $item = trim($item); if (! preg_match('/^[A-Za-z]/', $item)) continue; $item = preg_replace("/[ ]/", "_", $item); $item = preg_replace("/[^-_.a-zA-Z0-9]/", "", $item); $len = strlen($item); if((($min != '') && ($len < $min)) || (($max != '') && ($len > $max))) continue; $sanitized_list[] = $item; } if (! count($sanitized_list) > 0) return false; return $sanitized_list; } define('DOKU_AUTH', dirname(__FILE__)); require_once(DOKU_AUTH.'/http.class.php'); global $conf; if (!defined('AUTH_USERFILE')) { if (defined('SH_HTTP_DEBUG')) { //msg("Looking for user file. DOKU_CONF=".DOKU_CONF,0); } if ($conf['htpasswdfile']) { define('AUTH_USERFILE',$conf['htpasswdfile']); } else { if (defined('SH_HTTP_DEBUG')) { msg("Try to use file. DOKU_CONF../../auth/htpasswd=" .DOKU_CONF.'../../auth/htpasswd',0); } define('AUTH_USERFILE',realpath(DOKU_CONF.'../../auth/htpasswd')); } } if (!defined('AUTH_GROUPFILE')) { if ($conf['htgroupfile']) { define('AUTH_GROUPFILE',$conf['htgroupfile']); } else { if (defined('SH_HTTP_DEBUG')) { //msg("Try to use file. DOKU_CONF../../auth/htgroup=" // .DOKU_CONF.'../../auth/htgroup',0); } define('AUTH_GROUPFILE',realpath(DOKU_CONF.'../../auth/htgroup')); } } // we only accept page ids for auth_http if(isset($_REQUEST['u'])) $_REQUEST['u'] = cleanID($_REQUEST['u']); if(isset($_REQUEST['acl_user'])) $_REQUEST['acl_user'] = cleanID($_REQUEST['acl_user']); // the same goes for password reset requests if(isset($_POST['login'])){ $_POST['login'] = cleanID($_POST['login']); } class auth_http extends auth_basic { var $users = null; var $_pattern = array(); /** * Constructor * * Carry out sanity checks to ensure the object is * able to operate. Set capabilities. * * @author Simon Heimlicher */ function auth_http() { $files_available = true; /* msg("AUTH_USERFILE=\"".AUTH_USERFILE,1); msg("AUTH_GROUPFILE=\"".AUTH_GROUPFILE,1); */ if (!@is_readable(AUTH_USERFILE)){ if (defined('SH_HTTP_DEBUG')) msg("Auth HTTP: FATAL ERROR: Cannot read user file \"" .AUTH_USERFILE."\"", -1); /* die("Auth HTTP: FATAL ERROR: Cannot read user file \"" .AUTH_USERFILE."\""); */ $files_available = false; } if (!@is_readable(AUTH_GROUPFILE)){ if (defined('SH_HTTP_DEBUG')) msg("Auth HTTP: FATAL ERROR: Cannot read group file \"" .AUTH_GROUPFILE."\"", -1); /* die("Auth HTTP: FATAL ERROR: Cannot read group file \"" .AUTH_GROUPFILE."\""); */ $files_available = false; } if ($files_available) { if ( (@is_writable(AUTH_USERFILE)) && (@is_writable(AUTH_GROUPFILE))) { $this->cando['addUser'] = true; $this->cando['delUser'] = true; $this->cando['modLogin'] = true; $this->cando['modPass'] = true; $this->cando['modName'] = true; $this->cando['modMail'] = true; $this->cando['modGroups'] = true; } $this->cando['getUsers'] = true; $this->cando['getUserCount'] = true; $this->cando['external'] = true; $this->cando['logoff'] = true; } else { $this->success = false; } } /* * Returns htpasswd-equivalent crypted password * @author: Simon Heimlicher * @return string */ function auth_http_cryptPassword($pass) { global $conf; $crypted_pass = '*'; $crypt_type = $conf['passcrypt']; switch ($crypt_type) { /* SHA1 is not compatible with the method DokuWiki uses, * see inc/auth/auth.php:auth_cryptPassword case 'sha1': return '{SHA}'.base64_encode(pack("H*", sha1($pass))); */ case 'crypt': $salt = md5(uniqid(rand(), true)); return crypt($pass,substr($salt,0,2)); default: msg("HTTP authentication back-end does not support " ."passcrypt method $method; using \"crypt\"",-1); $salt = md5(uniqid(rand(), true)); return crypt($pass,substr($salt,0,2)); } } // Load given user file function auth_http_userFile($user_file) { //msg("BEGIN auth_http_userFile($user_file)", 1); if(!@file_exists($user_file)) { msg("Auth HTTP: FATAL ERROR: user file \"".$user_file ."\" not found", -1); return false; } $u_lines = file($user_file); foreach($u_lines as $u_line) { $u_line = preg_replace('/#.*$/','',$u_line); //ignore comments $u_line = trim($u_line); if(empty($u_line)) continue; $row = split(":", $u_line,5); $u_data[$row[0]]['user'] = $row[0]; $u_data[$row[0]]['pass'] = $row[1]; $u_data[$row[0]]['name'] = urldecode($row[2]); $u_data[$row[0]]['mail'] = $row[3]; } //msg("END auth_http_userFile()", 1); return $u_data; } // Load AUTH_GROUPFILE function auth_http_groupFile($group_file) { //msg("BEGIN auth_http_groupFile($group_file)", 1); if(!@file_exists($group_file)) { msg("Auth HTTP: FATAL ERROR: group file \"".$group_file ."\" not found", -1); return false; } $g_lines = file($group_file); foreach($g_lines as $g_line) { $g_line = preg_replace('/#.*$/','',$g_line); //ignore comments $g_line = trim($g_line); if(empty($g_line)) continue; $row = split(":", $g_line,2); $row[1] = preg_replace('/#.*$/','',$row[1]); //ignore comments $row[1] = trim($row[1]); $members = split(" ", $row[1]); if(strlen($members[0]) == 0) continue; if(count($members) == 0) continue; //msg("INFO: group = ".$row[0]." has ".count($members)." members", 1); $g_data[$row[0]]['group'] = $row[0]; $g_data[$row[0]]['members'] = $members; } //msg("END auth_http_groupFile()", 1); return $g_data; } function auth_http_loadUserData($user_file, $group_file=null, $filter_grps=null) { global $conf; //$this->users = array(); // Flush array if (defined('SH_HTTP_DEBUG')) msg("BEGIN auth_http_loadUserData($user_file,$group_file)", 1); // Slurp user file $u_data = $this->auth_http_userFile($user_file); if ($group_file != null) { // Slurp group file $g_data = $this->auth_http_groupFile($group_file); foreach($g_data as $g_record) { if(empty($g_record)) continue; foreach($g_record['members'] as $g_member) { if(! isset($u_data[$g_member])) { //msg("Error: user ".$g_member." is member of group \"" .$g_record['group']."\" but has no entry in " .$user_file, -1); continue; } //msg("Info: Adding user \"".$g_member ."\" to group \"".$g_record['group']."\"", 1); if (count($u_data[$g_member]['grps']) > 0) { array_push($u_data[$g_member]['grps'], $g_record['group']); } else { $u_data[$g_member]['grps'][0] = $g_record['group']; } } } } foreach ($u_data as $u_record) { // Check if we show this user if (($filter_grps != null) && (is_array($filter_grps))) { // Filter by group membership $hide_user = true; if (is_array($u_record['grps'])) { foreach ($filter_grps as $fg) { if (in_array($fg, $u_record['grps'])) { $hide_user = false; break; } } } if ($hide_user) { // Remove user from list if (defined('SH_HTTP_DEBUG')) msg("Hiding user ".$u_record['user'] ." because they are not in ".print_r($filter_grps,true),0); unset($u_data[$u_record['user']]); continue; } } if (count($u_record['grps']) == 0) { if ($filter_grps == null) { // Show user even though user is in no group $u_data[$u_record['user']]['grps'] = array(); /* if (isset($conf['defaultgroup'])) { $u_data[$u_record['user']]['grps'][0] = $conf['defaultgroup']; msg("Added.\"".$u_data[$u_record['user']]['user'] ."\" to default group \"" .join(', ', $u_data[$u_record['user']]['grps']) ."\"", -1); } else { msg("Invalid user .\"".$u_data[$u_record['user']]['user'] ."\": not in any group. Please define the name of the default group \$conf['defaultgroup']", -1); unset($u_data[$u_record['user']]); } */ } else { if (defined('SH_HTTP_DEBUG')) msg("Invalid user .\"".$u_data[$u_record['user']]['user'] ."\": not in any group", -1); unset($u_data[$u_record['user']]); continue; } } } if (defined('SH_HTTP_DEBUG')) msg("END auth_http_loadUserData()", 1); return $u_data; } // Set group memberships of given user in htgroup file function auth_http_setGroups($group_file, $user, $grps) { if (!isset($user) || empty($user)) { msg("auth_http_setGroups: user unset",-1); return false; } // Set default group if no groups specified if (!is_array($grps) || empty($grps)) { array($conf['defaultgroup']); } if ($grps == null) { // Remove user from all groups $grps = array(); } $g_file_orig = file($group_file); $grps_remain = $grps; foreach($g_file_orig as $g_line) { $g_line_orig = $g_line; $g_line = preg_replace('/#.*$/','',$g_line); //ignore comments $g_line = trim($g_line); if(empty($g_line)) { $g_file .= $g_line_orig; continue; } $g_record = split(":", $g_line,2); $g_record[1] = trim($g_record[1]); $g_name = $g_record[0]; $g_members = split(" ", $g_record[1]); foreach ($g_members as $g_member) { $g_member = trim($g_member); } if ((count($grps_remain) > 0) && (in_array($g_name, $grps_remain))) { if (! in_array($user, $g_members)) { // Need to add user to this group array_push($g_members, $user); $g_line = $g_name.":" .join(' ', $g_members)."\n"; //msg('Added user "'.$user.'" to group "'.$g_name.'": '.$g_line, 1); $g_file .= $g_line; } else { $g_file .= $g_line_orig; } $grps_remain = array_remove($grps_remain, $g_name); } else { if (in_array($user, $g_members)) { // Need to remove user from this group $g_members = array_remove($g_members, $user); if (count($g_members) > 0) { // Keep group $g_line = $g_name.":" .join(' ', $g_members)."\n"; if (defined('SH_HTTP_DEBUG')) msg('Auth HTTP: Removed user "'.$user.'" from group "'.$g_name.'": '.$g_line, 1); $g_file .= $g_line; } else { // Remove empty group if (defined('SH_HTTP_DEBUG')) msg('Auth HTTP: Removed user "'.$user.'" and group "'.$g_name.'"', 1); // FIXME Not implemented. Hmm, or is it implemented? } } else { // User is not in this group //msg('Auth HTTP: User "'.$user.'" not in group "'.$g_name.'": '.$g_line, 1); $g_file .= $g_line_orig; } } } // Check if any new groups need to be created if (! empty($grps_remain)) { foreach ($grps_remain as $g_name) { $g_line = $g_name.":".$user."\n"; //msg('Added group "'.$g_name.'" with user "'.$user.'": '.$g_line, 1); $g_file .= $g_line; } } if (!io_saveFile($group_file,$g_file,false)) { msg('Failed to write to group file "'.$group_file.'"',-1); auth_http_contactDetails(); return false; } return true; } /** Add user to user file * * @author Simon Heimlicher * @return bool */ function auth_http_addUser($user_file, $group_file=null, $user, $pass, $name, $mail, $grps) { if (defined('SH_HTTP_DEBUG')) msg("BEGIN auth_http_addUser($user_file, $group_file, " ."$user, $pass, $name, $mail," .auth_http_print_array($grps).")", 1); // Prepare user line if ( ($sane_user = sanitize_username($user,2,32)) == false) { msg('The given user name '."$user".' is invalid. ' .'Please use a user name matching ^[a-zA-Z][a-zA-Z0-9]*',-1); return false; } if (! $sane_grps = sanitize_grouplist($grps,2,32)) { msg('The given group list is invalid. ' .'Please use group names matching /^[a-zA-Z][a-zA-Z0-9]*/, ' .'separated by commas ",".',-1); return false; } $userline = join(':',array($sane_user, $pass, $name, $mail))."\n"; //msg('auth_http_addUser'.'('.$user_file.', '.$group_file.', ' .$user.', ' .$pass.', ' .$name.', ' .$mail.', ' . join(' ', $grps) .')', 1); if (! io_saveFile($user_file,$userline,true)) { msg('Failed to write to user file "'.$user_file.'"',-1); auth_http_contactDetails(); return false; } if ( $group_file !=null) { if (! $this->auth_http_setGroups($group_file, $sane_user, $sane_grps)) { msg('Failed to write to group file "'.$group_file.'"',-1); auth_http_contactDetails(); return false; } } if (defined('SH_HTTP_DEBUG')) msg("END auth_http_addUser()",1); return true; } /** * Remove one or more users from the list of registered users * * @author Simon Heimlicher * @param array $users array of users to be deleted * @return int the number of users deleted */ function auth_http_deleteUsers($user_file, $group_file, $del_users) { if (defined('SH_HTTP_DEBUG')) msg("BEGIN auth_http_deleteUsers($user_file, $group_file, " . print_r($del_users, true).")", 1); if (!is_array($del_users) || empty($del_users)) { msg("auth_http_deleteUsers: expected array", -1); return 0; } $user_data = $this->auth_http_loadUserData($user_file, $group_file); //msg("INFO: user_data: ".auth_http_print_array($user_data,true),1); $deleted = array(); foreach ($del_users as $user) { if (isset($user_data[$user])) $deleted[] = preg_quote($user,'/'); } if (empty($deleted)) { msg("auth_http_deleteUsers: no users to delete found in $user_file", -1); return 0; } $pattern = '/^('.join('|',$deleted).'):/'; $count = 0; if (io_deleteFromFile($user_file,$pattern,true)) { foreach ($deleted as $user) { // Remove from all groups if ($group_file != null) { $this->auth_http_setGroups($group_file, $user, null); } unset($user_data[$user]); } $count = count($deleted); } else { // problem deleting, reload the user list and count the difference $count = count($user_data()); $user_data = $this->auth_http_loadUserData($user_file, $group_file); $count -= $count($user_data()); } if (defined('SH_HTTP_DEBUG')) msg("END auth_http_deleteUsers()", 1); return $count; } /** * Returns all user data from user and group file * * @author Simon Heimlicher */ /** * Check user+password [required auth function] * * Checks if the given user exists and the given * plaintext password is correct * * @author Simon Heimlicher * @return bool */ function checkPass($user,$pass) { if (defined('SH_HTTP_DEBUG')) msg("HTTP Auth: checkPass(user=$user,pass=$pass)", 1); global $conf; //msg("HTTP Auth: checkPass($user,$pass)",0); $userinfo = $this->getUserData($user); if ($userinfo === false) { //msg("HTTP Auth: checkPass($user,$pass)",-1); msg("HTTP Auth: Could not retrieve user information. Maybe the user is hidden because they do not belong to the required group.", -1); return false; } else { return _getUserName(); } } /** * Logoff user * * @author Simon Heimlicher * */ function logOff(){ global $conf; global $_SERVER, $_REQUEST, $_GET; $msg = "<h1>Auth HTTP: logOff() called</h1>\n"; if (isset($conf['httpauth_realm'])) { $msg .="<h2>Auth HTTP: httpauth_realm = \"".$conf['httpauth_realm']."\"</h2>\n"; /* For logout in Firefox to work, you MUST send a "401" for * the exact realm the user is logged in with. * * Do NOT send a Location: header, it will make logout fail */ header('HTTP/1.1 401 Authorization Required', true, 401); header('WWW-Authenticate: Basic realm="'.$conf['httpauth_realm'].'"'); } elseif (isset($conf['httpauth_logout'])) { // DEPRECATED $msg .= "<h2>Auth HTTP: httpauth_logout = \"".$conf['httpauth_logout']."\"</h2>\n"; header('Location: '.$conf['httpauth_logout']); } else { header('HTTP/1.1 401 Authorization Required', true, 401); header('Date: '.date(r)); header('WWW-Authenticate: Basic realm="'.$_SERVER['SERVER_NAME'].'"'); header('Connection: close'); header('Content-Type: text/html'); header("Location: /logged-out-default"); } if (defined('SH_HTTP_DEBUG')) { echo($msg."\n"); echo("<h3>\$_SERVER</h3>\n<pre>\n"); print_r($_SERVER); echo("</pre>\n"); echo("<h3>\$_REQUEST</h3>\n<pre>\n"); echo("<pre>\n"); print_r($_REQUEST); echo("</pre>\n"); echo("<h3>\$_GET</h3>\n<pre>\n"); echo("<pre>\n"); print_r($_GET); echo("</pre>\n"); } print('<html><head><title>Logged out</title></head>'); print('<body><h1>You have been logged out</h1><h2>'); print('<a href="'.DOKU_BASE.'" title="Login again">Login again</a>'); print('</h2></body></html>'); exit; } /** * 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 functions below becomes optional. * * 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){ if (defined('SH_HTTP_DEBUG')) msg("HTTP Auth: trustExternal(user=$user,pass=$pass,$sticky)", 1); global $REQUEST; global $_SERVER; global $USERINFO; global $conf; global $lang; global $auth; $sticky ? $sticky = true : $sticky = false; //sanity check //msg("HTTP Auth: trustExternal($user,$pass,$sticky)",0); //msg("\$_SERVER['REDIRECT_REMOTE_USER'] = " . $_SERVER['REDIRECT_REMOTE_USER'] ."<br>\$_SERVER['REMOTE_USER'] = ".$_SERVER['REMOTE_USER'] ."<br>\$_REQUEST['u'] = ".$_REQUEST['u'] ."<br>\$user = ".$user,0); if(empty($user)) { //msg("auth: \$_REQUEST['u'] = ". $_REQUEST['u'],0); if (_getUserName()) { $user = $_SERVER['REMOTE_USER']; } if(empty($user)) { return false; } } if ($this->checkPass($user,$pass)) { //msg("trustExternal: \$session is not set up correctly",0); // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; $USERINFO = $this->getUserData($user); // set session // --sh--BEGIN 2009-05-11 23:16 // Comment the following cookie stuff /* $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); */ // --sh--END //msg("trustExternal: Successfully logged in user $user; return true",1); return true; } msg("trustExternal: Login failed.", -1); /*( echo("<p>\$_SERVER['REDIRECT_REMOTE_USER'] = " . $_SERVER['REDIRECT_REMOTE_USER'] ."\n\$_SERVER['REMOTE_USER'] = ".$_SERVER['REMOTE_USER'] ."\n\$user = ".$user."</p>\n"); echo("<h1>Calling logOff</h1>\n"); */ //just to be sure $this->logOff(); return false; } /** * Return user info * * 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 Simon Heimlicher */ function getUserData($user){ if (defined('SH_HTTP_DEBUG')) msg("HTTP Auth: getUserData($user)", 1); if($this->users === null) $this->loadUserData(); //msg("INFO",0); foreach($this->users as $u_record) { msg("INFO: user = ".$u_record['user'].", pass = ".$u_record['pass'].", name = ".$u_record['name'].", mail = ".$u_record['mail'].", groups = ".join(', ', $u_record['grps']), 1); } if (isset($this->users[$user])) { $u_record = $this->users[$user]; //msg("Found user data: user = ".$u_record['user'] .", pass = ".$u_record['pass'] .", name = ".$u_record['name'] .", mail = ".$u_record['mail'] .", groups = ".join(', ', $u_record['grps']), 1); } else { //msg("Could not find user data for user $user. Return false", -1); } return isset($this->users[$user]) ? $this->users[$user] : false; } function auth_http_getUserData($user_file, $group_file, $user, $filter_grps=null){ if (defined('SH_HTTP_DEBUG')) msg("BEGIN auth_http_getUserData($user_file, $group_file, $user, " ."$showall)", 1); $user_data = $this->auth_http_loadUserData($user_file, $group_file, $filter_grps); if (isset($user_data[$user])) { $u_record = $user_data[$user]; } else { if (defined('SH_HTTP_DEBUG')) msg("auth_http_getUserData: Could not find user data " ."for user $user with user file $user_file " ."and group file $group_file " ."Return false", 0); } if (defined('SH_HTTP_DEBUG')) msg("END auth_http_getUserData()", 1); return isset($u_record) ? $u_record : false; } /** * Create a new User * * Returns false if the user already exists, null when an error * occured and the cleartext password of the new user if * everything went well. * * The new user will be added to the default group by this * function if grps are not specified (default behaviour). * * @author Simon Heimlicher * * @return string */ function createUser($user,$pwd,$name,$mail,$grps=null) { global $conf; // User must not exist yet if ($this->getUserData($user) !== false) return false; // Set default group if no groups specified if (!is_array($grps)) $grps = array($conf['defaultgroup']); // Encrypt password $crypt = $this->auth_http_cryptPassword($pwd); if (! $this->auth_http_addUser(AUTH_USERFILE, AUTH_GROUPFILE, $user, $crypt, $name, $mail, $grps)) { return null; } $this->users[$user] = compact('crypt','name','mail','grps'); return $pwd; } /** * Modify user data * * @author Simon Heimlicher * @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) { global $conf; global $ACT; global $INFO; if (defined('SH_HTTP_DEBUG')) msg('modifyUser'.'(' .$user.', ' . auth_http_print_array($changes) .')', 1); // sanity checks, user must already exist // and there must be something to change if (($userinfo = $this->getUserData($user)) === false) return false; if (!is_array($changes) || !count($changes)) return true; if (defined('SH_HTTP_DEBUG')) msg('Original userinfo: user='.$user .', pass='.$userinfo['pass'] .', name='.$userinfo['name'] .', mail='.$userinfo['mail'] .', grps='.auth_http_print_array($userinfo['grps']), 1); // update userinfo with new data, remembering to encrypt any password $newuser = $user; foreach ($changes as $field => $value) { if ($field == 'user') { $newuser = $value; continue; } if ($field == 'pass') $value = $this->auth_http_cryptPassword($value); $userinfo[$field] = $value; } if (defined('SH_HTTP_DEBUG')) msg('Modified userinfo: user='.$newuser .', pass='.$userinfo['pass'] .', name='.$userinfo['name'] .', mail='.$userinfo['mail'] .', grps = '.join(' ', $userinfo['grps']), 1); $user_file = AUTH_USERFILE; $group_file = AUTH_GROUPFILE; // First remove the user if (! $this->auth_http_deleteUsers($user_file, $group_file,array($user))) { msg('Failed to write to user file "'.$user_file.'" or group file "' .$group_file.'"',-1); auth_http_contactDetails(); return false; } // Then add it with the new data if (! $this->auth_http_addUser($user_file, $group_file, $newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $userinfo['grps'])) { msg('Failed to add user with new data',-1); msg('Failed to write to user file "'.$user_file.'" or group file "' .$group_file.'"',-1); auth_http_contactDetails(); return false; } $this->users[$newuser] = $userinfo; //msg('userinfo of $newuser: user = '.$newuser .', pass = '.$this->users[$newuser]['pass'] .', name = '.$this->users[$newuser]['name'] .', mail = '.$this->users[$newuser]['mail'] .', grps = '.join(' ', $this->users[$newuser]['grps']), 1); //msg('$this->users array_keys: '. join (', ', array_keys($this->users)), 1); return true; } /** * Remove one or more users from the list of registered users * * @author Simon Heimlicher * @param array $users array of users to be deleted * @return int the number of users deleted */ function deleteUsers($del_users) { //msg("BEGIN deleteUsers()", 1); if (!is_array($del_users) || empty($del_users)) { //msg("deleteUsers: expected array", -1); return 0; } $user_file = AUTH_USERFILE; $group_file = AUTH_GROUPFILE; $count = 0; $count = $this->auth_http_deleteUsers($user_file, $group_file, $del_users); //msg("END deleteUsers()", 1); $this->loadUserData(); return $count; } /** * Return a count of the number of user which meet $filter criteria * * @author Simon Heimlicher */ function getUserCount($filter=array()) { if($this->users === null) $this->loadUserData(); if (!count($filter)) return count($this->users); $count = 0; $this->_constructPattern($filter); foreach ($this->users as $user => $info) { $count += $this->_filter($user, $info); } return $count; } /** * Bulk retrieval of user data * * @author Simon Heimlicher * @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 * @return array of userinfo (refer getUserData for * internal userinfo details) */ function retrieveUsers($start=0,$limit=0,$filter=array()) { if ($this->users === null) $this->loadUserData(); ksort($this->users); $i = 0; $count = 0; $out = array(); $this->_constructPattern($filter); foreach ($this->users as $user => $info) { if ($this->_filter($user, $info)) { if ($i >= $start) { $out[$user] = $info; $count++; if (($limit > 0) && ($count >= $limit)) break; } $i++; } } return $out; } /** * Load all user data * * loads the user file into a datastructure * * @author Simon Heimlicher */ function loadUserData() { global $conf; $user_file = AUTH_USERFILE; if (defined('AUTH_SUBWIKI_USER')) { $filter_grps = array(AUTH_SUBWIKI_USER); } if(!@file_exists($user_file)) { msg("Auth HTTP: ERROR: user file=\"".$user_file ."\" not found", -1); return false; } $group_file = AUTH_GROUPFILE; if(!@file_exists($group_file)) { msg("Auth HTTP: ERROR: group file=\"".$group_file ."\" not found", -1); return false; } $this->users = array(); // Flush array $this->users = $this->auth_http_loadUserData($user_file, $group_file, $filter_grps); } /** * return 1 if $user + $info match $filter criteria, 0 otherwise * * @author Chris Smith <chris@jalakai.co.uk> */ function _filter($user, $info) { // FIXME 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) { // allow regex characters $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/'; } } } function _getUserName() { global $_SERVER; if (defined('SH_HTTP_DEBUG')) msg("HTTP AUTH: getUserName",1); if (isset($_SERVER['REMOTE_USER'])) { if (defined('SH_HTTP_DEBUG')) msg("Found user name in \$_SERVER['REMOTE_USER'", 1); return true; } if (isset($_SERVER['HTTP_AUTH_USER'])) { if (defined('SH_HTTP_DEBUG')) msg("Found user name in \$_SERVER['HTTP_AUTH_USER'", 1); $_SERVER['REMOTE_USER'] = $_SERVER['HTTP_AUTH_USER']; return true; } if (isset($_SERVER['PHP_AUTH_USER'])) { if (defined('SH_HTTP_DEBUG')) msg("Found user name in \$_SERVER['PHP_AUTH_USER'", 1); $_SERVER['REMOTE_USER'] = $_SERVER['PHP_AUTH_USER']; return true; } if (isset($_SERVER['REDIRECT_REMOTE_USER'])) { if (defined('SH_HTTP_DEBUG')) msg("Found user name in \$_SERVER['REDIRECT_REMOTE_USER'", 1); $_SERVER['REMOTE_USER'] = $_SERVER['REDIRECT_REMOTE_USER']; return true; } if (defined('SH_HTTP_DEBUG')) { msg("Fatal: Could not retrieve HTTP AUTH user name", -1); msg("Neither " ."\$_SERVER['REMOTE_USER'] nor " ."\$_SERVER['HTTP_AUTH_USER'] nor " ."\$_SERVER['PHP_AUTH_USER'] nor " ."\$_SERVER['REDIRECT_REMOTE_USER'] is available", -1); } return false; } //Setup VIM: ex: et ts=2 sw=2 enc=utf-8 :
Discussion