X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fspecials%2FSpecialUserlogin.php;h=38d35490e8ed3a808cfd174004fe6d6297cc7ed2;hb=7d78861743a4c03519046d42f06d44cf437e7804;hp=21f1194fcddfd2a0dc01b86e3dcfe04d87a2a08d;hpb=566494709e3ce1ff97b3ad0ab6bf891bba6eb69a;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php index 21f1194fcd..38d35490e8 100644 --- a/includes/specials/SpecialUserlogin.php +++ b/includes/specials/SpecialUserlogin.php @@ -276,13 +276,17 @@ class LoginForm extends SpecialPage { } $this->setHeaders(); - // In the case where the user is already logged in, and was redirected to the login form from a - // page that requires login, do not show the login page. The use case scenario for this is when - // a user opens a large number of tabs, is redirected to the login page on all of them, and then - // logs in on one, expecting all the others to work properly. - // - // However, do show the form if it was visited intentionally (no 'returnto' is present). People - // who often switch between several accounts have grown accustomed to this behavior. + /** + * In the case where the user is already logged in, and was redirected to + * the login form from a page that requires login, do not show the login + * page. The use case scenario for this is when a user opens a large number + * of tabs, is redirected to the login page on all of them, and then logs + * in on one, expecting all the others to work properly. + * + * However, do show the form if it was visited intentionally (no 'returnto' + * is present). People who often switch between several accounts have grown + * accustomed to this behavior. + */ if ( $this->mType !== 'signup' && !$this->mPosted && @@ -357,10 +361,10 @@ class LoginForm extends SpecialPage { } $status = $this->addNewAccountInternal(); - LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt with mailed password', array( - 'event' => 'accountcreation', - 'status' => $status, - ) ); + LoggerFactory::getInstance( 'authmanager' )->info( + 'Account creation attempt with mailed password', + array( 'event' => 'accountcreation', 'status' => $status ) + ); if ( !$status->isGood() ) { $error = $status->getMessage(); $this->mainLoginForm( $error->toString() ); @@ -481,7 +485,7 @@ class LoginForm extends SpecialPage { * @return Status */ public function addNewAccountInternal() { - global $wgAuth, $wgMemc, $wgAccountCreationThrottle, $wgEmailConfirmToEdit; + global $wgAuth, $wgAccountCreationThrottle, $wgEmailConfirmToEdit; // If the user passes an invalid domain, something is fishy if ( !$wgAuth->validDomain( $this->mDomain ) ) { @@ -561,8 +565,9 @@ class LoginForm extends SpecialPage { return Status::newFatal( 'noname' ); } + $cache = ObjectCache::getLocalClusterInstance(); # Make sure the user does not exist already - $lock = $wgMemc->getScopedLock( wfGlobalCacheKey( 'account', md5( $this->mUsername ) ) ); + $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $this->mUsername ) ) ); if ( !$lock ) { return Status::newFatal( 'usernameinprogress' ); } elseif ( $u->idForName( User::READ_LOCKING ) ) { @@ -629,14 +634,14 @@ class LoginForm extends SpecialPage { } else { if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) { $key = wfMemcKey( 'acctcreate', 'ip', $ip ); - $value = $wgMemc->get( $key ); + $value = $cache->get( $key ); if ( !$value ) { - $wgMemc->set( $key, 0, 86400 ); + $cache->set( $key, 0, $cache::TTL_DAY ); } if ( $value >= $wgAccountCreationThrottle ) { return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle ); } - $wgMemc->incr( $key ); + $cache->incr( $key ); } } @@ -779,30 +784,34 @@ class LoginForm extends SpecialPage { // Give general extensions, such as a captcha, a chance to abort logins $abort = self::ABORTED; if ( !Hooks::run( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) { + if ( !in_array( $abort, array_keys( self::$statusCodes ), true ) ) { + throw new Exception( 'Invalid status code returned from AbortLogin hook: ' . $abort ); + } $this->mAbortLoginErrorMsg = $msg; - return $abort; } global $wgBlockDisablesLogin; if ( !$u->checkPassword( $this->mPassword ) ) { if ( $u->checkTemporaryPassword( $this->mPassword ) ) { - // The e-mailed temporary password should not be used for actu- - // al logins; that's a very sloppy habit, and insecure if an - // attacker has a few seconds to click "search" on someone's o- - // pen mail reader. - // - // Allow it to be used only to reset the password a single time - // to a new value, which won't be in the user's e-mail ar- - // chives. - // - // For backwards compatibility, we'll still recognize it at the - // login form to minimize surprises for people who have been - // logging in with a temporary password for some time. - // - // As a side-effect, we can authenticate the user's e-mail ad- - // dress if it's not already done, since the temporary password - // was sent via e-mail. + /** + * The e-mailed temporary password should not be used for actu- + * al logins; that's a very sloppy habit, and insecure if an + * attacker has a few seconds to click "search" on someone's + * open mail reader. + * + * Allow it to be used only to reset the password a single time + * to a new value, which won't be in the user's e-mail ar- + * chives. + * + * For backwards compatibility, we'll still recognize it at the + * login form to minimize surprises for people who have been + * logging in with a temporary password for some time. + * + * As a side-effect, we can authenticate the user's e-mail ad- + * dress if it's not already done, since the temporary password + * was sent via e-mail. + */ if ( !$u->isEmailConfirmed() && !wfReadOnly() ) { $u->confirmEmail(); $u->saveSettings(); @@ -820,7 +829,7 @@ class LoginForm extends SpecialPage { } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) { // If we've enabled it, make it so that a blocked user cannot login $retval = self::USER_BLOCKED; - } elseif ( $u->getPasswordExpired() == 'hard' ) { + } elseif ( $this->checkUserPasswordExpired( $u ) == 'hard' ) { // Force reset now, without logging in $retval = self::RESET_PASS; $this->mAbortLoginErrorMsg = 'resetpass-expired'; @@ -861,7 +870,7 @@ class LoginForm extends SpecialPage { * @return bool|int The integer hit count or True if it is already at the limit */ public static function incLoginThrottle( $username ) { - global $wgPasswordAttemptThrottle, $wgMemc, $wgRequest; + global $wgPasswordAttemptThrottle, $wgRequest; $username = trim( $username ); // sanity $throttleCount = 0; @@ -870,11 +879,12 @@ class LoginForm extends SpecialPage { $count = $wgPasswordAttemptThrottle['count']; $period = $wgPasswordAttemptThrottle['seconds']; - $throttleCount = $wgMemc->get( $throttleKey ); + $cache = ObjectCache::getLocalClusterInstance(); + $throttleCount = $cache->get( $throttleKey ); if ( !$throttleCount ) { - $wgMemc->add( $throttleKey, 1, $period ); // start counter + $cache->add( $throttleKey, 1, $period ); // start counter } elseif ( $throttleCount < $count ) { - $wgMemc->incr( $throttleKey ); + $cache->incr( $throttleKey ); } elseif ( $throttleCount >= $count ) { return true; } @@ -889,11 +899,11 @@ class LoginForm extends SpecialPage { * @return void */ public static function clearLoginThrottle( $username ) { - global $wgMemc, $wgRequest; + global $wgRequest; $username = trim( $username ); // sanity $throttleKey = wfMemcKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); - $wgMemc->delete( $throttleKey ); + ObjectCache::getLocalClusterInstance()->delete( $throttleKey ); } /** @@ -952,9 +962,9 @@ class LoginForm extends SpecialPage { } function processLogin() { - global $wgMemc, $wgLang, $wgSecureLogin, $wgPasswordAttemptThrottle, - $wgInvalidPasswordReset; + global $wgLang, $wgSecureLogin, $wgPasswordAttemptThrottle, $wgInvalidPasswordReset; + $cache = ObjectCache::getLocalClusterInstance(); $authRes = $this->authenticateUserData(); switch ( $authRes ) { case self::SUCCESS: @@ -976,7 +986,7 @@ class LoginForm extends SpecialPage { // Reset the throttle $request = $this->getRequest(); $key = wfMemcKey( 'password-throttle', $request->getIP(), md5( $this->mUsername ) ); - $wgMemc->delete( $key ); + $cache->delete( $key ); if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) { /* Replace the language object to provide user interface in @@ -988,7 +998,7 @@ class LoginForm extends SpecialPage { $this->getContext()->setLanguage( $userLang ); // Reset SessionID on Successful login (bug 40995) $this->renewSessionId(); - if ( $this->getUser()->getPasswordExpired() == 'soft' ) { + if ( $this->checkUserPasswordExpired( $this->getUser() ) == 'soft' ) { $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) ); } elseif ( $wgInvalidPasswordReset && !$user->isValidPassword( $this->mPassword ) @@ -1115,7 +1125,7 @@ class LoginForm extends SpecialPage { function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) { - global $wgNewPasswordExpiry; + global $wgNewPasswordExpiry, $wgMinimalPasswordLength; if ( $u->getEmail() == '' ) { return Status::newFatal( 'noemail', $u->getName() ); @@ -1128,7 +1138,7 @@ class LoginForm extends SpecialPage { $currentUser = $this->getUser(); Hooks::run( 'User::mailPasswordInternal', array( &$currentUser, &$ip, &$u ) ); - $np = $u->randomPassword(); + $np = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength ); $u->setNewpassword( $np, $throttle ); $u->saveSettings(); $userLanguage = $u->getOption( 'language' ); @@ -1379,11 +1389,6 @@ class LoginForm extends SpecialPage { ) ); if ( $this->mType == 'signup' ) { - // XXX hack pending RL or JS parse() support for complex content messages - // https://bugzilla.wikimedia.org/show_bug.cgi?id=25349 - $out->addJsConfigVars( 'wgCreateacctImgcaptchaHelp', - $this->msg( 'createacct-imgcaptcha-help' )->parse() ); - // Additional styles and scripts for signup form $out->addModules( array( 'mediawiki.special.userlogin.signup.js' @@ -1459,7 +1464,9 @@ class LoginForm extends SpecialPage { $template->set( 'emailothers', $wgEnableUserEmail ); $template->set( 'canreset', $wgAuth->allowPasswordChange() ); $template->set( 'resetlink', $resetLink ); - $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ? ( $wgCookieExpiration > 0 ) : ( $wgExtendedLoginCookieExpiration > 0 ) ); + $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ? + ( $wgCookieExpiration > 0 ) : + ( $wgExtendedLoginCookieExpiration > 0 ) ); $template->set( 'usereason', $user->isLoggedIn() ); $template->set( 'remember', $this->mRemember ); $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) ); @@ -1709,4 +1716,25 @@ class LoginForm extends SpecialPage { protected function getGroupName() { return 'login'; } + + /** + * Private function to check password expiration, until AuthManager comes + * along to handle that. + * @param User $user + * @return string|bool + */ + private function checkUserPasswordExpired( User $user ) { + global $wgPasswordExpireGrace; + $dbr = wfGetDB( DB_SLAVE ); + $ts = $dbr->selectField( 'user', 'user_password_expires', array( 'user_id' => $user->getId() ) ); + + $expired = false; + $now = wfTimestamp(); + $expUnix = wfTimestamp( TS_UNIX, $ts ); + if ( $ts !== null && $expUnix < $now ) { + $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft'; + } + return $expired; + } + }