~ubuntu-branches/debian/squeeze/mediawiki/squeeze

« back to all changes in this revision

Viewing changes to .pc/CVE-2012-5391.patch/includes/specials/SpecialUserlogin.php

  • Committer: Package Import Robot
  • Author(s): Jonathan Wiltshire, Dominik George
  • Date: 2012-12-16 17:53:38 UTC
  • Revision ID: package-import@ubuntu.com-20121216175338-yww3xg2e3svd4gqr
Tags: 1:1.15.5-2squeeze5
[ Dominik George ]
* Security fixes from upstream (Closes: #694998):
  - CVE-2012-5391 - Prevent session fixation in Special:UserLogin
  - Prevent linker regex from exceeding backtrack limit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * @file
 
4
 * @ingroup SpecialPage
 
5
 */
 
6
 
 
7
/**
 
8
 * constructor
 
9
 */
 
10
function wfSpecialUserlogin( $par = '' ) {
 
11
        global $wgRequest;
 
12
        if( session_id() == '' ) {
 
13
                wfSetupSession();
 
14
        }
 
15
 
 
16
        $form = new LoginForm( $wgRequest, $par );
 
17
        $form->execute();
 
18
}
 
19
 
 
20
/**
 
21
 * implements Special:Login
 
22
 * @ingroup SpecialPage
 
23
 */
 
24
class LoginForm {
 
25
 
 
26
        const SUCCESS = 0;
 
27
        const NO_NAME = 1;
 
28
        const ILLEGAL = 2;
 
29
        const WRONG_PLUGIN_PASS = 3;
 
30
        const NOT_EXISTS = 4;
 
31
        const WRONG_PASS = 5;
 
32
        const EMPTY_PASS = 6;
 
33
        const RESET_PASS = 7;
 
34
        const ABORTED = 8;
 
35
        const CREATE_BLOCKED = 9;
 
36
        const THROTTLED = 10;
 
37
        const USER_BLOCKED = 11;
 
38
        const NEED_TOKEN = 12;
 
39
        const WRONG_TOKEN = 13;
 
40
 
 
41
        var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
 
42
        var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
 
43
        var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage, $mSkipCookieCheck;
 
44
        var $mToken;
 
45
 
 
46
        /**
 
47
         * Constructor
 
48
         * @param WebRequest $request A WebRequest object passed by reference
 
49
         */
 
50
        function LoginForm( &$request, $par = '' ) {
 
51
                global $wgLang, $wgAllowRealName, $wgEnableEmail;
 
52
                global $wgAuth, $wgRedirectOnLogin;
 
53
 
 
54
                $this->mType = ( $par == 'signup' ) ? $par : $request->getText( 'type' ); # Check for [[Special:Userlogin/signup]]
 
55
                $this->mName = $request->getText( 'wpName' );
 
56
                $this->mPassword = $request->getText( 'wpPassword' );
 
57
                $this->mRetype = $request->getText( 'wpRetype' );
 
58
                $this->mDomain = $request->getText( 'wpDomain' );
 
59
                $this->mReturnTo = $request->getVal( 'returnto' );
 
60
                $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
 
61
                $this->mPosted = $request->wasPosted();
 
62
                $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
 
63
                $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
 
64
                                            && $wgEnableEmail;
 
65
                $this->mMailmypassword = $request->getCheck( 'wpMailmypassword' )
 
66
                                         && $wgEnableEmail;
 
67
                $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
 
68
                $this->mAction = $request->getVal( 'action' );
 
69
                $this->mRemember = $request->getCheck( 'wpRemember' );
 
70
                $this->mLanguage = $request->getText( 'uselang' );
 
71
                $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
 
72
                $this->mToken = ($this->mType == 'signup' ) ? $request->getVal( 'wpCreateaccountToken' ) : $request->getVal( 'wpLoginToken' );
 
73
 
 
74
                if ( $wgRedirectOnLogin ) {
 
75
                        $this->mReturnTo = $wgRedirectOnLogin;
 
76
                }
 
77
 
 
78
                if( $wgEnableEmail ) {
 
79
                        $this->mEmail = $request->getText( 'wpEmail' );
 
80
                } else {
 
81
                        $this->mEmail = '';
 
82
                }
 
83
                if( $wgAllowRealName ) {
 
84
                    $this->mRealName = $request->getText( 'wpRealName' );
 
85
                } else {
 
86
                    $this->mRealName = '';
 
87
                }
 
88
 
 
89
                if( !$wgAuth->validDomain( $this->mDomain ) ) {
 
90
                        $this->mDomain = 'invaliddomain';
 
91
                }
 
92
                $wgAuth->setDomain( $this->mDomain );
 
93
 
 
94
                # When switching accounts, it sucks to get automatically logged out
 
95
                if( $this->mReturnTo == $wgLang->specialPage( 'Userlogout' ) ) {
 
96
                        $this->mReturnTo = '';
 
97
                }
 
98
        }
 
99
 
 
100
        function execute() {
 
101
                if ( !is_null( $this->mCookieCheck ) ) {
 
102
                        $this->onCookieRedirectCheck( $this->mCookieCheck );
 
103
                        return;
 
104
                } else if( $this->mPosted ) {
 
105
                        if( $this->mCreateaccount ) {
 
106
                                return $this->addNewAccount();
 
107
                        } else if ( $this->mCreateaccountMail ) {
 
108
                                return $this->addNewAccountMailPassword();
 
109
                        } else if ( $this->mMailmypassword ) {
 
110
                                return $this->mailPassword();
 
111
                        } else if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
 
112
                                return $this->processLogin();
 
113
                        }
 
114
                }
 
115
                $this->mainLoginForm( '' );
 
116
        }
 
117
 
 
118
        /**
 
119
         * @private
 
120
         */
 
121
        function addNewAccountMailPassword() {
 
122
                global $wgOut;
 
123
 
 
124
                if ('' == $this->mEmail) {
 
125
                        $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) );
 
126
                        return;
 
127
                }
 
