Simon Heimlicher
 
  
 

HTTP Authentication

Adding the following file allows authentication based on Apache AUTH Basic (module mod_auth_basic).

Configuration

File ''dwbase/conf/local.protected.php''

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";

File ''dwbase/inc/auth/http.class.php''

<?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("{ }",'&nbsp;', $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

Enter your comment
XZLKY