MediaWiki  REL1_23
SpecialUserlogin.php
Go to the documentation of this file.
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 }