128
 
 
129
                $u = $this->addNewaccountInternal();
 
130
 
 
131
                if ($u == NULL) {
 
132
                        return;
 
133
                }
 
134
 
 
135
                // Wipe the initial password and mail a temporary one
 
136
                $u->setPassword( null );
 
137
                $u->saveSettings();
 
138
                $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
 
139
 
 
140
                wfRunHooks( 'AddNewAccount', array( $u, true ) );
 
141
                $u->addNewUserLogEntry();
 
142
 
 
143
                $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
 
144
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
 
145
                $wgOut->setArticleRelated( false );
 
146
 
 
147
                if( WikiError::isError( $result ) ) {
 
148
                        $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
 
149
                } else {
 
150
                        $wgOut->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
 
151
                        $wgOut->returnToMain( false );
 
152
                }
 
153
                $u = 0;
 
154
        }
 
155
 
 
156
 
 
157
        /**
 
158
         * @private
 
159
         */
 
160
        function addNewAccount() {
 
161
                global $wgUser, $wgEmailAuthentication;
 
162
 
 
163
                # Create the account and abort if there's a problem doing so
 
164
                $u = $this->addNewAccountInternal();
 
165
                if( $u == NULL )
 
166
                        return;
 
167
 
 
168
                # If we showed up language selection links, and one was in use, be
 
169
                # smart (and sensible) and save that language as the user's preference
 
170
                global $wgLoginLanguageSelector;
 
171
                if( $wgLoginLanguageSelector && $this->mLanguage )
 
172
                        $u->setOption( 'language', $this->mLanguage );
 
173
 
 
174
                # Send out an email authentication message if needed
 
175
                if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
 
176
                        global $wgOut;
 
177
                        $error = $u->sendConfirmationMail();
 
178
                        if( WikiError::isError( $error ) ) {
 
179
                                $wgOut->addWikiMsg( 'confirmemail_sendfailed', $error->getMessage() );
 
180
                        } else {
 
181
                                $wgOut->addWikiMsg( 'confirmemail_oncreate' );
 
182
                        }
 
183
                }
 
184
 
 
185
                # Save settings (including confirmation token)
 
186
                $u->saveSettings();
 
187
 
 
188
                # If not logged in, assume the new account as the current one and set
 
189
                # session cookies then show a "welcome" message or a "need cookies"
 
190
                # message as needed
 
191
                if( $wgUser->isAnon() ) {
 
192
                        $wgUser = $u;
 
193
                        $wgUser->setCookies();
 
194
                        wfRunHooks( 'AddNewAccount', array( $wgUser ) );
 
195
                        $wgUser->addNewUserLogEntry();
 
196
                        if( $this->hasSessionCookie() ) {
 
197
                                return $this->successfulCreation();
 
198
                        } else {
 
199
                                return $this->cookieRedirectCheck( 'new' );
 
200
                        }
 
201
                } else {
 
202
                        # Confirm that the account was created
 
203
                        global $wgOut;
 
204
                        $self = SpecialPage::getTitleFor( 'Userlogin' );
 
205
                        $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
 
206
                        $wgOut->setArticleRelated( false );
 
207
                        $wgOut->setRobotPolicy( 'noindex,nofollow' );
 
208
                        $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
 
209
                        $wgOut->returnToMain( false, $self );
 
210
                        wfRunHooks( 'AddNewAccount', array( $u ) );
 
211
                        $u->addNewUserLogEntry();
 
212
                        return true;
 
213
                }
 
214
        }
 
215
 
 
216
        /**
 
217
         * @private
 
218
         */
 
219
        function addNewAccountInternal() {
 
220
                global $wgUser, $wgOut;
 
221
                global $wgEnableSorbs, $wgProxyWhitelist;
 
222
                global $wgMemc, $wgAccountCreationThrottle;
 
223
                global $wgAuth, $wgMinimalPasswordLength;
 
224
                global $wgEmailConfirmToEdit;
 
225
 
 
226
                // If the user passes an invalid domain, something is fishy
 
227
                if( !$wgAuth->validDomain( $this->mDomain ) ) {
 
228
                        $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
 
229
                        return false;
 
230
                }
 
231
 
 
232
                // If we are not allowing users to login locally, we should be checking
 
233
                // to see if the user is actually able to authenticate to the authenti-
 
234
                // cation server before they create an account (otherwise, they can
 
235
                // create a local account and login as any domain user). We only need
 
236
                // to check this for domains that aren't local.
 
237
                if( 'local' != $this->mDomain && '' != $this->mDomain ) {
 
238
                        if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
 
239
                                $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
 
240
                                return false;
 
241
                        }
 
242
                }
 
243
 
 
244
                if ( wfReadOnly() ) {
 
245
                        $wgOut->readOnlyPage();
 
246
                        return false;
 
247
                }
 
248
 
 
249
                # Request forgery checks.
 
250
                if ( !self::getCreateaccountToken() ) {
 
251
                        self::setCreateaccountToken();
 
252
                        $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
253
                        return false;
 
254
                }
 
255
                
 
256
                # The user didn't pass a createaccount token
 
257
                if ( !$this->mToken ) {
 
258
                        $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
259
                        return false;
 
260
                }
 
261
                
 
262
                # Validate the createaccount token
 
263
                if ( $this->mToken !== self::getCreateaccountToken() ) {
 
264
                        $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
265
                        return false;
 
266
                }
 
267
 
 
268
                # Check permissions
 
269
                if ( !$wgUser->isAllowed( 'createaccount' ) ) {
 
270
                        $this->userNotPrivilegedMessage();
 
271
                        return false;
 
272
                } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
 
273
                        $this->userBlockedMessage();
 
