[ Index ]
 

Code source de Horde 3.1.3

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/Horde/ -> Auth.php (source)

   1  <?php
   2  /**
   3   * The parameter name for the logout reason.
   4   */
   5  define('AUTH_REASON_PARAM', 'logout_reason');
   6  
   7  /**
   8   * The parameter name for the logout message used with type
   9   * AUTH_REASON_MESSAGE.
  10   */
  11  define('AUTH_REASON_MSG_PARAM', 'logout_msg');
  12  
  13  /**
  14   * The 'badlogin' reason.
  15   *
  16   * The following 'reasons' for the logout screen are recognized:
  17   * <pre>
  18   *   'badlogin'   --  Bad username and/or password
  19   *   'browser'    --  A browser change was detected
  20   *   'failed'     --  Login failed
  21   *   'logout'     --  Logout due to user request
  22   *   'message'    --  Logout with custom message in AUTH_REASON_MSG_PARAM
  23   *   'session'    --  Logout due to session expiration
  24   *   'sessionip'  --  Logout due to change of IP address during session
  25   * </pre>
  26   */
  27  define('AUTH_REASON_BADLOGIN', 'badlogin');
  28  
  29  /**
  30   * The 'browser' reason.
  31   */
  32  define('AUTH_REASON_BROWSER', 'browser');
  33  
  34  /**
  35   * The 'failed' reason.
  36   */
  37  define('AUTH_REASON_FAILED', 'failed');
  38  
  39  /**
  40   * The 'expired' reason.
  41   */
  42  define('AUTH_REASON_EXPIRED', 'expired');
  43  
  44  /**
  45   * The 'logout' reason.
  46   */
  47  define('AUTH_REASON_LOGOUT', 'logout');
  48  
  49  /**
  50   * The 'message' reason.
  51   */
  52  define('AUTH_REASON_MESSAGE', 'message');
  53  
  54  /**
  55   * The 'session' reason.
  56   */
  57  define('AUTH_REASON_SESSION', 'session');
  58  
  59  /**
  60   * The 'sessionip' reason.
  61   */
  62  define('AUTH_REASON_SESSIONIP', 'sessionip');
  63  
  64  /**
  65   * The Auth:: class provides a common abstracted interface into the various
  66   * backends for the Horde authentication system.
  67   *
  68   * $Horde: framework/Auth/Auth.php,v 1.142.10.23 2006/08/14 02:48:48 chuck Exp $
  69   *
  70   * Copyright 1999-2006 Chuck Hagenbuch <chuck@horde.org>
  71   *
  72   * See the enclosed file COPYING for license information (LGPL). If you
  73   * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  74   *
  75   * @author  Chuck Hagenbuch <chuck@horde.org>
  76   * @since   Horde 1.3
  77   * @package Horde_Auth
  78   */
  79  class Auth {
  80  
  81      /**
  82       * An array of capabilities, so that the driver can report which
  83       * operations it supports and which it doesn't.
  84       *
  85       * @var array
  86       */
  87      var $capabilities = array('add'           => false,
  88                                'update'        => false,
  89                                'resetpassword' => false,
  90                                'remove'        => false,
  91                                'list'          => false,
  92                                'groups'        => false,
  93                                'transparent'   => false);
  94  
  95      /**
  96       * Hash containing parameters.
  97       *
  98       * @var array
  99       */
 100      var $_params = array();
 101  
 102      /**
 103       * The credentials currently being authenticated.
 104       *
 105       * @access protected
 106       *
 107       * @var array
 108       */
 109      var $_authCredentials = array();
 110  
 111      /**
 112       * Returns the name of the concrete Auth implementation.
 113       *
 114       * @return string  The Auth implementation name.
 115       */
 116      function getDriver()
 117      {
 118          return str_replace('auth_', '', strtolower(get_class($this)));
 119      }
 120  
 121      /**
 122       * Finds out if a set of login credentials are valid, and if requested,
 123       * mark the user as logged in in the current session.
 124       *
 125       * @param string $userId      The userId to check.
 126       * @param array $credentials  The credentials to check.
 127       * @param boolean $login      Whether to log the user in. If false, we'll
 128       *                            only test the credentials and won't modify
 129       *                            the current session. Defaults to true.
 130       * @param string $realm       The authentication realm to check.
 131       *
 132       * @return boolean  Whether or not the credentials are valid.
 133       */
 134      function authenticate($userId, $credentials, $login = true, $realm = null)
 135      {
 136          global $conf;
 137  
 138          $auth = false;
 139          $userId = trim($userId);
 140  
 141          if (!empty($conf['hooks']['preauthenticate'])) {
 142              include_once HORDE_BASE . '/config/hooks.php';
 143              if (function_exists('_horde_hook_preauthenticate')) {
 144                  if (!call_user_func('_horde_hook_preauthenticate', $userId, $credentials, $realm)) {
 145                      if ($this->_getAuthError() != AUTH_REASON_MESSAGE) {
 146                          $this->_setAuthError(AUTH_REASON_FAILED);
 147                      }
 148                      return false;
 149                  }
 150              }
 151          }
 152  
 153          /* Store the credentials being checked so that subclasses can modify
 154           * them if necessary (like transparent auth does). */
 155          $this->_authCredentials = array(
 156              'userId' => $userId,
 157              'credentials' => $credentials,
 158              'realm' => $realm,
 159              'changeRequested' => false
 160          );
 161  
 162          if ($authenticated = $this->_authenticate($userId, $credentials)) {
 163              if (is_a($authenticated, 'PEAR_Error')) {
 164                  return false;
 165              }
 166              if (!empty($conf['hooks']['postauthenticate'])) {
 167                  include_once HORDE_BASE . '/config/hooks.php';
 168                  if (function_exists('_horde_hook_postauthenticate')) {
 169                      if (!call_user_func('_horde_hook_postauthenticate', $userId, $credentials, $realm)) {
 170                          if ($this->_getAuthError() != AUTH_REASON_MESSAGE) {
 171                              $this->_setAuthError(AUTH_REASON_FAILED);
 172                          }
 173                          return false;
 174                      }
 175                  }
 176              }
 177  
 178              if ($login) {
 179                  $this->setAuth($this->_authCredentials['userId'],
 180                                 $this->_authCredentials['credentials'],
 181                                 $this->_authCredentials['realm'],
 182                                 $this->_authCredentials['changeRequested']);
 183                  $auth = true;
 184              } else {
 185                  if (!$this->_checkSessionIP()) {
 186                      $this->_setAuthError(AUTH_REASON_SESSIONIP);
 187                      return false;
 188                  } elseif (!$this->_checkBrowserString()) {
 189                      $this->_setAuthError(AUTH_REASON_BROWSER);
 190                      return false;
 191                  }
 192                  $auth = true;
 193              }
 194          }
 195  
 196          return $auth;
 197      }
 198  
 199      /**
 200       * Formats a password using the current encryption.
 201       *
 202       * @param string $plaintext      The plaintext password to encrypt.
 203       * @param string $salt           The salt to use to encrypt the password.
 204       *                               If not present, a new salt will be
 205       *                               generated.
 206       * @param string $encryption     The kind of pasword encryption to use.
 207       *                               Defaults to md5-hex.
 208       * @param boolean $show_encrypt  Some password systems prepend the kind of
 209       *                               encryption to the crypted password ({SHA},
 210       *                               etc). Defaults to false.
 211       *
 212       * @return string  The encrypted password.
 213       */
 214      function getCryptedPassword($plaintext, $salt = '',
 215                                  $encryption = 'md5-hex', $show_encrypt = false)
 216      {
 217          /* Get the salt to use. */
 218          $salt = Auth::getSalt($encryption, $salt, $plaintext);
 219  
 220          /* Encrypt the password. */
 221          switch ($encryption) {
 222          case 'plain':
 223              return $plaintext;
 224  
 225          case 'msad':
 226              return String::convertCharset('"' . $plaintext . '"', 'ISO-8859-1', 'UTF-16LE');
 227  
 228          case 'sha':
 229              $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext));
 230              return ($show_encrypt) ? '{SHA}' . $encrypted : $encrypted;
 231  
 232          case 'crypt':
 233          case 'crypt-des':
 234          case 'crypt-md5':
 235          case 'crypt-blowfish':
 236              return ($show_encrypt ? '{crypt}' : '') . crypt($plaintext, $salt);
 237  
 238          case 'md5-base64':
 239              $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext));
 240              return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;
 241  
 242          case 'ssha':
 243              $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext . $salt) . $salt);
 244              return ($show_encrypt) ? '{SSHA}' . $encrypted : $encrypted;
 245  
 246          case 'smd5':
 247              $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext . $salt) . $salt);
 248              return ($show_encrypt) ? '{SMD5}' . $encrypted : $encrypted;
 249  
 250          case 'aprmd5':
 251              $length = strlen($plaintext);
 252              $context = $plaintext . '$apr1$' . $salt;
 253              $binary = Auth::_bin(md5($plaintext . $salt . $plaintext));
 254  
 255              for ($i = $length; $i > 0; $i -= 16) {
 256                  $context .= substr($binary, 0, ($i > 16 ? 16 : $i));
 257              }
 258              for ($i = $length; $i > 0; $i >>= 1) {
 259                  $context .= ($i & 1) ? chr(0) : $plaintext{0};
 260              }
 261  
 262              $binary = Auth::_bin(md5($context));
 263  
 264              for ($i = 0; $i < 1000; $i++) {
 265                  $new = ($i & 1) ? $plaintext : substr($binary, 0,16);
 266                  if ($i % 3) {
 267                      $new .= $salt;
 268                  }
 269                  if ($i % 7) {
 270                      $new .= $plaintext;
 271                  }
 272                  $new .= ($i & 1) ? substr($binary, 0, 16) : $plaintext;
 273                  $binary = Auth::_bin(md5($new));
 274              }
 275  
 276              $p = array();
 277              for ($i = 0; $i < 5; $i++) {
 278                  $k = $i + 6;
 279                  $j = $i + 12;
 280                  if ($j == 16) {
 281                      $j = 5;
 282                  }
 283                  $p[] = Auth::_toAPRMD5((ord($binary[$i]) << 16) |
 284                                         (ord($binary[$k]) << 8) |
 285                                         (ord($binary[$j])),
 286                                         5);
 287              }
 288  
 289              return '$apr1$' . $salt . '$' . implode('', $p) . Auth::_toAPRMD5(ord($binary[11]), 3);
 290  
 291          case 'md5-hex':
 292          default:
 293              return ($show_encrypt) ? '{MD5}' . md5($plaintext) : md5($plaintext);
 294          }
 295      }
 296  
 297      /**
 298       * Returns a salt for the appropriate kind of password encryption.
 299       * Optionally takes a seed and a plaintext password, to extract the seed
 300       * of an existing password, or for encryption types that use the plaintext
 301       * in the generation of the salt.
 302       *
 303       * @param string $encryption  The kind of pasword encryption to use.
 304       *                            Defaults to md5-hex.
 305       * @param string $seed        The seed to get the salt from (probably a
 306       *                            previously generated password). Defaults to
 307       *                            generating a new seed.
 308       * @param string $plaintext   The plaintext password that we're generating
 309       *                            a salt for. Defaults to none.
 310       *
 311       * @return string  The generated or extracted salt.
 312       */
 313      function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '')
 314      {
 315          // Encrypt the password.
 316          switch ($encryption) {
 317          case 'crypt':
 318          case 'crypt-des':
 319              if ($seed) {
 320                  return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 2);
 321              } else {
 322                  return substr(md5(mt_rand()), 0, 2);
 323              }
 324  
 325          case 'crypt-md5':
 326              if ($seed) {
 327                  return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 12);
 328              } else {
 329                  return '$1$' . substr(md5(mt_rand()), 0, 8) . '$';
 330              }
 331  
 332          case 'crypt-blowfish':
 333              if ($seed) {
 334                  return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 16);
 335              } else {
 336                  return '$2$' . substr(md5(mt_rand()), 0, 12) . '$';
 337              }
 338  
 339          case 'ssha':
 340              if ($seed) {
 341                  return substr(preg_replace('|^{SSHA}|', '', $seed), -20);
 342              } else {
 343                  return mhash_keygen_s2k(MHASH_SHA1, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
 344              }
 345  
 346          case 'smd5':
 347              if ($seed) {
 348                  return substr(preg_replace('|^{SMD5}|', '', $seed), -16);
 349              } else {
 350                  return mhash_keygen_s2k(MHASH_MD5, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
 351              }
 352  
 353          case 'aprmd5':
 354              /* 64 characters that are valid for APRMD5 passwords. */
 355              $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
 356  
 357              if ($seed) {
 358                  return substr(preg_replace('/^\$apr1\$(.{8}).*/', '\\1', $seed), 0, 8);
 359              } else {
 360                  $salt = '';
 361                  for ($i = 0; $i < 8; $i++) {
 362                      $salt .= $APRMD5{rand(0, 63)};
 363                  }
 364                  return $salt;
 365              }
 366  
 367          default:
 368              return '';
 369          }
 370      }
 371  
 372      /**
 373       * Generates a random, hopefully pronounceable, password. This can be used
 374       * when resetting automatically a user's password.
 375       *
 376       * @return string A random password
 377       */
 378      function genRandomPassword()
 379      {
 380          $vowels    = 'aeiouy';
 381          $constants = 'bcdfghjklmnpqrstvwxz';
 382          $numbers   = '0123456789';
 383  
 384          /* Alternate constant and vowel random chars with two random numbers
 385           * at the end. This should produce a fairly pronounceable password. */
 386          $chars[0] = substr($constants, mt_rand(0, strlen($constants) - 1), 1);
 387          $chars[1] = substr($vowels, mt_rand(0, strlen($vowels) - 1), 1);
 388          $chars[2] = substr($constants, mt_rand(0, strlen($constants) - 1), 1);
 389          $chars[3] = substr($vowels, mt_rand(0, strlen($vowels) - 1), 1);
 390          $chars[4] = substr($constants, mt_rand(0, strlen($constants) - 1), 1);
 391          $chars[5] = substr($numbers, mt_rand(0, strlen($numbers) - 1), 1);
 392          $chars[6] = substr($numbers, mt_rand(0, strlen($numbers) - 1), 1);
 393  
 394          return implode('', $chars);
 395      }
 396  
 397      /**
 398       * Adds a set of authentication credentials.
 399       *
 400       * @abstract
 401       *
 402       * @param string $userId      The userId to add.
 403       * @param array $credentials  The credentials to use.
 404       *
 405       * @return mixed  True on success or a PEAR_Error object on failure.
 406       */
 407      function addUser($userId, $credentials)
 408      {
 409          return PEAR::raiseError('unsupported');
 410      }
 411  
 412      /**
 413       * Updates a set of authentication credentials.
 414       *
 415       * @abstract
 416       *
 417       * @param string $oldID        The old userId.
 418       * @param string $newID        The new userId.
 419       * @param array $credentials   The new credentials
 420       *
 421       * @return mixed  True on success or a PEAR_Error object on failure.
 422       */
 423      function updateUser($oldID, $newID, $credentials)
 424      {
 425          return PEAR::raiseError('unsupported');
 426      }
 427  
 428      /**
 429       * Deletes a set of authentication credentials.
 430       *
 431       * @abstract
 432       *
 433       * @param string $userId  The userId to delete.
 434       *
 435       * @return mixed  True on success or a PEAR_Error object on failure.
 436       */
 437      function removeUser($userId)
 438      {
 439          return PEAR::raiseError('unsupported');
 440      }
 441  
 442      /**
 443       * Calls all applications' removeUser API methods.
 444       *
 445       * @param string $userId  The userId to delete.
 446       *
 447       * @return mixed  True on success or a PEAR_Error object on failure.
 448       */
 449      function removeUserData($userId)
 450      {
 451          global $registry;
 452  
 453          foreach ($registry->listApps(array('notoolbar', 'hidden', 'active', 'admin')) as $app) {
 454              if ($registry->hasMethod('removeUserData', $app)) {
 455                  if (is_a($result = $registry->callByPackage($app, 'removeUserData', array($userId)), 'PEAR_Error')) {
 456                      return $result;
 457                  }
 458              }
 459          }
 460  
 461          return false;
 462      }
 463  
 464      /**
 465       * Lists all users in the system.
 466       *
 467       * @abstract
 468       *
 469       * @return mixed  The array of userIds, or a PEAR_Error object on failure.
 470       */
 471      function listUsers()
 472      {
 473          return PEAR::raiseError('unsupported');
 474      }
 475  
 476      /**
 477       * Checks if $userId exists in the system.
 478       *
 479       * @abstract
 480       *
 481       * @param string $userId User ID for which to check
 482       *
 483       * @return boolean  Whether or not $userId already exists.
 484       */
 485      function exists($userId)
 486      {
 487          return in_array($userId, $this->listUsers());
 488      }
 489  
 490      /**
 491       * Automatic authentication: Finds out if the client matches an allowed IP
 492       * block.
 493       *
 494       * @abstract
 495       *
 496       * @return boolean  Whether or not the client is allowed.
 497       */
 498      function transparent()
 499      {
 500          return false;
 501      }
 502  
 503      /**
 504       * Checks if there is a session with valid auth information. for the
 505       * specified user. If there isn't, but the configured Auth driver supports
 506       * transparent authentication, then we try that.
 507       *
 508       * @param string $realm  The authentication realm to check.
 509       *
 510       * @return boolean  Whether or not the user is authenticated.
 511       */
 512      function isAuthenticated($realm = null)
 513      {
 514          if (isset($_SESSION['__auth'])) {
 515              if (!empty($_SESSION['__auth']['authenticated']) &&
 516                  !empty($_SESSION['__auth']['userId']) &&
 517                  ($_SESSION['__auth']['realm'] == $realm)) {
 518                  if (!Auth::_checkSessionIP()) {
 519                      Auth::_setAuthError(AUTH_REASON_SESSIONIP);
 520                      return false;
 521                  } elseif (!Auth::_checkBrowserString()) {
 522                      Auth::_setAuthError(AUTH_REASON_BROWSER);
 523                      return false;
 524                  } else {
 525                      return true;
 526                  }
 527              }
 528          }
 529  
 530          // Try transparent authentication now.
 531          $auth = &Auth::singleton($GLOBALS['conf']['auth']['driver']);
 532          if ($auth->hasCapability('transparent') &&
 533              $auth->transparent()) {
 534              return Auth::isAuthenticated($realm);
 535          }
 536  
 537          return false;
 538      }
 539  
 540      /**
 541       * Returns the currently logged in user, if there is one.
 542       *
 543       * @return mixed  The userId of the current user, or false if no user is
 544       *                logged in.
 545       */
 546      function getAuth()
 547      {
 548          if (isset($_SESSION['__auth'])) {
 549              if (!empty($_SESSION['__auth']['authenticated']) &&
 550                  !empty($_SESSION['__auth']['userId'])) {
 551                  return $_SESSION['__auth']['userId'];
 552              }
 553          }
 554  
 555          return false;
 556      }
 557  
 558      /**
 559       * Return whether the authentication backend requested a password change.
 560       *
 561       * @return boolean Whether the backend requested a password change.
 562       */
 563      function isPasswordChangeRequested()
 564      {
 565          if (isset($_SESSION['__auth']) &&
 566              !empty($_SESSION['__auth']['authenticated']) &&
 567              !empty($_SESSION['__auth']['changeRequested'])) {
 568              return true;
 569          }
 570  
 571          return false;
 572      }
 573  
 574      /**
 575       * Returns the curently logged-in user without any domain information
 576       * (e.g., bob@example.com would be returned as 'bob').
 577       *
 578       * @return mixed  The user ID of the current user, or false if no user
 579       *                is logged in.
 580       */
 581      function getBareAuth()
 582      {
 583          $user = Auth::getAuth();
 584          if ($user) {
 585              $pos = strpos($user, '@');
 586              if ($pos !== false) {
 587                  $user = substr($user, 0, $pos);
 588              }
 589          }
 590  
 591          return $user;
 592      }
 593  
 594      /**
 595       * Returns the domain of currently logged-in user (e.g., bob@example.com
 596       * would be returned as 'example.com').
 597       *
 598       * @since Horde 3.0.6
 599       *
 600       * @return mixed  The domain suffix of the current user, or false.
 601       */
 602      function getAuthDomain()
 603      {
 604          if ($user = Auth::getAuth()) {
 605              $pos = strpos($user, '@');
 606              if ($pos !== false) {
 607                  return substr($user, $pos + 1);
 608              }
 609          }
 610  
 611          return false;
 612      }
 613  
 614      /**
 615       * Returns the requested credential for the currently logged in user, if
 616       * present.
 617       *
 618       * @param string $credential  The credential to retrieve.
 619       *
 620       * @return mixed  The requested credential, or false if no user is
 621       *                logged in.
 622       */
 623      function getCredential($credential)
 624      {
 625          if (!empty($_SESSION['__auth']) &&
 626              !empty($_SESSION['__auth']['authenticated'])) {
 627              require_once 'Horde/Secret.php';
 628              $credentials = @unserialize(Secret::read(Secret::getKey('auth'), $_SESSION['__auth']['credentials']));
 629          } else {
 630              return false;
 631          }
 632  
 633          if (is_array($credentials) &&
 634              isset($credentials[$credential])) {
 635              return $credentials[$credential];
 636          } else {
 637              return false;
 638          }
 639      }
 640  
 641      /**
 642       * Sets the requested credential for the currently logged in user.
 643       *
 644       * @param string $credential  The credential to set.
 645       * @param string $value       The value to set the credential to.
 646       */
 647      function setCredential($credential, $value)
 648      {
 649          if (!empty($_SESSION['__auth']) &&
 650              !empty($_SESSION['__auth']['authenticated'])) {
 651              require_once 'Horde/Secret.php';
 652              $credentials = @unserialize(Secret::read(Secret::getKey('auth'), $_SESSION['__auth']['credentials']));
 653              if (is_array($credentials)) {
 654                  $credentials[$credential] = $value;
 655              } else {
 656                  $credentials = array($credential => $value);
 657              }
 658              $_SESSION['__auth']['credentials'] = Secret::write(Secret::getKey('auth'), serialize($credentials));
 659          }
 660      }
 661  
 662      /**
 663       * Sets a variable in the session saying that authorization has succeeded,
 664       * note which userId was authorized, and note when the login took place.
 665       *
 666       * If a user name hook was defined in the configuration, it gets applied
 667       * to the userId at this point.
 668       *
 669       * @param string $userId            The userId who has been authorized.
 670       * @param array $credentials        The credentials of the user.
 671       * @param string $realm             The authentication realm to use.
 672       * @param boolean $changeRequested  Whether to request that the user change
 673       *                                  their password.
 674       */
 675      function setAuth($userId, $credentials, $realm = null, $changeRequested = false)
 676      {
 677          $userId = trim($userId);
 678          $userId = Auth::addHook($userId);
 679  
 680          /* If we're already set with this userId, don't continue. */
 681          if (isset($_SESSION['__auth']['userId']) &&
 682              $_SESSION['__auth']['userId'] == $userId) {
 683              return;
 684          }
 685  
 686          /* Clear any existing info. */
 687          $this->clearAuth($realm);
 688  
 689          require_once 'Horde/Secret.php';
 690          $credentials = Secret::write(Secret::getKey('auth'), serialize($credentials));
 691  
 692          if (!empty($realm)) {
 693              $userId .= '@' . $realm;
 694          }
 695  
 696          $_SESSION['__auth'] = array(
 697              'authenticated' => true,
 698              'userId' => $userId,
 699              'credentials' => $credentials,
 700              'realm' => $realm,
 701              'timestamp' => time(),
 702              'remote_addr' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null,
 703              'browser' => $GLOBALS['browser']->getAgentString(),
 704              'changeRequested' => $changeRequested
 705          );
 706  
 707          /* Reload preferences for the new user. */
 708          $GLOBALS['registry']->loadPrefs();
 709          NLS::setLang($GLOBALS['prefs']->getValue('language'));
 710  
 711          /* Fetch the user's last login time. */
 712          $old_login = @unserialize($GLOBALS['prefs']->getValue('last_login'));
 713  
 714          /* Display it, if we have a notification object and the
 715           * show_last_login preference is active. */
 716          if (isset($GLOBALS['notification']) && $GLOBALS['prefs']->getValue('show_last_login')) {
 717              if (empty($old_login['time'])) {
 718                  $GLOBALS['notification']->push(_("Last login: Never"), 'horde.message');
 719              } else {
 720                  if (empty($old_login['host'])) {
 721                      $GLOBALS['notification']->push(sprintf(_("Last login: %s"), strftime('%c', $old_login['time'])), 'horde.message');
 722                  } else {
 723                      $GLOBALS['notification']->push(sprintf(_("Last login: %s from %s"), strftime('%c', $old_login['time']), $old_login['host']), 'horde.message');
 724                  }
 725              }
 726          }
 727  
 728          // Set the user's last_login information.
 729          $host = empty($_SERVER['HTTP_X_FORWARDED_FOR'])
 730              ? $_SERVER['REMOTE_ADDR']
 731              : $_SERVER['HTTP_X_FORWARDED_FOR'];
 732          $last_login = array('time' => time(),
 733                              'host' => @gethostbyaddr($host));
 734          $GLOBALS['prefs']->setValue('last_login', serialize($last_login));
 735  
 736          if ($changeRequested) {
 737              $GLOBALS['notification']->push(_("Your password has expired."),
 738                                             'horde.message');
 739              if ($this->hasCapability('update')) {
 740                  /* A bit of a kludge.  URL is set from the login screen, but
 741                   * we aren't completely certain we got here from the login
 742                   * screen.  So any screen which calls setAuth() which has a
 743                   * url will end up going there.  Should be OK. */
 744                  $url_param = Util::getFormData('url');
 745  
 746                  if ($url_param) {
 747                      $url = Horde::url(Util::removeParameter($url_param,
 748                                                              session_name()),
 749                                        true);
 750                      $return_to = $GLOBALS['registry']->get('webroot', 'horde') .
 751                                   '/index.php';
 752                      $return_to = Util::addParameter($return_to, 'url', $url);
 753                  } else {
 754                      $return_to = Horde::url($GLOBALS['registry']->get('webroot', 'horde')
 755                                   . '/index.php');
 756                  }
 757  
 758                  $url = Horde::applicationUrl('services/changepassword.php');
 759                  $url = Util::addParameter($url,
 760                                            array('return_to' => $return_to),
 761                                            null, false);
 762  
 763                  header('Location: ' . $url);
 764                  exit;
 765              }
 766          }
 767      }
 768  
 769      /**
 770       * Clears any authentication tokens in the current session.
 771       *
 772       * @param string $realm  The authentication realm to clear.
 773       */
 774      function clearAuth($realm = null)
 775      {
 776          if (!empty($realm) && isset($_SESSION['__auth'][$realm])) {
 777              $_SESSION['__auth'][$realm] = array();
 778              $_SESSION['__auth'][$realm]['authenticated'] = false;
 779          } elseif (isset($_SESSION['__auth'])) {
 780              $_SESSION['__auth'] = array();
 781              $_SESSION['__auth']['authenticated'] = false;
 782          }
 783  
 784          /* Remove the user's cached preferences if they are present. */
 785          if (isset($GLOBALS['registry'])) {
 786              $GLOBALS['registry']->unloadPrefs();
 787          }
 788      }
 789  
 790      /**
 791       * Is the current user an administrator?
 792       *
 793       * @param string $permission  Allow users with this permission admin access
 794       *                            in the current context.
 795       * @param integer $permlevel  The level of permissions to check for
 796       *                            (PERMS_EDIT, PERMS_DELETE, etc). Defaults
 797       *                            to PERMS_EDIT.
 798       * @param string $user        The user to check. Defaults to Auth::getAuth().
 799       *
 800       * @return boolean  Whether or not this is an admin user.
 801       */
 802      function isAdmin($permission = null, $permlevel = null, $user = null)
 803      {
 804          global $conf;
 805  
 806          if ($user === null) {
 807              $user = Auth::getAuth();
 808          }
 809  
 810          if (@is_array($conf['auth']['admins'])) {
 811              if ($user && in_array($user, $conf['auth']['admins'])) {
 812                  return true;
 813              }
 814          }
 815  
 816          if (!is_null($permission)) {
 817              if (is_null($permlevel)) {
 818                  $permlevel = PERMS_EDIT;
 819              }
 820              return $GLOBALS['perms']->hasPermission($permission, $user, $permlevel);
 821          }
 822  
 823          return false;
 824      }
 825  
 826      /**
 827       * Applies a hook defined by the function _username_hook_frombackend() to
 828       * the given user name if this function exists and user hooks are enabled.
 829       *
 830       * This method should be called if a backend's user name needs to be
 831       * converted to a (unique) Horde user name.
 832       *
 833       * @param string $userId  The original user name.
 834       *
 835       * @return string  The user name with the hook applied to it.
 836       */
 837      function addHook($userId)
 838      {
 839          global $conf;
 840  
 841          if (!empty($conf['hooks']['username'])) {
 842              require_once HORDE_BASE . '/config/hooks.php';
 843              if (function_exists('_username_hook_frombackend')) {
 844                  $userId = call_user_func('_username_hook_frombackend', $userId);
 845              }
 846          }
 847  
 848          return $userId;
 849      }
 850  
 851      /**
 852       * Applies a hook defined by the function _username_hook_tobackend() to
 853       * the given user name if this function exists and user hooks are enabled.
 854       *
 855       * This method should be called if a Horde user name needs to be converted
 856       * to a backend's user name or displayed to the user.
 857       *
 858       * @param string $userId  The Horde user name.
 859       *
 860       * @return string  The user name with the hook applied to it.
 861       */
 862      function removeHook($userId)
 863      {
 864          global $conf;
 865  
 866          if (!empty($conf['hooks']['username'])) {
 867              require_once HORDE_BASE . '/config/hooks.php';
 868              if (function_exists('_username_hook_tobackend')) {
 869                  $userId = call_user_func('_username_hook_tobackend', $userId);
 870              }
 871          }
 872  
 873          return $userId;
 874      }
 875  
 876      /**
 877       * Queries the current Auth object to find out if it supports the given
 878       * capability.
 879       *
 880       * @param string $capability  The capability to test for.
 881       *
 882       * @return boolean  Whether or not the capability is supported.
 883       */
 884      function hasCapability($capability)
 885      {
 886          return !empty($this->capabilities[$capability]);
 887      }
 888  
 889      /**
 890       * Returns the URI of the login screen for the current authentication
 891       * method.
 892       *
 893       * @param string $app  The application to use.
 894       * @param string $url  The URL to redirect to after login.
 895       *
 896       * @return string  The login screen URI.
 897       */
 898      function getLoginScreen($app = 'horde', $url = '')
 899      {
 900          global $conf;
 901          $auth = &Auth::singleton($conf['auth']['driver']);
 902          return $auth->_getLoginScreen($app, $url);
 903      }
 904  
 905      /**
 906       * Returns the named parameter for the current auth driver.
 907       *
 908       * @param string $param  The parameter to fetch.
 909       *
 910       * @return string  The parameter's value.
 911       */
 912      function getParam($param)
 913      {
 914          return isset($this->_params[$param]) ? $this->_params[$param] : null;
 915      }
 916  
 917      /**
 918       * Returns the name of the authentication provider.
 919       *
 920       * @param string $driver  Used by recursive calls when untangling composite
 921       *                        auth.
 922       * @param array  $params  Used by recursive calls when untangling composite
 923       *                        auth.
 924       *
 925       * @return string  The name of the driver currently providing
 926       *                 authentication.
 927       */
 928      function getProvider($driver = null, $params = null)
 929      {
 930          global $conf;
 931  
 932          if (is_null($driver)) {
 933              $driver = $conf['auth']['driver'];
 934          }
 935          if (is_null($params)) {
 936              $params = Horde::getDriverConfig('auth',
 937                  is_array($driver) ? $driver[1] : $driver);
 938          }
 939  
 940          if ($driver == 'application') {
 941              return isset($params['app']) ? $params['app'] : 'application';
 942          } elseif ($driver == 'composite') {
 943              if (($login_driver = Auth::_getDriverByParam('loginscreen_switch', $params)) &&
 944                  !empty($params['drivers'][$login_driver])) {
 945                  return Auth::getProvider($params['drivers'][$login_driver]['driver'],
 946                                           isset($params['drivers'][$login_driver]['params']) ? $params['drivers'][$login_driver]['params'] : null);
 947              }
 948              return 'composite';
 949          } else {
 950              return $driver;
 951          }
 952      }
 953  
 954      /**
 955       * Returns the logout reason.
 956       *
 957       * @return string One of the logout reasons (see the AUTH_LOGOUT_*
 958       *                constants for the valid reasons).  Returns null if there
 959       *                is no logout reason present.
 960       */
 961      function getLogoutReason()
 962      {
 963          if (isset($GLOBALS['__autherror']['type'])) {
 964              return $GLOBALS['__autherror']['type'];
 965          } else {
 966              return Util::getFormData(AUTH_REASON_PARAM);
 967          }
 968      }
 969  
 970      /**
 971       * Returns the status string to use for logout messages.
 972       *
 973       * @return string  The logout reason string.
 974       */
 975      function getLogoutReasonString()
 976      {
 977          switch (Auth::getLogoutReason()) {
 978          case AUTH_REASON_SESSION:
 979              $text = sprintf(_("Your %s session has expired. Please login again."), $GLOBALS['registry']->get('name'));
 980              break;
 981  
 982          case AUTH_REASON_SESSIONIP:
 983              $text = sprintf(_("Your Internet Address has changed since the beginning of your %s session. To protect your security, you must login again."), $GLOBALS['registry']->get('name'));
 984              break;
 985  
 986          case AUTH_REASON_BROWSER:
 987              $text = sprintf(_("Your browser appears to have changed since the beginning of your %s session. To protect your security, you must login again."), $GLOBALS['registry']->get('name'));
 988              break;
 989  
 990          case AUTH_REASON_LOGOUT:
 991              $text = _("You have been logged out.");
 992              break;
 993  
 994          case AUTH_REASON_FAILED:
 995              $text = _("Login failed.");
 996              break;
 997  
 998          case AUTH_REASON_BADLOGIN:
 999              $text = _("Login failed because your username or password was entered incorrectly.");
1000              break;
1001  
1002          case AUTH_REASON_EXPIRED:
1003              $text = _("Your login has expired.");
1004              break;
1005  
1006          case AUTH_REASON_MESSAGE:
1007              if (isset($GLOBALS['__autherror']['msg'])) {
1008                  $text = $GLOBALS['__autherror']['msg'];
1009              } else {
1010                  $text = Util::getFormData(AUTH_REASON_MSG_PARAM);
1011              }
1012              break;
1013  
1014          default:
1015              $text = '';
1016              break;
1017          }
1018  
1019          return $text;
1020      }
1021  
1022      /**
1023       * Generates the correct parameters to pass to the given logout URL.
1024       *
1025       * If no reason/msg is passed in, use the current global authentication
1026       * error message.
1027       *
1028       * @param string $url     The URL to redirect to.
1029       * @param string $reason  The reason for logout.
1030       * @param string $msg     If reason is AUTH_REASON_MESSAGE, the message to
1031       *                        display to the user.
1032       * @return string The formatted URL
1033       */
1034      function addLogoutParameters($url, $reason = null, $msg = null)
1035      {
1036          if (is_null($reason)) {
1037              $reason = Auth::getLogoutReason();
1038          }
1039  
1040          if ($reason) {
1041              $url = Util::addParameter($url, AUTH_REASON_PARAM, $reason, false);
1042              if ($reason == AUTH_REASON_MESSAGE) {
1043                  if (is_null($msg)) {
1044                      $msg = Auth::getLogoutReasonString();
1045                  }
1046                  $url = Util::addParameter($url, AUTH_REASON_MSG_PARAM, $msg, false);
1047              }
1048          }
1049  
1050          return $url;
1051      }
1052  
1053      /**
1054       * Returns the URI of the login screen for this authentication object.
1055       *
1056       * @access private
1057       *
1058       * @param string $app  The application to use.
1059       * @param string $url  The URL to redirect to after login.
1060       *
1061       * @return string  The login screen URI.
1062       */
1063      function _getLoginScreen($app = 'horde', $url = '')
1064      {
1065          $login = Horde::url($GLOBALS['registry']->get('webroot', $app) . '/login.php', true);
1066          if (!empty($url)) {
1067              $login = Util::addParameter($login, 'url', $url);
1068          }
1069          return $login;
1070      }
1071  
1072      /**
1073       * Authentication stub.
1074       *
1075       * @abstract
1076       * @access private
1077       *
1078       * @return boolean  False.
1079       */
1080      function _authenticate()
1081      {
1082          return false;
1083      }
1084  
1085      /**
1086       * Sets the error message for an invalid authentication.
1087       *
1088       * @access private
1089       *
1090       * @param string $type  The type of error (AUTH_REASON constant).
1091       * @param string $msg   The error message/reason for invalid
1092       *                      authentication.
1093       */
1094      function _setAuthError($type, $msg = null)
1095      {
1096          $GLOBALS['__autherror'] = array();
1097          $GLOBALS['__autherror']['type'] = $type;
1098          $GLOBALS['__autherror']['msg'] = $msg;
1099      }
1100  
1101      /**
1102       * Returns the error type for an invalid authentication or false on error.
1103       *
1104       * @access private
1105       *
1106       * @return mixed Error type or false on error
1107       */
1108      function _getAuthError()
1109      {
1110          if (isset($GLOBALS['__autherror']['type'])) {
1111              return $GLOBALS['__autherror']['type'];
1112          }
1113  
1114          return false;
1115      }
1116  
1117      /**
1118       * Returns the appropriate authentication driver, if any, selecting by the
1119       * specified parameter.
1120       *
1121       * @access private
1122       *
1123       * @param string $name          The parameter name.
1124       * @param array $params         The parameter list.
1125       * @param string $driverparams  A list of parameters to pass to the driver.
1126       *
1127       * @return mixed Return value or called user func or null if unavailable
1128       */
1129      function _getDriverByParam($name, $params, $driverparams = array())
1130      {
1131          if (isset($params[$name]) &&
1132              function_exists($params[$name])) {
1133              return call_user_func_array($params[$name], $driverparams);
1134          }
1135  
1136          return null;
1137      }
1138  
1139      /**
1140       * Performs check on session to see if IP Address has changed since the
1141       * last access.
1142       *
1143       * @access private
1144       *
1145       * @return boolean  True if IP Address is the same (or the check is
1146       *                  disabled), false if the address has changed.
1147       */
1148      function _checkSessionIP()
1149      {
1150          return (empty($GLOBALS['conf']['auth']['checkip']) ||
1151                  (isset($_SESSION['__auth']['remote_addr']) && $_SESSION['__auth']['remote_addr'] == $_SERVER['REMOTE_ADDR']));
1152      }
1153  
1154      /**
1155       * Performs check on session to see if browser string has changed since
1156       * the last access.
1157       *
1158       * @access private
1159       *
1160       * @return boolean  True if browser string is the same, false if the
1161       *                  string has changed.
1162       */
1163      function _checkBrowserString()
1164      {
1165          return (empty($GLOBALS['conf']['auth']['checkbrowser']) ||
1166                  $_SESSION['__auth']['browser'] == $GLOBALS['browser']->getAgentString());
1167      }
1168  
1169      /**
1170       * Converts to allowed 64 characters for APRMD5 passwords.
1171       *
1172       * @access private
1173       *
1174       * @param string  $value
1175       * @param integer $count
1176       *
1177       * @return string  $value converted to the 64 MD5 characters.
1178       */
1179      function _toAPRMD5($value, $count)
1180      {
1181          /* 64 characters that are valid for APRMD5 passwords. */
1182          $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
1183  
1184          $aprmd5 = '';
1185          $count = abs($count);
1186          while (--$count) {
1187              $aprmd5 .= $APRMD5[$value & 0x3f];
1188              $value >>= 6;
1189          }
1190          return $aprmd5;
1191      }
1192  
1193      /**
1194       * Converts hexadecimal string to binary data.
1195       *
1196       * @access private
1197       *
1198       * @param string $hex  Hex data.
1199       *
1200       * @return string  Binary data.
1201       */
1202      function _bin($hex)
1203      {
1204          $bin = '';
1205          $length = strlen($hex);
1206          for ($i = 0; $i < $length; $i += 2) {
1207              $tmp = sscanf(substr($hex, $i, 2), '%x');
1208              $bin .= chr(array_shift($tmp));
1209          }
1210          return $bin;
1211      }
1212  
1213      /**
1214       * Attempts to return a concrete Auth instance based on $driver.
1215       *
1216       * @param mixed $driver  The type of concrete Auth subclass to return. This
1217       *                       is based on the storage driver ($driver). The code
1218       *                       is dynamically included. If $driver is an array,
1219       *                       then we will look in $driver[0]/lib/Auth/ for the
1220       *                       subclass implementation named $driver[1].php.
1221       * @param array $params  A hash containing any additional configuration or
1222       *                       connection parameters a subclass might need.
1223       *
1224       * @return Auth  The newly created concrete Auth instance, or false on an
1225       *               error.
1226       */
1227      function &factory($driver, $params = null)
1228      {
1229          if (is_array($driver)) {
1230              $app = $driver[0];
1231              $driver = $driver[1];
1232          }
1233  
1234          $driver = basename($driver);
1235  
1236          if (empty($driver) || ($driver == 'none')) {
1237              $auth = &new Auth();
1238              return $auth;
1239          }
1240  
1241          if (is_null($params)) {
1242              $params = Horde::getDriverConfig('auth', $driver);
1243          }
1244  
1245          ini_set('track_errors', 1);
1246          $include_error = '';
1247          if (!empty($app)) {
1248              @include_once $GLOBALS['registry']->get('fileroot', $app) . '/lib/Auth/' . $driver . '.php';
1249          } else {
1250              @include_once 'Horde/Auth/' . $driver . '.php';
1251          }
1252          if (isset($php_errormsg)) {
1253              $include_error = $php_errormsg;
1254          }
1255          ini_restore('track_errors');
1256  
1257          $class = 'Auth_' . $driver;
1258          if (class_exists($class)) {
1259              $auth = &new $class($params);
1260          } else {
1261              $auth = PEAR::raiseError('Auth Driver (' . $class . ') not found' . ($include_error ? ': ' . $include_error : '') . '.');
1262          }
1263  
1264          return $auth;
1265      }
1266  
1267      /**
1268       * Attempts to return a reference to a concrete Auth instance based on
1269       * $driver. It will only create a new instance if no Auth instance with
1270       * the same parameters currently exists.
1271       *
1272       * This should be used if multiple authentication sources (and, thus,
1273       * multiple Auth instances) are required.
1274       *
1275       * This method must be invoked as: $var = &Auth::singleton()
1276       *
1277       * @param string $driver  The type of concrete Auth subclass to return.
1278       *                        This is based on the storage driver ($driver).
1279       *                        The code is dynamically included.
1280       * @param array $params   A hash containing any additional configuration or
1281       *                        connection parameters a subclass might need.
1282       *
1283       * @return Auth  The concrete Auth reference, or false on an error.
1284       */
1285      function &singleton($driver, $params = null)
1286      {
1287          static $instances = array();
1288  
1289          if (is_null($params)) {
1290              $params = Horde::getDriverConfig('auth',
1291                  is_array($driver) ? $driver[1] : $driver);
1292          }
1293  
1294          $signature = serialize(array($driver, $params));
1295          if (empty($instances[$signature])) {
1296              $instances[$signature] = &Auth::factory($driver, $params);
1297          }
1298  
1299          return $instances[$signature];
1300      }
1301  
1302  }


Généré le : Sun Feb 25 18:01:28 2007 par Balluche grâce à PHPXref 0.7