Source for file basicauth.php

Documentation is available at basicauth.php

  1. <?php
  2. /**
  3. * User Authentication object
  4. *
  5. @author     Stuart Prescott
  6. @copyright  Copyright Stuart Prescott
  7. @license    http://opensource.org/licenses/gpl-license.php GNU Public License
  8. @version    $Id$
  9. @package    Bumblebee
  10. @subpackage DBObjects
  11. */
  12.  
  13. /** Load ancillary functions */
  14. require_once 'inc/typeinfo.php';
  15.  
  16. /** sql manipulation routines */
  17. require_once 'inc/formslib/sql.php';
  18. /** type checking and data manipulation */
  19. require_once 'inc/typeinfo.php';
  20. /** username and password checks */
  21. require_once 'inc/passwords.php';
  22. /** permissions codes */
  23. require_once 'inc/permissions.php';
  24. /** logging functions */
  25. require_once 'inc/logging.php';
  26. /** configuration */
  27. require_once 'inc/bb/configreader.php';
  28.  
  29. /**
  30. * User Authentication
  31. *
  32. @package    Bumblebee
  33. @subpackage DBObjects
  34. @todo //TODO: update permissions system
  35. @todo //TODO: documentation
  36. */
  37. class BasicAuth {
  38.   var $uid;    //user id from table
  39.     var $username;
  40.   var $name;
  41.   var $email;
  42.   var $_loggedin=0;
  43.   var $_error = '';
  44.   var $table;
  45.   var $localLogin = 0;
  46.   /** @var array      database row for the user */
  47.   var $user_row = array();
  48.   /** @var integer    debug level (0=off, 10=verbose)  */
  49.   var $DEBUG = 0;
  50.  
  51.   /**
  52.   *  Create the authentication object
  53.   *
  54.   * @param array   $data    array containing keys 'username' and 'pass'
  55.   * @param boolean $recheck (optional) ignore session data and check anyway
  56.   * @param string  $table  (optional) db table from which login data should be taken
  57.   */
  58.   function BasicAuth($data$recheck false$table='users'{
  59.     $conf ConfigReader::getInstance();
  60.     // Only start the session if one has not already been started (e.g. to cope
  61.     // with the situation where session.auto_start=1 in php.ini or where
  62.     // the entire thing is embedded within some other framework.
  63.     // For session.auto_start, the following is enough:
  64.     //      if (! ini_get('session.auto_start')) {
  65.     // But we can check the session_id() (hexadecimal string if session has started
  66.     // empty string "" if it hasn't)
  67.     #preDump($_SESSION);
  68.     if (session_id()) {
  69.       #print "Creating new session". session_id();;
  70.       session_name('BumblebeeLogin');
  71.       session_set_cookie_params(ini_get('session.cookie_lifetime')$conf->BasePath.'/');
  72.       session_start();
  73.       #print "Started session, ". session_id();
  74.     }
  75.     $this->table = $table;
  76.     if (!$recheck && $this->_var_get('uid'!== NULL{
  77.       // the we have a session login already done, check it
  78.       $this->_loggedin = $this->_verifyLogin();
  79.     elseif (isset($data['username'])) {
  80.       // then some login info has been provided, so we need to check it
  81.       $this->_loggedin = $this->_login($data);
  82.     else {
  83.       // we're not logged in at all
  84.     }
  85.   }
  86.  
  87.   /**
  88.   * Generate a pseudo-random tag that is unique to this user and installation
  89.   *
  90.   * The tag is unique to this user and this installation of Bumblebee so that it
  91.   * can be used to test whether the submitted data is from a Bumblebee-produced
  92.   * form or if it is perhaps from a spoofed source.
  93.   *
  94.   * @see http://www.debian-administration.org/articles/465
  95.   * @returns string    tag unique to this user and installation
  96.   */
  97.   function makeValidationTag({
  98.     return md5(session_id());
  99.   }
  100.  
  101.   /**
  102.   * Test if the magic tag in the form matches the magic tag for this user
  103.   *
  104.   * @see makeValidationTag()
  105.   *
  106.   * @param   string    $tag     submitted tag to be tested
  107.   * @returns boolean            the submitted tag is valid
  108.   */
  109.   function isValidTag($tag{
  110.     return $tag == $this->makeValidationTag();
  111.   }
  112.  
  113.   /**
  114.   * test function to see if user is logge in
  115.   *
  116.   * @returns boolean  user is logged in
  117.   */
  118.   function isLoggedIn({
  119.     return $this->_loggedin;
  120.   }
  121.  
  122.   /**
  123.   * log the user out of the system
  124.   */
  125.   function logout({
  126.     session_destroy();
  127.     $this->_loggedin = 0;
  128.     logmsg(4"User '$this->usernamelogged out");
  129.   }
  130.  
  131.   /**
  132.   * obtain an error string that (if appropriate) describes the failure mode
  133.   * @returns string  error message
  134.   */
  135.   function loginError({
  136.     $conf ConfigReader::getInstance();
  137.     if ($this->DEBUG ||
  138.           ($conf->value('auth''authAdvancedSecurityHole'&&
  139.            $conf->value('auth''verboseFailure'))) {
  140.       return xssqw($this->_error);
  141.     elseif (strpos($this->_error':'!== false{
  142.       // protect any additional info that is in the error string:
  143.       // functions in this class can report the error in the format 'General error: details'
  144.       // Normally, we shouldn't reveal whether it was a bad username or password,
  145.       // but for debugging purposes, it's nice to have the extra info.
  146.       list($public,$privatepreg_split('/:/'$this->_error);
  147.       return xssqw($public);
  148.     else {
  149.       return xssqw($this->_error);
  150.     }
  151.   }
  152.  
  153.   /**
  154.   * store a piece of data in the session for persistance across page calls
  155.   *
  156.   * @param string $var    name to call the data in the session
  157.   * @param mixed  $value  value to store
  158.   */
  159.   function _var_put($var$value{
  160.     $conf ConfigReader::getInstance();
  161.     $_SESSION[$conf->SessionIndex][$var$value;
  162.   }
  163.  
  164.   /**
  165.   * retrieve a piece of data previously stored
  166.   * @returns mixed  value stored
  167.   */
  168.   function _var_get($var{
  169.     $conf ConfigReader::getInstance();
  170.     return issetSet($_SESSION[$conf->SessionIndex]$var);
  171.   }
  172.  
  173.   /**
  174.   * create the login session for persistant data storage
  175.   * @param array  $row  database row for the user
  176.   */
  177.   function _createSession($row{
  178.     $this->_var_put('uid',        $this->uid        = $row['id']);
  179.     $this->_var_put('username',   $this->username   = $row['username']);
  180.     $this->_var_put('name',       $this->name       = $row['name']);
  181. //     $this->_var_put('email']      = $this->email      = $row['email'];
  182. //     $this->_var_put('isadmin']    = $this->isadmin    = $row['isadmin'];
  183.     $this->_var_put('localLogin'$this->localLogin);
  184.     logmsg(4"User '$this->usernamelogged in");
  185.   }
  186.  
  187.   function _verifyLogin({
  188.     // check that the credentials contained in the session are OK
  189.     $uid $this->_var_get('uid');
  190.     $row $this->_retrieveUserInfo($uid0);
  191.     $this->user_row = $row;
  192.     if ($row['username']  == $this->_var_get('username'&&
  193.         $row['name']      == $this->_var_get('name') ) {
  194.       $this->uid        = $uid;
  195.       $this->username   = $this->_var_get('username');
  196.       $this->name       = $this->_var_get('name');
  197.       $this->email      = $row['email'];
  198.       $this->isadmin    $row['isadmin'];
  199.       $this->localLogin = $this->_var_get('localLogin');
  200.       logmsg(4"User '$this->usernamesession accepted");
  201.       return 1;
  202.     else {
  203.       $this->logout();
  204.       $this->_error = T_('Login failed: SESSION INVALID!');
  205.       return 0;
  206.     }
  207.   }
  208.  
  209.   /**
  210.   * check login details, if OK, set up a PHP SESSION to manage the login
  211.   *
  212.   * @returns boolean credentialsOK
  213.   */
  214.   function _login($data{
  215.     $conf ConfigReader::getInstance();
  216.     // a login attempt must have a password
  217.     if (isset($data['pass']) ) {
  218.       $this->_error = 'Login failed: no password specified.';
  219.       return false;
  220.     }
  221.     // test the username to make sure it looks valid
  222.     if (is_valid_username($data['username'])) {
  223.       $this->_error = T_('Login failed: bad username'.' -- '
  224.                      .T_('Either change the username using phpMyAdmin or change how you define a valid username in config/bumblebee.ini (see the value "validUserRegexp")');
  225.       return false;
  226.     }
  227.     // then there is data provided to us in a login form
  228.     // need to verify if it is valid login info
  229.     $PASSWORD $data['pass'];
  230.     $USERNAME $data['username'];
  231.     $row $this->_retrieveUserInfo($USERNAME);
  232.     $this->user_row = $row;
  233.  
  234.     // if the admin user has locked themselves out of the system, let them get back in:
  235.     if ($conf->value('auth','authAdvancedSecurityHole'&& $conf->value('auth','recoverAdminPassword')) {
  236.       $this->_createSession($row);
  237.       return true;
  238.     }
  239.  
  240.     // the username has to exist in the users table for the login to be valid, so check that first
  241.     if ($row == '0'{
  242.       return false;
  243.     }
  244.  
  245.     $authOK 0;
  246.     if ($conf->value('auth''useRadius'&& $conf->value('auth''RadiusPassToken'== $row['passwd']{
  247.       $authOK $this->_auth_via_radius($USERNAME$PASSWORD);
  248.     elseif ($conf->value('auth','useLDAP'&& $conf->value('auth','LDAPPassToken'== $row['passwd']{
  249.       $authOK $this->_auth_via_ldap($USERNAME$PASSWORD);
  250.     elseif ($conf->value('auth''useLocal')) {
  251.       $this->localLogin = 1;
  252.       $authOK $this->_auth_local($USERNAME$PASSWORD);
  253.     else {   //system is misconfigured
  254.       $this->_error = T_('System has no login method enabled');
  255.     }
  256.     if ($authOK{
  257.       return false;
  258.     }
  259.     if (isset($row['suspended']&& $row['suspended']{
  260.       $this->_error = T_('Login failed: this account is suspended, please contact us about this.');
  261.       return false;
  262.     }
  263.     // if we got to here, then we're logged in!
  264.     $this->_createSession($row);
  265.     return true;
  266.   }
  267.  
  268.   function _retrieveUserInfo($identifier$type=1{
  269.     $conf ConfigReader::getInstance();
  270.     $row quickSQLSelect('users',($type?'username':'id'),$identifier);
  271.     if ($conf->value('auth','authAdvancedSecurityHole'&& $conf->value('auth','recoverAdminPassword')) {
  272.       if (is_array($row)) {
  273.         $row array('id' => -1);
  274.       }
  275.       $row['isadmin'1;
  276.     }
  277.     if (is_array($row)) {
  278.       $this->_error = T_('Login failed: unknown username');
  279.       return 0;
  280.     }
  281.     //$row = db_fetch_array($sql);
  282.     return $row;
  283.   }
  284.  
  285.   /**
  286.   * RADIUS auth method to login the user against a RADIUS server
  287.   */
  288.   function _auth_via_radius($username$password{
  289.     require_once 'Auth/Auth.php';
  290.     $conf ConfigReader::getInstance();
  291.     $conf->MergeFile('radius.ini''_auth_radius');
  292.     $params array(
  293.                 "servers" => array(array($conf->value('_auth_radius''host'),
  294.                                          0,
  295.                                          $conf->value('_auth_radius''key'),
  296.                                          33)
  297.                                   ),
  298.                 "authtype" => $conf->value('_auth_radius''authtype')
  299.                 );
  300.     // start the PEAR::Auth system using RADIUS authentication with the parameters
  301.     // we have defined here for this config. Do not display a login box on error.
  302.     $a new Auth("RADIUS"$params''false);
  303.     $a->username $username;
  304.     $a->password $password;
  305.     $a->start();
  306.     $auth $a->getAuth();
  307.     if ($auth{
  308.       $this->_error = T_('Login failed: radius auth failed');
  309.     }
  310.     return $auth;
  311.   }
  312.  
  313.   /**
  314.   * LDAP auth method to login the user against an LDAP server
  315.   */
  316.   function _auth_via_ldap($username$password{
  317.     require_once 'Auth/Auth.php';
  318.     $conf ConfigReader::getInstance();
  319.     $conf->MergeFile('ldap.ini''_auth_ldap');
  320.     $params array(
  321.                 'url'        => $conf->value('_auth_ldap''url'),
  322.                 'basedn'     => $conf->value('_auth_ldap''basedn'),
  323.                 'userattr'   => $conf->value('_auth_ldap''userattr'),
  324.                 'useroc'     => $conf->value('_auth_ldap''userobjectclass'),          // for v 1.2
  325.                 'userfilter' => $conf->value('_auth_ldap''userfilter'),               // for v 1.3
  326.                 'debug'      => $conf->value('_auth_ldap''debug'true false,
  327.                 'version'    => intval($conf->value('_auth_ldap''version')),          // for v 1.3
  328.                 'start_tls'  => $conf->value('_auth_ldap''start_tls'true false  // requires patched version of LDAP auth
  329.                 );
  330.     // start the PEAR::Auth system using LDAP authentication with the parameters
  331.     // we have defined here for this config. Do not display a login box on error.
  332.     $a new Auth("LDAP"$params''false);
  333.     $a->username $username;
  334.     $a->password $password;
  335.     $a->start();
  336.     $auth $a->getAuth();
  337.     if ($auth{
  338.       $this->_error = T_('Login failed: ldap auth failed');
  339.     }
  340.     return $auth;
  341.   }
  342.  
  343.   /**
  344.   *
  345.   */
  346.   function _auth_local($username$password{
  347.     $conf ConfigReader::getInstance();
  348.     $passOK check_password($password$this->user_row['passwd']);
  349.     if ($passOK{
  350.       $this->_error = T_('Login failed: bad password');
  351.     }
  352.     if ($passOK && $conf->value('auth''convertEntries'false)
  353.                 && passwordHashType($this->user_row['passwd']!= $conf->value('auth''LocalPassToken')) {
  354.       $this->updatePassword($password);
  355.     }
  356.     return $passOK;
  357.   }
  358.  
  359.   function isMe($id{
  360.     return $id == $this->uid;
  361.   }
  362.  
  363.   function getRemoteIP({
  364.     return (getenv('HTTP_X_FORWARDED_FOR')
  365.            ?  getenv('HTTP_X_FORWARDED_FOR')
  366.            :  getenv('REMOTE_ADDR'));
  367.   }
  368.  
  369.  
  370.   /**
  371.   * @global string db table prefix
  372.   */
  373.   function updatePassword($pass{
  374.     global $TABLEPREFIX;
  375.     logmsg(8"Updating password entry to new hash scheme for user {$this->user_row['id']}");
  376.     $enc =qw(makePasswordHash($pass));
  377.     db_quiet("UPDATE {$TABLEPREFIX}users SET passwd=$enc WHERE id='{$this->user_row['id']}'");
  378.   }
  379.  
  380. //BasicAuth
  381.  
  382.  
  383. ?>

Documentation generated on Tue, 06 Mar 2007 10:00:39 +0000 by phpDocumentor 1.3.0