274
                        return false;
 
275
                }
 
276
 
 
277
                $ip = wfGetIP();
 
278
                if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
 
279
                  $wgUser->inSorbsBlacklist( $ip ) )
 
280
                {
 
281
                        $this->mainLoginForm( wfMsg( 'sorbs_create_account_reason' ) . ' (' . htmlspecialchars( $ip ) . ')' );
 
282
                        return false;
 
283
                }
 
284
 
 
285
                # Now create a dummy user ($u) and check if it is valid
 
286
                $name = trim( $this->mName );
 
287
                $u = User::newFromName( $name, 'creatable' );
 
288
                if ( is_null( $u ) ) {
 
289
                        $this->mainLoginForm( wfMsg( 'noname' ) );
 
290
                        return false;
 
291
                }
 
292
 
 
293
                if ( 0 != $u->idForName() ) {
 
294
                        $this->mainLoginForm( wfMsg( 'userexists' ) );
 
295
                        return false;
 
296
                }
 
297
 
 
298
                if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
 
299
                        $this->mainLoginForm( wfMsg( 'badretype' ) );
 
300
                        return false;
 
301
                }
 
302
 
 
303
                # check for minimal password length
 
304
                if ( !$u->isValidPassword( $this->mPassword ) ) {
 
305
                        if ( !$this->mCreateaccountMail ) {
 
306
                                $this->mainLoginForm( wfMsgExt( 'passwordtooshort', array( 'parsemag' ), $wgMinimalPasswordLength ) );
 
307
                                return false;
 
308
                        } else {
 
309
                                # do not force a password for account creation by email
 
310
                                # set invalid password, it will be replaced later by a random generated password
 
311
                                $this->mPassword = null;
 
312
                        }
 
313
                }
 
314
 
 
315
                # if you need a confirmed email address to edit, then obviously you
 
316
                # need an email address.
 
317
                if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
 
318
                        $this->mainLoginForm( wfMsg( 'noemailtitle' ) );
 
319
                        return false;
 
320
                }
 
321
 
 
322
                if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
 
323
                        $this->mainLoginForm( wfMsg( 'invalidemailaddress' ) );
 
324
                        return false;
 
325
                }
 
326
 
 
327
                # Set some additional data so the AbortNewAccount hook can be used for
 
328
                # more than just username validation
 
329
                $u->setEmail( $this->mEmail );
 
330
                $u->setRealName( $this->mRealName );
 
331
 
 
332
                $abortError = '';
 
333
                if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
 
334
                        // Hook point to add extra creation throttles and blocks
 
335
                        wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
 
336
                        $this->mainLoginForm( $abortError );
 
337
                        return false;
 
338
                }
 
339
 
 
340
                if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
 
341
                        $key = wfMemcKey( 'acctcreate', 'ip', $ip );
 
342
                        $value = $wgMemc->get( $key );
 
343
                        if ( !$value ) {
 
344
                                $wgMemc->set( $key, 0, 86400 );
 
345
                        }
 
346
                        if ( $value >= $wgAccountCreationThrottle ) {
 
347
                                $this->throttleHit( $wgAccountCreationThrottle );
 
348
                                return false;
 
349
                        }
 
350
                        $wgMemc->incr( $key );
 
351
                }
 
352
 
 
353
                if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
 
354
                        $this->mainLoginForm( wfMsg( 'externaldberror' ) );
 
355
                        return false;
 
356
                }
 
357
 
 
358
                self::clearCreateaccountToken();                
 
359
                return $this->initUser( $u, false );
 
360
        }
 
361
 
 
362
        /**
 
363
         * Actually add a user to the database.
 
364
         * Give it a User object that has been initialised with a name.
 
365
         *
 
366
         * @param $u User object.
 
367
         * @param $autocreate boolean -- true if this is an autocreation via auth plugin
 
368
         * @return User object.
 
369
         * @private
 
370
         */
 
371
        function initUser( $u, $autocreate ) {
 
372
                global $wgAuth;
 
373
 
 
374
                $u->addToDatabase();
 
375
 
 
376
                if ( $wgAuth->allowPasswordChange() ) {
 
377
                        $u->setPassword( $this->mPassword );
 
378
                }
 
379
 
 
380
                $u->setEmail( $this->mEmail );
 
381
                $u->setRealName( $this->mRealName );
 
382
                $u->setToken();
 
383
 
 
384
                $wgAuth->initUser( $u, $autocreate );
 
385
 
 
386
                $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
 
387
                $u->saveSettings();
 
388
 
 
389
                # Update user count
 
390
                $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
 
391
                $ssUpdate->doUpdate();
 
392
 
 
393
                return $u;
 
394
        }
 
395
 
 
396
        /**
 
397
         * Internally authenticate the login request.
 
398
         *
 
399
         * This may create a local account as a side effect if the
 
400
         * authentication plugin allows transparent local account
 
401
         * creation.
 
402
         *
 
403
         * @public
 
404
         */
 
405
        function authenticateUserData() {
 
406
                global $wgUser, $wgAuth;
 
407
                if ( '' == $this->mName ) {
 
408
                        return self::NO_NAME;
 
409
                }
 
410
 
 
411
                // We require a login token to prevent login CSRF
 
412
                // Handle part of this before incrementing the throttle so
 
413
                // token-less login attempts don't count towards the throttle
 
414
                // but wrong-token attempts do.
 
415
                
 
416
                // If the user doesn't have a login token yet, set one.
 
417
                if ( !self::getLoginToken() ) {
 
418
                        self::setLoginToken();
 
419
                        return self::NEED_TOKEN;
 
420
                }
 
421
                // If the user didn't pass a login token, tell them we need one
 
422
                if ( !$this->mToken ) {
 
423
                        return self::NEED_TOKEN;
 
424
                }
 
425
 
 
426
                global $wgPasswordAttemptThrottle;
 
427
 
 
428
                $throttleCount=0;
 
429
                if ( is_array($wgPasswordAttemptThrottle) ) {
 
430
                        $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
 
431
                        $count = $wgPasswordAttemptThrottle['count'];
 
432
                        $period = $wgPasswordAttemptThrottle['seconds'];
 
433
                        
 
434
                        global $wgMemc;
 
435
                        $throttleCount = $wgMemc->get($throttleKey);
 
436
                        if ( !$throttleCount ) {
 
437
                                $wgMemc->add( $throttleKey, 1, $period ); // start counter
 
438
                        } else if ( $throttleCount < $count ) {
 
439
                                $wgMemc->incr($throttleKey);
 
440
                        } else if ( $throttleCount >= $count ) {
 
441
                                return self::THROTTLED;
 
442
                        }
 
443
                }
 
444
                
 
445
                // Validate the login token
 
446
                if ( $this->mToken !== self::getLoginToken() ) {
 
447
                        return self::WRONG_TOKEN;
 
448
                }
 
449
 
 
450
                // Load $wgUser now, and check to see if we're logging in as the same
 
451
                // name. This is necessary because loading $wgUser (say by calling
 
452
                // getName()) calls the UserLoadFromSession hook, which potentially
 
453
                // creates the user in the database. Until we load $wgUser, checking
 
454
                // for user existence using User::newFromName($name)->getId() below
 
455
                // will effectively be using stale data.
 
456
                if ( $wgUser->getName() === $this->mName ) {
 
457
                        wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
 
458
                        return self::SUCCESS;
 
459
                }
 
460
                $u = User::newFromName( $this->mName );
 
461
                if( is_null( $u ) || !User::isUsableName( $u->getName() ) ) {
 
462
                        return self::ILLEGAL;
 
463
                }
 
464
 
 
465
                $isAutoCreated = false;
 
466
                if ( 0 == $u->getID() ) {
 
467
                        $status = $this->attemptAutoCreate( $u );
 
468
                        if ( $status !== self::SUCCESS ) {
 
469
                                return $status;
 
470
                        } else {
 
471
                                $isAutoCreated = true;
 
472
                        }
 
473
                } else {
 
474
                        $u->load();
 
475
                }
 
476
 
 
477
                // Give general extensions, such as a captcha, a chance to abort logins
 
478
                $abort = self::ABORTED;
 
479
                if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
 
480
                        return $abort;
 
481
                }
 
482
 
 
483
                if (!$u->checkPassword( $this->mPassword )) {
 
484
                        if( $u->checkTemporaryPassword( $this->mPassword ) ) {
 
485
                                // The e-mailed temporary password should not be used for actu-
 
486
                                // al logins; that's a very sloppy habit, and insecure if an
 
487
                                // attacker has a few seconds to click "search" on someone's o-
 
488
                                // pen mail reader.
 
489
                                //
 
490
                                // Allow it to be used only to reset the password a single time
 
491
                                // to a new value, which won't be in the user's e-mail ar-
 
492
                                // chives.
 
493
                                //
 
494
                                // For backwards compatibility, we'll still recognize it at the
 
495
                                // login form to minimize surprises for people who have been
 
496
                                // logging in with a temporary password for some time.
 
497
                                //
 
498
                                // As a side-effect, we can authenticate the user's e-mail ad-
 
499
                                // dress if it's not already done, since the temporary password
 
500
                                // was sent via e-mail.
 
501
                                if( !$u->isEmailConfirmed() ) {
 
502
                                        $u->confirmEmail();
 
503
                                        $u->saveSettings();
 
504
                                }
 
505
 
 
506
                                // At this point we just return an appropriate code/ indicating
 
507
                                // that the UI should show a password reset form; bot inter-
 
508
                                // faces etc will probably just fail cleanly here.
 
509
                                $retval = self::RESET_PASS;
 
510
                        } else {
 
511
                                $retval = '' == $this->mPassword ? self::EMPTY_PASS : self::WRONG_PASS;
 
512
                        }
 
513
                } else {
 
514
                        $wgAuth->updateUser( $u );
 
515
                        $wgUser = $u;
 
516
 
 
517
                        // Please reset throttle for successful logins, thanks!
 
518
                        if($throttleCount) {
 
519
                                $wgMemc->delete($throttleKey);
 
520
                        }
 
521
 
 
522
                        if ( $isAutoCreated ) {
 
523
                                // Must be run after $wgUser is set, for correct new user log
 
524
                                wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
 
525
                        }
 
526
 
 
527
                        $retval = self::SUCCESS;
 
528
                }
 
529
                wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
 
530
                return $retval;
 
531
        }
 
532
 
 
533
        /**
 
534
         * Attempt to automatically create a user on login. Only succeeds if there
 
535
         * is an external authentication method which allows it.
 
536
         * @return integer Status code
 
537
         */
 
538
        function attemptAutoCreate( $user ) {
 
539
                global $wgAuth, $wgUser;
 
540
                /**
 
541
                 * If the external authentication plugin allows it, automatically cre-
 
542
                 * ate a new account for users that are externally defined but have not
 
543
                 * yet logged in.
 
544
                 */
 
545
                if ( !$wgAuth->autoCreate() ) {
 
546
                        return self::NOT_EXISTS;
 
547
                }
 
548
                if ( !$wgAuth->userExists( $user->getName() ) ) {
 
549
                        wfDebug( __METHOD__.": user does not exist\n" );
 
550
                        return self::NOT_EXISTS;
 
551
                }
 
552
                if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
 
553
                        wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
 
554
                        return self::WRONG_PLUGIN_PASS;
 
555
                }
 
556
                if ( $wgUser->isBlockedFromCreateAccount() ) {
 
557
                        wfDebug( __METHOD__.": user is blocked from account creation\n" );
 
558
                        return self::CREATE_BLOCKED;
 
559
                }
 
560
 
 
561
                wfDebug( __METHOD__.": creating account\n" );
 
562
                $user = $this->initUser( $user, true );
 
563
                return self::SUCCESS;
 
564
        }
 
565
 
 
566
        function processLogin() {
 
567
                global $wgUser, $wgAuth;
 
568
 
 
569
                switch ($this->authenticateUserData())
 
570
                {
 
571
                        case self::SUCCESS:
 
572
                                # We've verified now, update the real record
 
573
                                if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
 
574
                                        $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
 
575
                                        $wgUser->saveSettings();
 
576
                                } else {
 
577
                                        $wgUser->invalidateCache();
 
578
                                }
 
579
                                $wgUser->setCookies();
 
580
                                self::clearLoginToken();
 
581
 
 
582
                                // Reset the throttle
 
583
                                $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
 
584
                                global $wgMemc;
 
585
                                $wgMemc->delete( $key );
 
586
 
 
587
                                if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
 
588
                                        /* Replace the language object to provide user interface in
 
589
                                         * correct language immediately on this first page load.
 
590
                                         */
 
591
                                        global $wgLang, $wgRequest;
 
592
                                        $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
 
593
                                        $wgLang = Language::factory( $code );
 
594
                                        return $this->successfulLogin();
 
595
                                } else {
 
596
                                        return $this->cookieRedirectCheck( 'login' );
 
597
                                }
 
598
                                break;
 
599
                        
 
600
                        case self::NEED_TOKEN:
 
601
                        case self::WRONG_TOKEN:
 
602
                                $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
603
                                break;
 
604
                        case self::NO_NAME:
 
605
                        case self::ILLEGAL:
 
606
                                $this->mainLoginForm( wfMsg( 'noname' ) );
 
607
                                break;
 
608
                        case self::WRONG_PLUGIN_PASS:
 
609
                                $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
 
610
                                break;
 
611
                        case self::NOT_EXISTS:
 
612
                                if( $wgUser->isAllowed( 'createaccount' ) ){
 
613
                                        $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
 
614
                                } else {
 
615
                                        $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
 
616
                                }
 
617
                                break;
 
618
                        case self::WRONG_PASS:
 
619
                                $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
 
620
                                break;
 
621
                        case self::EMPTY_PASS:
 
622
                                $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
 
623
                                break;
 
624
                        case self::RESET_PASS:
 
625
                                $this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
 
626
                                break;
 
627
                        case self::CREATE_BLOCKED:
 
628
                                $this->userBlockedMessage();
 
629
                                break;
 
630
                        case self::THROTTLED:
 
631
                                $this->mainLoginForm( wfMsg( 'login-throttled' ) );
 
632
                                break;
 
633
                        default:
 
634
                                throw new MWException( "Unhandled case value" );
 
635
                }
 
636
        }
 
637
 
 
638
        function resetLoginForm( $error ) {
 
639
                global $wgOut;
 
640
                $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
 
641
                $reset = new SpecialResetpass();
 
642
                $reset->execute( null );
 
643
        }
 
644
 
 
645
        /**
 
646
         * @private
 
647
         */
 
648
        function mailPassword() {
 
649
                global $wgUser, $wgOut, $wgAuth;
 
650
                
 
651
                if ( wfReadOnly() ) {
 
652
                        $wgOut->readOnlyPage();
 
653
                        return false;
 
654
                }
 
655
                
 
656
                if( !$wgAuth->allowPasswordChange() ) {
 
657
                        $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
 
658
                        return;
 
659
                }
 
660
 
 
661
                # Check against blocked IPs so blocked users can't flood admins 
 
662
                # with password resets
 
663
                if( $wgUser->isBlocked() ) {
 
664
                        $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
 
665
                        return;
 
666
                }
 
667
 
 
668
                # If the user doesn't have a login token yet, set one.
 
669
                if ( !self::getLoginToken() ) {
 
670
                        self::setLoginToken();
 
671
                        $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
672
                        return;
 
673
                }
 
674
 
 
675
                # If the user didn't pass a login token, tell them we need one
 
676
                if ( !$this->mToken ) {
 
677
                        $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
678
                        return;
 
679
                }
 
680
                
 
681
                # Check against the rate limiter
 
682
                if( $wgUser->pingLimiter( 'mailpassword' ) ) {
 
683
                        $wgOut->rateLimited();
 
684
                        return;
 
685
                }
 
686
 
 
687
                if ( '' == $this->mName ) {
 
688
                        $this->mainLoginForm( wfMsg( 'noname' ) );
 
689
                        return;
 
690
                }
 
691
                $u = User::newFromName( $this->mName );
 
692
                if( is_null( $u ) ) {
 
693
                        $this->mainLoginForm( wfMsg( 'noname' ) );
 
694
                        return;
 
695
                }
 
696
                if ( 0 == $u->getID() ) {
 
697
                        $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
 
698
                        return;
 
699
                }
 
700
 
 
701
                # Validate the login token
 
702
                if ( $this->mToken !== self::getLoginToken() ) {
 
703
                        $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
 
704
                        return;
 
705
                }
 
706
 
 
707
                # Check against password throttle
 
708
                if ( $u->isPasswordReminderThrottled() ) {
 
709
                        global $wgPasswordReminderResendTime;
 
710
                        # Round the time in hours to 3 d.p., in case someone is specifying
 
711
                        # minutes or seconds.
 
712
                        $this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
 
713
                                round( $wgPasswordReminderResendTime, 3 ) ) );
 
714
                        return;
 
715
                }
 
716
 
 
717
                $result = $this->mailPasswordInternal( $u, true, 'passwordremindertitle', 'passwordremindertext' );
 
718
                if( WikiError::isError( $result ) ) {
 
719
                        $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
 
720
                } else {
 
721
                        $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ), 'success' );
 
722
                        self::clearLoginToken();
 
723
                }
 
724
        }
 
725
 
 
726
 
 
727
        /**
 
728
         * @param object user
 
729
         * @param bool throttle
 
730
         * @param string message name of email title
 
731
         * @param string message name of email text
 
732
         * @return mixed true on success, WikiError on failure
 
733
         * @private
 
734
         */
 
735
        function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) {
 
736
                global $wgServer, $wgScript, $wgUser, $wgNewPasswordExpiry;
 
737
 
 
738
                if ( '' == $u->getEmail() ) {
 
739
                        return new WikiError( wfMsg( 'noemail', $u->getName() ) );
 
740
                }
 
741
                $ip = wfGetIP();
 
742
                if( !$ip ) {
 
743
                        return new WikiError( wfMsg( 'badipaddress' ) );
 
744
                }
 
745
                
 
746
                wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$u) );
 
747
 
 
748
                $np = $u->randomPassword();
 
749
                $u->setNewpassword( $np, $throttle );
 
750
                $u->saveSettings();
 
751
 
 
752
                $m = wfMsgExt( $emailText, array( 'parsemag' ), $ip, $u->getName(), $np,
 
753
                                $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
 
754
                $result = $u->sendMail( wfMsg( $emailTitle ), $m );
 
755
 
 
756
                return $result;
 
757
        }
 
758
 
 
759
 
 
760
        /**
 
761
         * Run any hooks registered for logins, then HTTP redirect to
 
762
         * $this->mReturnTo (or Main Page if that's undefined).  Formerly we had a
 
763
         * nice message here, but that's really not as useful as just being sent to
 
764
         * wherever you logged in from.  It should be clear that the action was
 
765
         * successful, given the lack of error messages plus the appearance of your
 
766
         * name in the upper right.
 
767
         *
 
768
         * @private
 
769
         */
 
770
        function successfulLogin() {
 
771
                global $wgUser, $wgOut;
 
772
 
 
773
                # Run any hooks; display injected HTML if any, else redirect
 
774
                $injected_html = '';
 
775
                wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
 
776
 
 
777
                if( $injected_html !== '' ) {
 
778
                        $this->displaySuccessfulLogin( 'loginsuccess', $injected_html );
 
779
                } else {
 
780
                        $titleObj = Title::newFromText( $this->mReturnTo );
 
781
                        if ( !$titleObj instanceof Title ) {
 
782
                                $titleObj = Title::newMainPage();
 
783
                        }
 
784
 
 
785
                        $wgOut->redirect( $titleObj->getFullURL() );
 
786
                }
 
787
        }
 
788
 
 
789
        /**
 
790
         * Run any hooks registered for logins, then display a message welcoming
 
791
         * the user.
 
792
         *
 
793
         * @private
 
794
         */
 
795
        function successfulCreation() {
 
796
                global $wgUser, $wgOut;
 
797
 
 
798
                # Run any hooks; display injected HTML
 
799
                $injected_html = '';
 
800
                wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
 
801
 
 
802
                $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
 
803
        }
 
804
 
 
805
        /**
 
806
         * Display a "login successful" page.
 
807
         */
 
808
        private function displaySuccessfulLogin( $msgname, $injected_html ) {
 
809
                global $wgOut, $wgUser;
 
810
 
 
811
                $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
 
812
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
 
813
                $wgOut->setArticleRelated( false );
 
814
                $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
 
815
                $wgOut->addHTML( $injected_html );
 
816
 
 
817
                if ( !empty( $this->mReturnTo ) ) {
 
818
                        $wgOut->returnToMain( null, $this->mReturnTo );
 
819
                } else {
 
820
                        $wgOut->returnToMain( null );
 
821
                }
 
822
        }
 
823
 
 
824
        /** */
 
825
        function userNotPrivilegedMessage($errors) {
 
826
                global $wgOut;
 
827
 
 
828
                $wgOut->setPageTitle( wfMsg( 'permissionserrors' ) );
 
829
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
 
830
                $wgOut->setArticleRelated( false );
 
831
 
 
832
                $wgOut->addWikitext( $wgOut->formatPermissionsErrorMessage( $errors, 'createaccount' ) );
 
833
                // Stuff that might want to be added at the end. For example, instruc-
 
834
                // tions if blocked.
 
835
                $wgOut->addWikiMsg( 'cantcreateaccount-nonblock-text' );
 
836
 
 
837
                $wgOut->returnToMain( false );
 
838
        }
 
839
 
 
840
        /** */
 
841
        function userBlockedMessage() {
 
842
                global $wgOut, $wgUser;
 
843
 
 
844
                # Let's be nice about this, it's likely that this feature will be used
 
845
                # for blocking large numbers of innocent people, e.g. range blocks on
 
846
                # schools. Don't blame it on the user. There's a small chance that it
 
847
                # really is the user's fault, i.e. the username is blocked and they
 
848
                # haven't bothered to log out before trying to create an account to
 
849
                # evade it, but we'll leave that to their guilty conscience to figure
 
850
                # out.
 
851
 
 
852
                $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
 
853
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
 
854
                $wgOut->setArticleRelated( false );
 
855
 
 
856
                $ip = wfGetIP();
 
857
                $blocker = User::whoIs( $wgUser->mBlock->mBy );
 
858
                $block_reason = $wgUser->mBlock->mReason;
 
859
 
 
860
                if ( strval( $block_reason ) === '' ) {
 
861
                        $block_reason = wfMsg( 'blockednoreason' );
 
862
                }
 
863
                $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
 
864
                $wgOut->returnToMain( false );
 
865
        }
 
866
 
 
867
        /**
 
868
         * @private
 
869
         */
 
