[ Index ] |
|
Code source de Horde 3.1.3 |
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 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |