MediaWiki
REL1_23
|
00001 <?php 00029 class LoginForm extends SpecialPage { 00030 const SUCCESS = 0; 00031 const NO_NAME = 1; 00032 const ILLEGAL = 2; 00033 const WRONG_PLUGIN_PASS = 3; 00034 const NOT_EXISTS = 4; 00035 const WRONG_PASS = 5; 00036 const EMPTY_PASS = 6; 00037 const RESET_PASS = 7; 00038 const ABORTED = 8; 00039 const CREATE_BLOCKED = 9; 00040 const THROTTLED = 10; 00041 const USER_BLOCKED = 11; 00042 const NEED_TOKEN = 12; 00043 const WRONG_TOKEN = 13; 00044 00045 public $mAbortLoginErrorMsg = null; 00046 00047 protected $mUsername; 00048 protected $mPassword; 00049 protected $mRetype; 00050 protected $mReturnTo; 00051 protected $mCookieCheck; 00052 protected $mPosted; 00053 protected $mAction; 00054 protected $mCreateaccount; 00055 protected $mCreateaccountMail; 00056 protected $mLoginattempt; 00057 protected $mRemember; 00058 protected $mEmail; 00059 protected $mDomain; 00060 protected $mLanguage; 00061 protected $mSkipCookieCheck; 00062 protected $mReturnToQuery; 00063 protected $mToken; 00064 protected $mStickHTTPS; 00065 protected $mType; 00066 protected $mReason; 00067 protected $mRealName; 00068 00069 private $mTempPasswordUsed; 00070 private $mLoaded = false; 00071 private $mSecureLoginUrl; 00072 00074 private $mOverrideRequest = null; 00075 00077 private $mRequest = null; 00078 00082 public function __construct( $request = null ) { 00083 parent::__construct( 'Userlogin' ); 00084 00085 $this->mOverrideRequest = $request; 00086 } 00087 00091 function load() { 00092 global $wgAuth, $wgHiddenPrefs, $wgEnableEmail; 00093 00094 if ( $this->mLoaded ) { 00095 return; 00096 } 00097 $this->mLoaded = true; 00098 00099 if ( $this->mOverrideRequest === null ) { 00100 $request = $this->getRequest(); 00101 } else { 00102 $request = $this->mOverrideRequest; 00103 } 00104 $this->mRequest = $request; 00105 00106 $this->mType = $request->getText( 'type' ); 00107 $this->mUsername = $request->getText( 'wpName' ); 00108 $this->mPassword = $request->getText( 'wpPassword' ); 00109 $this->mRetype = $request->getText( 'wpRetype' ); 00110 $this->mDomain = $request->getText( 'wpDomain' ); 00111 $this->mReason = $request->getText( 'wpReason' ); 00112 $this->mCookieCheck = $request->getVal( 'wpCookieCheck' ); 00113 $this->mPosted = $request->wasPosted(); 00114 $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' ) 00115 && $wgEnableEmail; 00116 $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail; 00117 $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' ); 00118 $this->mAction = $request->getVal( 'action' ); 00119 $this->mRemember = $request->getCheck( 'wpRemember' ); 00120 $this->mFromHTTP = $request->getBool( 'fromhttp', false ); 00121 $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' ) 00122 || $request->getBool( 'wpForceHttps', false ); 00123 $this->mLanguage = $request->getText( 'uselang' ); 00124 $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' ); 00125 $this->mToken = $this->mType == 'signup' 00126 ? $request->getVal( 'wpCreateaccountToken' ) 00127 : $request->getVal( 'wpLoginToken' ); 00128 $this->mReturnTo = $request->getVal( 'returnto', '' ); 00129 $this->mReturnToQuery = $request->getVal( 'returntoquery', '' ); 00130 00131 if ( $wgEnableEmail ) { 00132 $this->mEmail = $request->getText( 'wpEmail' ); 00133 } else { 00134 $this->mEmail = ''; 00135 } 00136 if ( !in_array( 'realname', $wgHiddenPrefs ) ) { 00137 $this->mRealName = $request->getText( 'wpRealName' ); 00138 } else { 00139 $this->mRealName = ''; 00140 } 00141 00142 if ( !$wgAuth->validDomain( $this->mDomain ) ) { 00143 $this->mDomain = $wgAuth->getDomain(); 00144 } 00145 $wgAuth->setDomain( $this->mDomain ); 00146 00147 # 1. When switching accounts, it sucks to get automatically logged out 00148 # 2. Do not return to PasswordReset after a successful password change 00149 # but goto Wiki start page (Main_Page) instead ( bug 33997 ) 00150 $returnToTitle = Title::newFromText( $this->mReturnTo ); 00151 if ( is_object( $returnToTitle ) 00152 && ( $returnToTitle->isSpecial( 'Userlogout' ) 00153 || $returnToTitle->isSpecial( 'PasswordReset' ) ) 00154 ) { 00155 $this->mReturnTo = ''; 00156 $this->mReturnToQuery = ''; 00157 } 00158 } 00159 00160 function getDescription() { 00161 if ( $this->mType === 'signup' ) { 00162 return $this->msg( 'createaccount' )->text(); 00163 } else { 00164 return $this->msg( 'login' )->text(); 00165 } 00166 } 00167 00168 /* 00169 * @param $subPage string|null 00170 */ 00171 public function execute( $subPage ) { 00172 if ( session_id() == '' ) { 00173 wfSetupSession(); 00174 } 00175 00176 $this->load(); 00177 00178 // Check for [[Special:Userlogin/signup]]. This affects form display and 00179 // page title. 00180 if ( $subPage == 'signup' ) { 00181 $this->mType = 'signup'; 00182 } 00183 $this->setHeaders(); 00184 00185 // If logging in and not on HTTPS, either redirect to it or offer a link. 00186 global $wgSecureLogin; 00187 if ( $this->mRequest->getProtocol() !== 'https' ) { 00188 $title = $this->getFullTitle(); 00189 $query = array( 00190 'returnto' => $this->mReturnTo !== '' ? $this->mReturnTo : null, 00191 'returntoquery' => $this->mReturnToQuery !== '' ? 00192 $this->mReturnToQuery : null, 00193 'title' => null, 00194 ) + $this->mRequest->getQueryValues(); 00195 $url = $title->getFullURL( $query, false, PROTO_HTTPS ); 00196 if ( $wgSecureLogin && wfCanIPUseHTTPS( $this->getRequest()->getIP() ) ) { 00197 $url = wfAppendQuery( $url, 'fromhttp=1' ); 00198 $this->getOutput()->redirect( $url ); 00199 // Since we only do this redir to change proto, always vary 00200 $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' ); 00201 00202 return; 00203 } else { 00204 // A wiki without HTTPS login support should set $wgServer to 00205 // http://somehost, in which case the secure URL generated 00206 // above won't actually start with https:// 00207 if ( substr( $url, 0, 8 ) === 'https://' ) { 00208 $this->mSecureLoginUrl = $url; 00209 } 00210 } 00211 } 00212 00213 if ( !is_null( $this->mCookieCheck ) ) { 00214 $this->onCookieRedirectCheck( $this->mCookieCheck ); 00215 00216 return; 00217 } elseif ( $this->mPosted ) { 00218 if ( $this->mCreateaccount ) { 00219 $this->addNewAccount(); 00220 00221 return; 00222 } elseif ( $this->mCreateaccountMail ) { 00223 $this->addNewAccountMailPassword(); 00224 00225 return; 00226 } elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) { 00227 $this->processLogin(); 00228 00229 return; 00230 } 00231 } 00232 $this->mainLoginForm( '' ); 00233 } 00234 00238 function addNewAccountMailPassword() { 00239 if ( $this->mEmail == '' ) { 00240 $this->mainLoginForm( $this->msg( 'noemailcreate' )->escaped() ); 00241 00242 return; 00243 } 00244 00245 $status = $this->addNewAccountInternal(); 00246 if ( !$status->isGood() ) { 00247 $error = $status->getMessage(); 00248 $this->mainLoginForm( $error->toString() ); 00249 00250 return; 00251 } 00252 00253 $u = $status->getValue(); 00254 00255 // Wipe the initial password and mail a temporary one 00256 $u->setPassword( null ); 00257 $u->saveSettings(); 00258 $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' ); 00259 00260 wfRunHooks( 'AddNewAccount', array( $u, true ) ); 00261 $u->addNewUserLogEntry( 'byemail', $this->mReason ); 00262 00263 $out = $this->getOutput(); 00264 $out->setPageTitle( $this->msg( 'accmailtitle' ) ); 00265 00266 if ( !$result->isGood() ) { 00267 $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() ); 00268 } else { 00269 $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() ); 00270 $this->executeReturnTo( 'success' ); 00271 } 00272 } 00273 00278 function addNewAccount() { 00279 global $wgContLang, $wgUser, $wgEmailAuthentication, $wgLoginLanguageSelector; 00280 00281 # Create the account and abort if there's a problem doing so 00282 $status = $this->addNewAccountInternal(); 00283 if ( !$status->isGood() ) { 00284 $error = $status->getMessage(); 00285 $this->mainLoginForm( $error->toString() ); 00286 00287 return false; 00288 } 00289 00290 $u = $status->getValue(); 00291 00292 # Only save preferences if the user is not creating an account for someone else. 00293 if ( $this->getUser()->isAnon() ) { 00294 # If we showed up language selection links, and one was in use, be 00295 # smart (and sensible) and save that language as the user's preference 00296 if ( $wgLoginLanguageSelector && $this->mLanguage ) { 00297 $u->setOption( 'language', $this->mLanguage ); 00298 } else { 00299 00300 # Otherwise the user's language preference defaults to $wgContLang, 00301 # but it may be better to set it to their preferred $wgContLang variant, 00302 # based on browser preferences or URL parameters. 00303 $u->setOption( 'language', $wgContLang->getPreferredVariant() ); 00304 } 00305 if ( $wgContLang->hasVariants() ) { 00306 $u->setOption( 'variant', $wgContLang->getPreferredVariant() ); 00307 } 00308 } 00309 00310 $out = $this->getOutput(); 00311 00312 # Send out an email authentication message if needed 00313 if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) { 00314 $status = $u->sendConfirmationMail(); 00315 if ( $status->isGood() ) { 00316 $out->addWikiMsg( 'confirmemail_oncreate' ); 00317 } else { 00318 $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) ); 00319 } 00320 } 00321 00322 # Save settings (including confirmation token) 00323 $u->saveSettings(); 00324 00325 # If not logged in, assume the new account as the current one and set 00326 # session cookies then show a "welcome" message or a "need cookies" 00327 # message as needed 00328 if ( $this->getUser()->isAnon() ) { 00329 $u->setCookies(); 00330 $wgUser = $u; 00331 // This should set it for OutputPage and the Skin 00332 // which is needed or the personal links will be 00333 // wrong. 00334 $this->getContext()->setUser( $u ); 00335 wfRunHooks( 'AddNewAccount', array( $u, false ) ); 00336 $u->addNewUserLogEntry( 'create' ); 00337 if ( $this->hasSessionCookie() ) { 00338 $this->successfulCreation(); 00339 } else { 00340 $this->cookieRedirectCheck( 'new' ); 00341 } 00342 } else { 00343 # Confirm that the account was created 00344 $out->setPageTitle( $this->msg( 'accountcreated' ) ); 00345 $out->addWikiMsg( 'accountcreatedtext', $u->getName() ); 00346 $out->addReturnTo( $this->getPageTitle() ); 00347 wfRunHooks( 'AddNewAccount', array( $u, false ) ); 00348 $u->addNewUserLogEntry( 'create2', $this->mReason ); 00349 } 00350 00351 return true; 00352 } 00353 00360 public function addNewAccountInternal() { 00361 global $wgAuth, $wgMemc, $wgAccountCreationThrottle, 00362 $wgMinimalPasswordLength, $wgEmailConfirmToEdit; 00363 00364 // If the user passes an invalid domain, something is fishy 00365 if ( !$wgAuth->validDomain( $this->mDomain ) ) { 00366 return Status::newFatal( 'wrongpassword' ); 00367 } 00368 00369 // If we are not allowing users to login locally, we should be checking 00370 // to see if the user is actually able to authenticate to the authenti- 00371 // cation server before they create an account (otherwise, they can 00372 // create a local account and login as any domain user). We only need 00373 // to check this for domains that aren't local. 00374 if ( 'local' != $this->mDomain && $this->mDomain != '' ) { 00375 if ( 00376 !$wgAuth->canCreateAccounts() && 00377 ( 00378 !$wgAuth->userExists( $this->mUsername ) || 00379 !$wgAuth->authenticate( $this->mUsername, $this->mPassword ) 00380 ) 00381 ) { 00382 return Status::newFatal( 'wrongpassword' ); 00383 } 00384 } 00385 00386 if ( wfReadOnly() ) { 00387 throw new ReadOnlyError; 00388 } 00389 00390 # Request forgery checks. 00391 if ( !self::getCreateaccountToken() ) { 00392 self::setCreateaccountToken(); 00393 00394 return Status::newFatal( 'nocookiesfornew' ); 00395 } 00396 00397 # The user didn't pass a createaccount token 00398 if ( !$this->mToken ) { 00399 return Status::newFatal( 'sessionfailure' ); 00400 } 00401 00402 # Validate the createaccount token 00403 if ( $this->mToken !== self::getCreateaccountToken() ) { 00404 return Status::newFatal( 'sessionfailure' ); 00405 } 00406 00407 # Check permissions 00408 $currentUser = $this->getUser(); 00409 $creationBlock = $currentUser->isBlockedFromCreateAccount(); 00410 if ( !$currentUser->isAllowed( 'createaccount' ) ) { 00411 throw new PermissionsError( 'createaccount' ); 00412 } elseif ( $creationBlock instanceof Block ) { 00413 // Throws an ErrorPageError. 00414 $this->userBlockedMessage( $creationBlock ); 00415 00416 // This should never be reached. 00417 return false; 00418 } 00419 00420 # Include checks that will include GlobalBlocking (Bug 38333) 00421 $permErrors = $this->getPageTitle()->getUserPermissionsErrors( 00422 'createaccount', 00423 $currentUser, 00424 true 00425 ); 00426 00427 if ( count( $permErrors ) ) { 00428 throw new PermissionsError( 'createaccount', $permErrors ); 00429 } 00430 00431 $ip = $this->getRequest()->getIP(); 00432 if ( $currentUser->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) { 00433 return Status::newFatal( 'sorbs_create_account_reason' ); 00434 } 00435 00436 // Normalize the name so that silly things don't cause "invalid username" 00437 // errors. User::newFromName does some rather strict checking, rejecting 00438 // e.g. leading/trailing/multiple spaces. 00439 $title = Title::makeTitleSafe( NS_USER, $this->mUsername ); 00440 if ( !is_object( $title ) ) { 00441 return Status::newFatal( 'noname' ); 00442 } 00443 00444 # Now create a dummy user ($u) and check if it is valid 00445 $u = User::newFromName( $title->getText(), 'creatable' ); 00446 if ( !is_object( $u ) ) { 00447 return Status::newFatal( 'noname' ); 00448 } elseif ( 0 != $u->idForName() ) { 00449 return Status::newFatal( 'userexists' ); 00450 } 00451 00452 if ( $this->mCreateaccountMail ) { 00453 # do not force a password for account creation by email 00454 # set invalid password, it will be replaced later by a random generated password 00455 $this->mPassword = null; 00456 } else { 00457 if ( $this->mPassword !== $this->mRetype ) { 00458 return Status::newFatal( 'badretype' ); 00459 } 00460 00461 # check for minimal password length 00462 $valid = $u->getPasswordValidity( $this->mPassword ); 00463 if ( $valid !== true ) { 00464 if ( !is_array( $valid ) ) { 00465 $valid = array( $valid, $wgMinimalPasswordLength ); 00466 } 00467 00468 return call_user_func_array( 'Status::newFatal', $valid ); 00469 } 00470 } 00471 00472 # if you need a confirmed email address to edit, then obviously you 00473 # need an email address. 00474 if ( $wgEmailConfirmToEdit && strval( $this->mEmail ) === '' ) { 00475 return Status::newFatal( 'noemailtitle' ); 00476 } 00477 00478 if ( strval( $this->mEmail ) !== '' && !Sanitizer::validateEmail( $this->mEmail ) ) { 00479 return Status::newFatal( 'invalidemailaddress' ); 00480 } 00481 00482 # Set some additional data so the AbortNewAccount hook can be used for 00483 # more than just username validation 00484 $u->setEmail( $this->mEmail ); 00485 $u->setRealName( $this->mRealName ); 00486 00487 $abortError = ''; 00488 $abortStatus = null; 00489 if ( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError, &$abortStatus ) ) ) { 00490 // Hook point to add extra creation throttles and blocks 00491 wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" ); 00492 if ( $abortStatus === null ) { 00493 // Report back the old string as a raw message status. 00494 // This will report the error back as 'createaccount-hook-aborted' 00495 // with the given string as the message. 00496 // To return a different error code, return a Status object. 00497 $abortError = new Message( 'createaccount-hook-aborted', array( $abortError ) ); 00498 $abortError->text(); 00499 00500 return Status::newFatal( $abortError ); 00501 } else { 00502 // For MediaWiki 1.23+ and updated hooks, return the Status object 00503 // returned from the hook. 00504 return $abortStatus; 00505 } 00506 } 00507 00508 // Hook point to check for exempt from account creation throttle 00509 if ( !wfRunHooks( 'ExemptFromAccountCreationThrottle', array( $ip ) ) ) { 00510 wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " . 00511 "allowed account creation w/o throttle\n" ); 00512 } else { 00513 if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) { 00514 $key = wfMemcKey( 'acctcreate', 'ip', $ip ); 00515 $value = $wgMemc->get( $key ); 00516 if ( !$value ) { 00517 $wgMemc->set( $key, 0, 86400 ); 00518 } 00519 if ( $value >= $wgAccountCreationThrottle ) { 00520 return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle ); 00521 } 00522 $wgMemc->incr( $key ); 00523 } 00524 } 00525 00526 if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) { 00527 return Status::newFatal( 'externaldberror' ); 00528 } 00529 00530 self::clearCreateaccountToken(); 00531 00532 return $this->initUser( $u, false ); 00533 } 00534 00544 function initUser( $u, $autocreate ) { 00545 global $wgAuth; 00546 00547 $status = $u->addToDatabase(); 00548 if ( !$status->isOK() ) { 00549 return $status; 00550 } 00551 00552 if ( $wgAuth->allowPasswordChange() ) { 00553 $u->setPassword( $this->mPassword ); 00554 } 00555 00556 $u->setEmail( $this->mEmail ); 00557 $u->setRealName( $this->mRealName ); 00558 $u->setToken(); 00559 00560 $wgAuth->initUser( $u, $autocreate ); 00561 00562 $u->saveSettings(); 00563 00564 // Update user count 00565 DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) ); 00566 00567 // Watch user's userpage and talk page 00568 $u->addWatch( $u->getUserPage(), WatchedItem::IGNORE_USER_RIGHTS ); 00569 00570 return Status::newGood( $u ); 00571 } 00572 00581 public function authenticateUserData() { 00582 global $wgUser, $wgAuth; 00583 00584 $this->load(); 00585 00586 if ( $this->mUsername == '' ) { 00587 return self::NO_NAME; 00588 } 00589 00590 // We require a login token to prevent login CSRF 00591 // Handle part of this before incrementing the throttle so 00592 // token-less login attempts don't count towards the throttle 00593 // but wrong-token attempts do. 00594 00595 // If the user doesn't have a login token yet, set one. 00596 if ( !self::getLoginToken() ) { 00597 self::setLoginToken(); 00598 00599 return self::NEED_TOKEN; 00600 } 00601 // If the user didn't pass a login token, tell them we need one 00602 if ( !$this->mToken ) { 00603 return self::NEED_TOKEN; 00604 } 00605 00606 $throttleCount = self::incLoginThrottle( $this->mUsername ); 00607 if ( $throttleCount === true ) { 00608 return self::THROTTLED; 00609 } 00610 00611 // Validate the login token 00612 if ( $this->mToken !== self::getLoginToken() ) { 00613 return self::WRONG_TOKEN; 00614 } 00615 00616 // Load the current user now, and check to see if we're logging in as 00617 // the same name. This is necessary because loading the current user 00618 // (say by calling getName()) calls the UserLoadFromSession hook, which 00619 // potentially creates the user in the database. Until we load $wgUser, 00620 // checking for user existence using User::newFromName($name)->getId() below 00621 // will effectively be using stale data. 00622 if ( $this->getUser()->getName() === $this->mUsername ) { 00623 wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" ); 00624 00625 return self::SUCCESS; 00626 } 00627 00628 $u = User::newFromName( $this->mUsername ); 00629 if ( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) { 00630 return self::ILLEGAL; 00631 } 00632 00633 $isAutoCreated = false; 00634 if ( $u->getID() == 0 ) { 00635 $status = $this->attemptAutoCreate( $u ); 00636 if ( $status !== self::SUCCESS ) { 00637 return $status; 00638 } else { 00639 $isAutoCreated = true; 00640 } 00641 } else { 00642 $u->load(); 00643 } 00644 00645 // Give general extensions, such as a captcha, a chance to abort logins 00646 $abort = self::ABORTED; 00647 $msg = null; 00648 if ( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) { 00649 $this->mAbortLoginErrorMsg = $msg; 00650 00651 return $abort; 00652 } 00653 00654 global $wgBlockDisablesLogin; 00655 if ( !$u->checkPassword( $this->mPassword ) ) { 00656 if ( $u->checkTemporaryPassword( $this->mPassword ) ) { 00657 // The e-mailed temporary password should not be used for actu- 00658 // al logins; that's a very sloppy habit, and insecure if an 00659 // attacker has a few seconds to click "search" on someone's o- 00660 // pen mail reader. 00661 // 00662 // Allow it to be used only to reset the password a single time 00663 // to a new value, which won't be in the user's e-mail ar- 00664 // chives. 00665 // 00666 // For backwards compatibility, we'll still recognize it at the 00667 // login form to minimize surprises for people who have been 00668 // logging in with a temporary password for some time. 00669 // 00670 // As a side-effect, we can authenticate the user's e-mail ad- 00671 // dress if it's not already done, since the temporary password 00672 // was sent via e-mail. 00673 if ( !$u->isEmailConfirmed() ) { 00674 $u->confirmEmail(); 00675 $u->saveSettings(); 00676 } 00677 00678 // At this point we just return an appropriate code/ indicating 00679 // that the UI should show a password reset form; bot inter- 00680 // faces etc will probably just fail cleanly here. 00681 $this->mAbortLoginErrorMsg = 'resetpass-temp-emailed'; 00682 $this->mTempPasswordUsed = true; 00683 $retval = self::RESET_PASS; 00684 } else { 00685 $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS; 00686 } 00687 } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) { 00688 // If we've enabled it, make it so that a blocked user cannot login 00689 $retval = self::USER_BLOCKED; 00690 } elseif ( $u->getPasswordExpired() == 'hard' ) { 00691 // Force reset now, without logging in 00692 $retval = self::RESET_PASS; 00693 $this->mAbortLoginErrorMsg = 'resetpass-expired'; 00694 } else { 00695 $wgAuth->updateUser( $u ); 00696 $wgUser = $u; 00697 // This should set it for OutputPage and the Skin 00698 // which is needed or the personal links will be 00699 // wrong. 00700 $this->getContext()->setUser( $u ); 00701 00702 // Please reset throttle for successful logins, thanks! 00703 if ( $throttleCount ) { 00704 self::clearLoginThrottle( $this->mUsername ); 00705 } 00706 00707 if ( $isAutoCreated ) { 00708 // Must be run after $wgUser is set, for correct new user log 00709 wfRunHooks( 'AuthPluginAutoCreate', array( $u ) ); 00710 } 00711 00712 $retval = self::SUCCESS; 00713 } 00714 wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) ); 00715 00716 return $retval; 00717 } 00718 00725 public static function incLoginThrottle( $username ) { 00726 global $wgPasswordAttemptThrottle, $wgMemc, $wgRequest; 00727 $username = trim( $username ); // sanity 00728 00729 $throttleCount = 0; 00730 if ( is_array( $wgPasswordAttemptThrottle ) ) { 00731 $throttleKey = wfMemcKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); 00732 $count = $wgPasswordAttemptThrottle['count']; 00733 $period = $wgPasswordAttemptThrottle['seconds']; 00734 00735 $throttleCount = $wgMemc->get( $throttleKey ); 00736 if ( !$throttleCount ) { 00737 $wgMemc->add( $throttleKey, 1, $period ); // start counter 00738 } elseif ( $throttleCount < $count ) { 00739 $wgMemc->incr( $throttleKey ); 00740 } elseif ( $throttleCount >= $count ) { 00741 return true; 00742 } 00743 } 00744 00745 return $throttleCount; 00746 } 00747 00753 public static function clearLoginThrottle( $username ) { 00754 global $wgMemc, $wgRequest; 00755 $username = trim( $username ); // sanity 00756 00757 $throttleKey = wfMemcKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); 00758 $wgMemc->delete( $throttleKey ); 00759 } 00760 00769 function attemptAutoCreate( $user ) { 00770 global $wgAuth; 00771 00772 if ( $this->getUser()->isBlockedFromCreateAccount() ) { 00773 wfDebug( __METHOD__ . ": user is blocked from account creation\n" ); 00774 00775 return self::CREATE_BLOCKED; 00776 } 00777 00778 if ( !$wgAuth->autoCreate() ) { 00779 return self::NOT_EXISTS; 00780 } 00781 00782 if ( !$wgAuth->userExists( $user->getName() ) ) { 00783 wfDebug( __METHOD__ . ": user does not exist\n" ); 00784 00785 return self::NOT_EXISTS; 00786 } 00787 00788 if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) { 00789 wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" ); 00790 00791 return self::WRONG_PLUGIN_PASS; 00792 } 00793 00794 $abortError = ''; 00795 if ( !wfRunHooks( 'AbortAutoAccount', array( $user, &$abortError ) ) ) { 00796 // Hook point to add extra creation throttles and blocks 00797 wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" ); 00798 $this->mAbortLoginErrorMsg = $abortError; 00799 00800 return self::ABORTED; 00801 } 00802 00803 wfDebug( __METHOD__ . ": creating account\n" ); 00804 $status = $this->initUser( $user, true ); 00805 00806 if ( !$status->isOK() ) { 00807 $errors = $status->getErrorsByType( 'error' ); 00808 $this->mAbortLoginErrorMsg = $errors[0]['message']; 00809 00810 return self::ABORTED; 00811 } 00812 00813 return self::SUCCESS; 00814 } 00815 00816 function processLogin() { 00817 global $wgMemc, $wgLang, $wgSecureLogin, $wgPasswordAttemptThrottle, 00818 $wgInvalidPasswordReset; 00819 00820 switch ( $this->authenticateUserData() ) { 00821 case self::SUCCESS: 00822 # We've verified now, update the real record 00823 $user = $this->getUser(); 00824 $user->invalidateCache(); 00825 00826 if ( $user->requiresHTTPS() ) { 00827 $this->mStickHTTPS = true; 00828 } 00829 00830 if ( $wgSecureLogin && !$this->mStickHTTPS ) { 00831 $user->setCookies( $this->mRequest, false, $this->mRemember ); 00832 } else { 00833 $user->setCookies( $this->mRequest, null, $this->mRemember ); 00834 } 00835 self::clearLoginToken(); 00836 00837 // Reset the throttle 00838 $request = $this->getRequest(); 00839 $key = wfMemcKey( 'password-throttle', $request->getIP(), md5( $this->mUsername ) ); 00840 $wgMemc->delete( $key ); 00841 00842 if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) { 00843 /* Replace the language object to provide user interface in 00844 * correct language immediately on this first page load. 00845 */ 00846 $code = $request->getVal( 'uselang', $user->getOption( 'language' ) ); 00847 $userLang = Language::factory( $code ); 00848 $wgLang = $userLang; 00849 $this->getContext()->setLanguage( $userLang ); 00850 // Reset SessionID on Successful login (bug 40995) 00851 $this->renewSessionId(); 00852 if ( $this->getUser()->getPasswordExpired() == 'soft' ) { 00853 $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) ); 00854 } elseif ( $wgInvalidPasswordReset 00855 && !$user->isValidPassword( $this->mPassword ) 00856 ) { 00857 $status = $user->checkPasswordValidity( $this->mPassword ); 00858 $this->resetLoginForm( 00859 $status->getMessage( 'resetpass-validity-soft' ) 00860 ); 00861 } else { 00862 $this->successfulLogin(); 00863 } 00864 } else { 00865 $this->cookieRedirectCheck( 'login' ); 00866 } 00867 break; 00868 00869 case self::NEED_TOKEN: 00870 $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin'; 00871 $this->mainLoginForm( $this->msg( $error )->parse() ); 00872 break; 00873 case self::WRONG_TOKEN: 00874 $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure'; 00875 $this->mainLoginForm( $this->msg( $error )->text() ); 00876 break; 00877 case self::NO_NAME: 00878 case self::ILLEGAL: 00879 $error = $this->mAbortLoginErrorMsg ?: 'noname'; 00880 $this->mainLoginForm( $this->msg( $error )->text() ); 00881 break; 00882 case self::WRONG_PLUGIN_PASS: 00883 $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword'; 00884 $this->mainLoginForm( $this->msg( $error )->text() ); 00885 break; 00886 case self::NOT_EXISTS: 00887 if ( $this->getUser()->isAllowed( 'createaccount' ) ) { 00888 $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser'; 00889 $this->mainLoginForm( $this->msg( $error, 00890 wfEscapeWikiText( $this->mUsername ) )->parse() ); 00891 } else { 00892 $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort'; 00893 $this->mainLoginForm( $this->msg( $error, 00894 wfEscapeWikiText( $this->mUsername ) )->text() ); 00895 } 00896 break; 00897 case self::WRONG_PASS: 00898 $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword'; 00899 $this->mainLoginForm( $this->msg( $error )->text() ); 00900 break; 00901 case self::EMPTY_PASS: 00902 $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty'; 00903 $this->mainLoginForm( $this->msg( $error )->text() ); 00904 break; 00905 case self::RESET_PASS: 00906 $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce'; 00907 $this->resetLoginForm( $this->msg( $error ) ); 00908 break; 00909 case self::CREATE_BLOCKED: 00910 $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() ); 00911 break; 00912 case self::THROTTLED: 00913 $error = $this->mAbortLoginErrorMsg ?: 'login-throttled'; 00914 $this->mainLoginForm( $this->msg( $error ) 00915 ->params( $this->getLanguage()->formatDuration( $wgPasswordAttemptThrottle['seconds'] ) ) 00916 ->text() 00917 ); 00918 break; 00919 case self::USER_BLOCKED: 00920 $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked'; 00921 $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() ); 00922 break; 00923 case self::ABORTED: 00924 $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic'; 00925 $this->mainLoginForm( $this->msg( $error )->text() ); 00926 break; 00927 default: 00928 throw new MWException( 'Unhandled case value' ); 00929 } 00930 } 00931 00936 protected function resetLoginForm( Message $msg ) { 00937 // Allow hooks to explain this password reset in more detail 00938 wfRunHooks( 'LoginPasswordResetMessage', array( &$msg, $this->mUsername ) ); 00939 $reset = new SpecialChangePassword(); 00940 $derivative = new DerivativeContext( $this->getContext() ); 00941 $derivative->setTitle( $reset->getPageTitle() ); 00942 $reset->setContext( $derivative ); 00943 if ( !$this->mTempPasswordUsed ) { 00944 $reset->setOldPasswordMessage( 'oldpassword' ); 00945 } 00946 $reset->setChangeMessage( $msg ); 00947 $reset->execute( null ); 00948 } 00949 00957 function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', 00958 $emailText = 'passwordremindertext' 00959 ) { 00960 global $wgNewPasswordExpiry; 00961 00962 if ( $u->getEmail() == '' ) { 00963 return Status::newFatal( 'noemail', $u->getName() ); 00964 } 00965 $ip = $this->getRequest()->getIP(); 00966 if ( !$ip ) { 00967 return Status::newFatal( 'badipaddress' ); 00968 } 00969 00970 $currentUser = $this->getUser(); 00971 wfRunHooks( 'User::mailPasswordInternal', array( &$currentUser, &$ip, &$u ) ); 00972 00973 $np = $u->randomPassword(); 00974 $u->setNewpassword( $np, $throttle ); 00975 $u->saveSettings(); 00976 $userLanguage = $u->getOption( 'language' ); 00977 00978 $mainPage = Title::newMainPage(); 00979 $mainPageUrl = $mainPage->getCanonicalURL(); 00980 00981 $m = $this->msg( $emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>', 00982 round( $wgNewPasswordExpiry / 86400 ) )->inLanguage( $userLanguage )->text(); 00983 $result = $u->sendMail( $this->msg( $emailTitle )->inLanguage( $userLanguage )->text(), $m ); 00984 00985 return $result; 00986 } 00987 00998 function successfulLogin() { 00999 # Run any hooks; display injected HTML if any, else redirect 01000 $currentUser = $this->getUser(); 01001 $injected_html = ''; 01002 wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) ); 01003 01004 if ( $injected_html !== '' ) { 01005 $this->displaySuccessfulAction( $this->msg( 'loginsuccesstitle' ), 01006 'loginsuccess', $injected_html ); 01007 } else { 01008 $this->executeReturnTo( 'successredirect' ); 01009 } 01010 } 01011 01018 function successfulCreation() { 01019 # Run any hooks; display injected HTML 01020 $currentUser = $this->getUser(); 01021 $injected_html = ''; 01022 $welcome_creation_msg = 'welcomecreation-msg'; 01023 01024 wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) ); 01025 01031 wfRunHooks( 'BeforeWelcomeCreation', array( &$welcome_creation_msg, &$injected_html ) ); 01032 01033 $this->displaySuccessfulAction( $this->msg( 'welcomeuser', $this->getUser()->getName() ), 01034 $welcome_creation_msg, $injected_html ); 01035 } 01036 01044 private function displaySuccessfulAction( $title, $msgname, $injected_html ) { 01045 $out = $this->getOutput(); 01046 $out->setPageTitle( $title ); 01047 if ( $msgname ) { 01048 $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) ); 01049 } 01050 01051 $out->addHTML( $injected_html ); 01052 01053 $this->executeReturnTo( 'success' ); 01054 } 01055 01064 function userBlockedMessage( Block $block ) { 01065 # Let's be nice about this, it's likely that this feature will be used 01066 # for blocking large numbers of innocent people, e.g. range blocks on 01067 # schools. Don't blame it on the user. There's a small chance that it 01068 # really is the user's fault, i.e. the username is blocked and they 01069 # haven't bothered to log out before trying to create an account to 01070 # evade it, but we'll leave that to their guilty conscience to figure 01071 # out. 01072 $errorParams = array( 01073 $block->getTarget(), 01074 $block->mReason ? $block->mReason : $this->msg( 'blockednoreason' )->text(), 01075 $block->getByName() 01076 ); 01077 01078 if ( $block->getType() === Block::TYPE_RANGE ) { 01079 $errorMessage = 'cantcreateaccount-range-text'; 01080 $errorParams[] = $this->getRequest()->getIP(); 01081 } else { 01082 $errorMessage = 'cantcreateaccount-text'; 01083 } 01084 01085 throw new ErrorPageError( 01086 'cantcreateaccounttitle', 01087 $errorMessage, 01088 $errorParams 01089 ); 01090 } 01091 01106 public function showReturnToPage( 01107 $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false 01108 ) { 01109 $this->mReturnTo = $returnTo; 01110 $this->mReturnToQuery = $returnToQuery; 01111 $this->mStickHTTPS = $stickHTTPs; 01112 $this->executeReturnTo( $type ); 01113 } 01114 01123 private function executeReturnTo( $type ) { 01124 global $wgRedirectOnLogin, $wgSecureLogin; 01125 01126 if ( $type != 'error' && $wgRedirectOnLogin !== null ) { 01127 $returnTo = $wgRedirectOnLogin; 01128 $returnToQuery = array(); 01129 } else { 01130 $returnTo = $this->mReturnTo; 01131 $returnToQuery = wfCgiToArray( $this->mReturnToQuery ); 01132 } 01133 01134 $returnToTitle = Title::newFromText( $returnTo ); 01135 if ( !$returnToTitle ) { 01136 $returnToTitle = Title::newMainPage(); 01137 } 01138 01139 if ( $wgSecureLogin && !$this->mStickHTTPS ) { 01140 $options = array( 'http' ); 01141 $proto = PROTO_HTTP; 01142 } elseif ( $wgSecureLogin ) { 01143 $options = array( 'https' ); 01144 $proto = PROTO_HTTPS; 01145 } else { 01146 $options = array(); 01147 $proto = PROTO_RELATIVE; 01148 } 01149 01150 if ( $type == 'successredirect' ) { 01151 $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto ); 01152 $this->getOutput()->redirect( $redirectUrl ); 01153 } else { 01154 $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options ); 01155 } 01156 } 01157 01161 function mainLoginForm( $msg, $msgtype = 'error' ) { 01162 global $wgEnableEmail, $wgEnableUserEmail; 01163 global $wgHiddenPrefs, $wgLoginLanguageSelector; 01164 global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration; 01165 global $wgSecureLogin, $wgPasswordResetRoutes; 01166 01167 $titleObj = $this->getPageTitle(); 01168 $user = $this->getUser(); 01169 $out = $this->getOutput(); 01170 01171 if ( $this->mType == 'signup' ) { 01172 // Block signup here if in readonly. Keeps user from 01173 // going through the process (filling out data, etc) 01174 // and being informed later. 01175 $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $user, true ); 01176 if ( count( $permErrors ) ) { 01177 throw new PermissionsError( 'createaccount', $permErrors ); 01178 } elseif ( $user->isBlockedFromCreateAccount() ) { 01179 $this->userBlockedMessage( $user->isBlockedFromCreateAccount() ); 01180 01181 return; 01182 } elseif ( wfReadOnly() ) { 01183 throw new ReadOnlyError; 01184 } 01185 } 01186 01187 // Pre-fill username (if not creating an account, bug 44775). 01188 if ( $this->mUsername == '' && $this->mType != 'signup' ) { 01189 if ( $user->isLoggedIn() ) { 01190 $this->mUsername = $user->getName(); 01191 } else { 01192 $this->mUsername = $this->getRequest()->getCookie( 'UserName' ); 01193 } 01194 } 01195 01196 // Generic styles and scripts for both login and signup form 01197 $out->addModuleStyles( array( 01198 'mediawiki.ui', 01199 'mediawiki.ui.button', 01200 'mediawiki.special.userlogin.common.styles' 01201 ) ); 01202 $out->addModules( array( 01203 'mediawiki.special.userlogin.common.js' 01204 ) ); 01205 01206 if ( $this->mType == 'signup' ) { 01207 // XXX hack pending RL or JS parse() support for complex content messages 01208 // https://bugzilla.wikimedia.org/show_bug.cgi?id=25349 01209 $out->addJsConfigVars( 'wgCreateacctImgcaptchaHelp', 01210 $this->msg( 'createacct-imgcaptcha-help' )->parse() ); 01211 01212 // Additional styles and scripts for signup form 01213 $out->addModules( array( 01214 'mediawiki.special.userlogin.signup.js' 01215 ) ); 01216 $out->addModuleStyles( array( 01217 'mediawiki.special.userlogin.signup.styles' 01218 ) ); 01219 01220 $template = new UsercreateTemplate(); 01221 01222 // Must match number of benefits defined in messages 01223 $template->set( 'benefitCount', 3 ); 01224 01225 $q = 'action=submitlogin&type=signup'; 01226 $linkq = 'type=login'; 01227 } else { 01228 // Additional styles for login form 01229 $out->addModuleStyles( array( 01230 'mediawiki.special.userlogin.login.styles' 01231 ) ); 01232 01233 $template = new UserloginTemplate(); 01234 01235 $q = 'action=submitlogin&type=login'; 01236 $linkq = 'type=signup'; 01237 } 01238 01239 if ( $this->mReturnTo !== '' ) { 01240 $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo ); 01241 if ( $this->mReturnToQuery !== '' ) { 01242 $returnto .= '&returntoquery=' . 01243 wfUrlencode( $this->mReturnToQuery ); 01244 } 01245 $q .= $returnto; 01246 $linkq .= $returnto; 01247 } 01248 01249 # Don't show a "create account" link if the user can't. 01250 if ( $this->showCreateOrLoginLink( $user ) ) { 01251 # Pass any language selection on to the mode switch link 01252 if ( $wgLoginLanguageSelector && $this->mLanguage ) { 01253 $linkq .= '&uselang=' . $this->mLanguage; 01254 } 01255 // Supply URL, login template creates the button. 01256 $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) ); 01257 } else { 01258 $template->set( 'link', '' ); 01259 } 01260 01261 $resetLink = $this->mType == 'signup' 01262 ? null 01263 : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) ); 01264 01265 $template->set( 'header', '' ); 01266 $template->set( 'skin', $this->getSkin() ); 01267 $template->set( 'name', $this->mUsername ); 01268 $template->set( 'password', $this->mPassword ); 01269 $template->set( 'retype', $this->mRetype ); 01270 $template->set( 'createemailset', $this->mCreateaccountMail ); 01271 $template->set( 'email', $this->mEmail ); 01272 $template->set( 'realname', $this->mRealName ); 01273 $template->set( 'domain', $this->mDomain ); 01274 $template->set( 'reason', $this->mReason ); 01275 01276 $template->set( 'action', $titleObj->getLocalURL( $q ) ); 01277 $template->set( 'message', $msg ); 01278 $template->set( 'messagetype', $msgtype ); 01279 $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() ); 01280 $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) ); 01281 $template->set( 'useemail', $wgEnableEmail ); 01282 $template->set( 'emailrequired', $wgEmailConfirmToEdit ); 01283 $template->set( 'emailothers', $wgEnableUserEmail ); 01284 $template->set( 'canreset', $wgAuth->allowPasswordChange() ); 01285 $template->set( 'resetlink', $resetLink ); 01286 $template->set( 'canremember', ( $wgCookieExpiration > 0 ) ); 01287 $template->set( 'usereason', $user->isLoggedIn() ); 01288 $template->set( 'remember', $this->mRemember ); 01289 $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) ); 01290 $template->set( 'stickhttps', (int)$this->mStickHTTPS ); 01291 $template->set( 'loggedin', $user->isLoggedIn() ); 01292 $template->set( 'loggedinuser', $user->getName() ); 01293 01294 if ( $this->mType == 'signup' ) { 01295 if ( !self::getCreateaccountToken() ) { 01296 self::setCreateaccountToken(); 01297 } 01298 $template->set( 'token', self::getCreateaccountToken() ); 01299 } else { 01300 if ( !self::getLoginToken() ) { 01301 self::setLoginToken(); 01302 } 01303 $template->set( 'token', self::getLoginToken() ); 01304 } 01305 01306 # Prepare language selection links as needed 01307 if ( $wgLoginLanguageSelector ) { 01308 $template->set( 'languages', $this->makeLanguageSelector() ); 01309 if ( $this->mLanguage ) { 01310 $template->set( 'uselang', $this->mLanguage ); 01311 } 01312 } 01313 01314 $template->set( 'secureLoginUrl', $this->mSecureLoginUrl ); 01315 // Use loginend-https for HTTPS requests if it's not blank, loginend otherwise 01316 // Ditto for signupend. New forms use neither. 01317 $usingHTTPS = $this->mRequest->getProtocol() == 'https'; 01318 $loginendHTTPS = $this->msg( 'loginend-https' ); 01319 $signupendHTTPS = $this->msg( 'signupend-https' ); 01320 if ( $usingHTTPS && !$loginendHTTPS->isBlank() ) { 01321 $template->set( 'loginend', $loginendHTTPS->parse() ); 01322 } else { 01323 $template->set( 'loginend', $this->msg( 'loginend' )->parse() ); 01324 } 01325 if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) { 01326 $template->set( 'signupend', $signupendHTTPS->parse() ); 01327 } else { 01328 $template->set( 'signupend', $this->msg( 'signupend' )->parse() ); 01329 } 01330 01331 // Give authentication and captcha plugins a chance to modify the form 01332 $wgAuth->modifyUITemplate( $template, $this->mType ); 01333 if ( $this->mType == 'signup' ) { 01334 wfRunHooks( 'UserCreateForm', array( &$template ) ); 01335 } else { 01336 wfRunHooks( 'UserLoginForm', array( &$template ) ); 01337 } 01338 01339 $out->disallowUserJs(); // just in case... 01340 $out->addTemplate( $template ); 01341 } 01342 01350 private function showCreateOrLoginLink( &$user ) { 01351 if ( $this->mType == 'signup' ) { 01352 return true; 01353 } elseif ( $user->isAllowed( 'createaccount' ) ) { 01354 return true; 01355 } else { 01356 return false; 01357 } 01358 } 01359 01370 function hasSessionCookie() { 01371 global $wgDisableCookieCheck; 01372 01373 return $wgDisableCookieCheck ? true : $this->getRequest()->checkSessionCookie(); 01374 } 01375 01380 public static function getLoginToken() { 01381 global $wgRequest; 01382 01383 return $wgRequest->getSessionData( 'wsLoginToken' ); 01384 } 01385 01389 public static function setLoginToken() { 01390 global $wgRequest; 01391 // Generate a token directly instead of using $user->getEditToken() 01392 // because the latter reuses $_SESSION['wsEditToken'] 01393 $wgRequest->setSessionData( 'wsLoginToken', MWCryptRand::generateHex( 32 ) ); 01394 } 01395 01399 public static function clearLoginToken() { 01400 global $wgRequest; 01401 $wgRequest->setSessionData( 'wsLoginToken', null ); 01402 } 01403 01408 public static function getCreateaccountToken() { 01409 global $wgRequest; 01410 01411 return $wgRequest->getSessionData( 'wsCreateaccountToken' ); 01412 } 01413 01417 public static function setCreateaccountToken() { 01418 global $wgRequest; 01419 $wgRequest->setSessionData( 'wsCreateaccountToken', MWCryptRand::generateHex( 32 ) ); 01420 } 01421 01425 public static function clearCreateaccountToken() { 01426 global $wgRequest; 01427 $wgRequest->setSessionData( 'wsCreateaccountToken', null ); 01428 } 01429 01433 private function renewSessionId() { 01434 global $wgSecureLogin, $wgCookieSecure; 01435 if ( $wgSecureLogin && !$this->mStickHTTPS ) { 01436 $wgCookieSecure = false; 01437 } 01438 01439 wfResetSessionID(); 01440 } 01441 01445 function cookieRedirectCheck( $type ) { 01446 $titleObj = SpecialPage::getTitleFor( 'Userlogin' ); 01447 $query = array( 'wpCookieCheck' => $type ); 01448 if ( $this->mReturnTo !== '' ) { 01449 $query['returnto'] = $this->mReturnTo; 01450 $query['returntoquery'] = $this->mReturnToQuery; 01451 } 01452 $check = $titleObj->getFullURL( $query ); 01453 01454 $this->getOutput()->redirect( $check ); 01455 } 01456 01460 function onCookieRedirectCheck( $type ) { 01461 if ( !$this->hasSessionCookie() ) { 01462 if ( $type == 'new' ) { 01463 $this->mainLoginForm( $this->msg( 'nocookiesnew' )->parse() ); 01464 } elseif ( $type == 'login' ) { 01465 $this->mainLoginForm( $this->msg( 'nocookieslogin' )->parse() ); 01466 } else { 01467 # shouldn't happen 01468 $this->mainLoginForm( $this->msg( 'error' )->text() ); 01469 } 01470 } else { 01471 $this->successfulLogin(); 01472 } 01473 } 01474 01481 function makeLanguageSelector() { 01482 $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage(); 01483 if ( !$msg->isBlank() ) { 01484 $langs = explode( "\n", $msg->text() ); 01485 $links = array(); 01486 foreach ( $langs as $lang ) { 01487 $lang = trim( $lang, '* ' ); 01488 $parts = explode( '|', $lang ); 01489 if ( count( $parts ) >= 2 ) { 01490 $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) ); 01491 } 01492 } 01493 01494 return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams( 01495 $this->getLanguage()->pipeList( $links ) )->escaped() : ''; 01496 } else { 01497 return ''; 01498 } 01499 } 01500 01509 function makeLanguageSelectorLink( $text, $lang ) { 01510 if ( $this->getLanguage()->getCode() == $lang ) { 01511 // no link for currently used language 01512 return htmlspecialchars( $text ); 01513 } 01514 $query = array( 'uselang' => $lang ); 01515 if ( $this->mType == 'signup' ) { 01516 $query['type'] = 'signup'; 01517 } 01518 if ( $this->mReturnTo !== '' ) { 01519 $query['returnto'] = $this->mReturnTo; 01520 $query['returntoquery'] = $this->mReturnToQuery; 01521 } 01522 01523 $attr = array(); 01524 $targetLanguage = Language::factory( $lang ); 01525 $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode(); 01526 01527 return Linker::linkKnown( 01528 $this->getPageTitle(), 01529 htmlspecialchars( $text ), 01530 $attr, 01531 $query 01532 ); 01533 } 01534 01535 protected function getGroupName() { 01536 return 'login'; 01537 } 01538 }