870
        function mainLoginForm( $msg, $msgtype = 'error' ) {
 
871
                global $wgUser, $wgOut, $wgAllowRealName, $wgEnableEmail;
 
872
                global $wgCookiePrefix, $wgLoginLanguageSelector;
 
873
                global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
 
874
                
 
875
                $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
 
876
                
 
877
                if ( $this->mType == 'signup' ) {
 
878
                        // Block signup here if in readonly. Keeps user from 
 
879
                        // going through the process (filling out data, etc) 
 
880
                        // and being informed later.
 
881
                        if ( wfReadOnly() ) {
 
882
                                $wgOut->readOnlyPage();
 
883
                                return;
 
884
                        } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
 
885
                                $this->userBlockedMessage();
 
886
                                return;
 
887
                        } elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
 
888
                                $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
 
889
                                return;
 
890
                        }
 
891
                }
 
892
 
 
893
                if ( '' == $this->mName ) {
 
894
                        if ( $wgUser->isLoggedIn() ) {
 
895
                                $this->mName = $wgUser->getName();
 
896
                        } else {
 
897
                                $this->mName = isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ? $_COOKIE[$wgCookiePrefix.'UserName'] : null;
 
898
                        }
 
899
                }
 
900
 
 
901
                $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
 
902
 
 
903
                if ( $this->mType == 'signup' ) {
 
904
                        $template = new UsercreateTemplate();
 
905
                        $q = 'action=submitlogin&type=signup';
 
906
                        $linkq = 'type=login';
 
907
                        $linkmsg = 'gotaccount';
 
908
                } else {
 
909
                        $template = new UserloginTemplate();
 
910
                        $q = 'action=submitlogin&type=login';
 
911
                        $linkq = 'type=signup';
 
912
                        $linkmsg = 'nologin';
 
913
                }
 
914
 
 
915
                if ( !empty( $this->mReturnTo ) ) {
 
916
                        $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
 
917
                        $q .= $returnto;
 
918
                        $linkq .= $returnto;
 
919
                }
 
920
 
 
921
                # Pass any language selection on to the mode switch link
 
922
                if( $wgLoginLanguageSelector && $this->mLanguage )
 
923
                        $linkq .= '&uselang=' . $this->mLanguage;
 
924
 
 
925
                $link = '<a href="' . htmlspecialchars ( $titleObj->getLocalUrl( $linkq ) ) . '">';
 
926
                $link .= wfMsgHtml( $linkmsg . 'link' ); # Calling either 'gotaccountlink' or 'nologinlink'
 
927
                $link .= '</a>';
 
928
 
 
929
                # Don't show a "create account" link if the user can't
 
930
                if( $this->showCreateOrLoginLink( $wgUser ) )
 
931
                        $template->set( 'link', wfMsgHtml( $linkmsg, $link ) );
 
932
                else
 
933
                        $template->set( 'link', '' );
 
934
 
 
935
                $template->set( 'header', '' );
 
936
                $template->set( 'name', $this->mName );
 
937
                $template->set( 'password', $this->mPassword );
 
938
                $template->set( 'retype', $this->mRetype );
 
939
                $template->set( 'email', $this->mEmail );
 
940
                $template->set( 'realname', $this->mRealName );
 
941
                $template->set( 'domain', $this->mDomain );
 
942
 
 
943
                $template->set( 'action', $titleObj->getLocalUrl( $q ) );
 
944
                $template->set( 'message', $msg );
 
945
                $template->set( 'messagetype', $msgtype );
 
946
                $template->set( 'createemail', $wgEnableEmail && $wgUser->isLoggedIn() );
 
947
                $template->set( 'userealname', $wgAllowRealName );
 
948
                $template->set( 'useemail', $wgEnableEmail );
 
949
                $template->set( 'emailrequired', $wgEmailConfirmToEdit );
 
950
                $template->set( 'canreset', $wgAuth->allowPasswordChange() );
 
951
                $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
 
952
                $template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) or $this->mRemember  );
 
953
 
 
954
                if ( $this->mType == 'signup' ) {
 
955
                        if ( !self::getCreateaccountToken() ) {
 
956
                                self::setCreateaccountToken();
 
957
                        }
 
958
                        $template->set( 'token', self::getCreateaccountToken() );
 
959
                } else {
 
960
                        if ( !self::getLoginToken() ) {
 
961
                                self::setLoginToken();
 
962
                        }
 
963
                        $template->set( 'token', self::getLoginToken() );
 
964
                }
 
965
                
 
966
                # Prepare language selection links as needed
 
967
                if( $wgLoginLanguageSelector ) {
 
968
                        $template->set( 'languages', $this->makeLanguageSelector() );
 
969
                        if( $this->mLanguage )
 
970
                                $template->set( 'uselang', $this->mLanguage );
 
971
                }
 
972
 
 
973
                // Give authentication and captcha plugins a chance to modify the form
 
974
                $wgAuth->modifyUITemplate( $template );
 
975
                if ( $this->mType == 'signup' ) {
 
976
                        wfRunHooks( 'UserCreateForm', array( &$template ) );
 
977
                } else {
 
978
                        wfRunHooks( 'UserLoginForm', array( &$template ) );
 
979
                }
 
980
 
 
981
                $wgOut->setPageTitle( wfMsg( 'userlogin' ) );
 
982
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
 
983
                $wgOut->setArticleRelated( false );
 
984
                $wgOut->disallowUserJs();  // just in case...
 
985
                $wgOut->addTemplate( $template );
 
986
        }
 
987
 
 
988
        /**
 
989
         * @private
 
990
         */
 
991
        function showCreateOrLoginLink( &$user ) {
 
992
                if( $this->mType == 'signup' ) {
 
993
                        return( true );
 
994
                } elseif( $user->isAllowed( 'createaccount' ) ) {
 
995
                        return( true );
 
996
                } else {
 
997
                        return( false );
 
998
                }
 
999
        }
 
1000
 
 
1001
        /**
 
1002
         * Check if a session cookie is present.
 
1003
         *
 
1004
         * This will not pick up a cookie set during _this_ request, but is meant
 
1005
         * to ensure that the client is returning the cookie which was set on a
 
1006
         * previous pass through the system.
 
1007
         *
 
1008
         * @private
 
1009
         */
 
1010
        function hasSessionCookie() {
 
1011
                global $wgDisableCookieCheck, $wgRequest;
 
1012
                return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
 
1013
        }
 
1014
        
 
1015
        /**
 
1016
         * Get the login token from the current session
 
1017
         */
 
1018
        public static function getLoginToken() {
 
1019
                global $wgRequest;
 
1020
                return $wgRequest->getSessionData( 'wsLoginToken' );
 
1021
        }
 
1022
        
 
1023
        /**
 
1024
         * Randomly generate a new login token and attach it to the current session
 
1025
         */
 
1026
        public static function setLoginToken() {
 
1027
                global $wgRequest;
 
1028
                // Use User::generateToken() instead of $user->editToken()
 
1029
                // because the latter reuses $_SESSION['wsEditToken']
 
1030
                $wgRequest->setSessionData( 'wsLoginToken', User::generateToken() );
 
1031
        }
 
1032
        
 
1033
        /**
 
1034
         * Remove any login token attached to the current session
 
1035
         */
 
1036
        public static function clearLoginToken() {
 
1037
                global $wgRequest;
 
1038
                $wgRequest->setSessionData( 'wsLoginToken', null );
 
1039
        }
 
1040
 
 
1041
        /**
 
1042
         * Get the createaccount token from the current session
 
1043
         */
 
1044
        public static function getCreateaccountToken() {
 
1045
                global $wgRequest;
 
1046
                return $wgRequest->getSessionData( 'wsCreateaccountToken' );
 
1047
        }
 
1048
        
 
1049
        /**
 
1050
         * Randomly generate a new createaccount token and attach it to the current session
 
1051
         */
 
1052
        public static function setCreateaccountToken() {
 
1053
                global $wgRequest;
 
1054
                $wgRequest->setSessionData( 'wsCreateaccountToken', User::generateToken() );
 
1055
        }
 
1056
        
 
1057
        /**
 
1058
         * Remove any createaccount token attached to the current session
 
1059
         */
 
1060
        public static function clearCreateaccountToken() {
 
1061
                global $wgRequest;
 
1062
                $wgRequest->setSessionData( 'wsCreateaccountToken', null );
 
1063
        }
 
1064
 
 
1065
        /**
 
1066
         * @private
 
1067
         */
 
1068
        function cookieRedirectCheck( $type ) {
 
1069
                global $wgOut;
 
1070
 
 
1071
                $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
 
1072
                $query = array( 'wpCookieCheck' => $type );
 
1073
                if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
 
1074
                $check = $titleObj->getFullURL( $query );
 
1075
 
 
1076
                return $wgOut->redirect( $check );
 
1077
        }
 
1078
 
 
1079
        /**
 
1080
         * @private
 
1081
         */
 
1082
        function onCookieRedirectCheck( $type ) {
 
1083
                global $wgUser;
 
1084
 
 
1085
                if ( !$this->hasSessionCookie() ) {
 
1086
                        if ( $type == 'new' ) {
 
1087
                                return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
 
1088
                        } else if ( $type == 'login' ) {
 
1089
                                return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
 
1090
                        } else {
 
1091
                                # shouldn't happen
 
1092
                                return $this->mainLoginForm( wfMsg( 'error' ) );
 
1093
                        }
 
1094
                } else {
 
1095
                        return $this->successfulLogin();
 
1096
                }
 
1097
        }
 
1098
 
 
1099
        /**
 
1100
         * @private
 
1101
         */
 
1102
        function throttleHit( $limit ) {
 
1103
                $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
 
1104
        }
 
1105
 
 
1106
        /**
 
1107
         * Produce a bar of links which allow the user to select another language
 
1108
         * during login/registration but retain "returnto"
 
1109
         *
 
1110
         * @return string
 
1111
         */
 
1112
        function makeLanguageSelector() {
 
1113
                global $wgLang;
 
1114
 
 
1115
                $msg = wfMsgForContent( 'loginlanguagelinks' );
 
1116
                if( $msg != '' && !wfEmptyMsg( 'loginlanguagelinks', $msg ) ) {
 
1117
                        $langs = explode( "\n", $msg );
 
1118
                        $links = array();
 
1119
                        foreach( $langs as $lang ) {
 
1120
                                $lang = trim( $lang, '* ' );
 
1121
                                $parts = explode( '|', $lang );
 
1122
                                if (count($parts) >= 2) {
 
1123
                                        $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
 
1124
                                }
 
1125
                        }
 
1126
                        return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
 
1127
                } else {
 
1128
                        return '';
 
1129
                }
 
1130
        }
 
1131
 
 
1132
        /**
 
1133
         * Create a language selector link for a particular language
 
1134
         * Links back to this page preserving type and returnto
 
1135
         *
 
1136
         * @param $text Link text
 
1137
         * @param $lang Language code
 
1138
         */
 
1139
        function makeLanguageSelectorLink( $text, $lang ) {
 
1140
                global $wgUser;
 
1141
                $self = SpecialPage::getTitleFor( 'Userlogin' );
 
1142
                $attr[] = 'uselang=' . $lang;
 
1143
                if( $this->mType == 'signup' )
 
1144
                        $attr[] = 'type=signup';
 
1145
                if( $this->mReturnTo )
 
1146
                        $attr[] = 'returnto=' . $this->mReturnTo;
 
1147
                $skin = $wgUser->getSkin();
 
1148
                return $skin->makeKnownLinkObj( $self, htmlspecialchars( $text ), implode( '&', $attr ) );
 
1149
        }
 
1150
}