- /**
- * Internally authenticate the login request.
- *
- * This may create a local account as a side effect if the
- * authentication plugin allows transparent local account
- * creation.
- */
- public function authenticateUserData() {
- global $wgUser, $wgAuth, $wgMemc;
-
- if ( $this->mName == '' ) {
- return self::NO_NAME;
- }
-
- // We require a login token to prevent login CSRF
- // Handle part of this before incrementing the throttle so
- // token-less login attempts don't count towards the throttle
- // but wrong-token attempts do.
-
- // If the user doesn't have a login token yet, set one.
- if ( !self::getLoginToken() ) {
- self::setLoginToken();
- return self::NEED_TOKEN;
- }
- // If the user didn't pass a login token, tell them we need one
- if ( !$this->mToken ) {
- return self::NEED_TOKEN;
- }
-
- global $wgPasswordAttemptThrottle;
-
- $throttleCount = 0;
- if ( is_array( $wgPasswordAttemptThrottle ) ) {
- $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
- $count = $wgPasswordAttemptThrottle['count'];
- $period = $wgPasswordAttemptThrottle['seconds'];
-
- $throttleCount = $wgMemc->get( $throttleKey );
- if ( !$throttleCount ) {
- $wgMemc->add( $throttleKey, 1, $period ); // start counter
- } elseif ( $throttleCount < $count ) {
- $wgMemc->incr( $throttleKey );
- } elseif ( $throttleCount >= $count ) {
- return self::THROTTLED;
- }
- }
-
- // Validate the login token
- if ( $this->mToken !== self::getLoginToken() ) {
- return self::WRONG_TOKEN;
- }
-
- // Load $wgUser now, and check to see if we're logging in as the same
- // name. This is necessary because loading $wgUser (say by calling
- // getName()) calls the UserLoadFromSession hook, which potentially
- // creates the user in the database. Until we load $wgUser, checking
- // for user existence using User::newFromName($name)->getId() below
- // will effectively be using stale data.
- if ( $wgUser->getName() === $this->mName ) {
- wfDebug( __METHOD__ . ": already logged in as {$this->mName}\n" );
- return self::SUCCESS;
- }
-
- $this->mExtUser = ExternalUser::newFromName( $this->mName );
-
- # TODO: Allow some magic here for invalid external names, e.g., let the
- # user choose a different wiki name.
- $u = User::newFromName( $this->mName );
- if( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) {
- return self::ILLEGAL;
- }
-
- $isAutoCreated = false;
- if ( 0 == $u->getID() ) {
- $status = $this->attemptAutoCreate( $u );
- if ( $status !== self::SUCCESS ) {
- return $status;
- } else {
- $isAutoCreated = true;
- }
- } else {
- global $wgExternalAuthType, $wgAutocreatePolicy;
- if ( $wgExternalAuthType && $wgAutocreatePolicy != 'never'
- && is_object( $this->mExtUser )
- && $this->mExtUser->authenticate( $this->mPassword ) ) {
- # The external user and local user have the same name and
- # password, so we assume they're the same.
- $this->mExtUser->linkToLocal( $u->getID() );
- }
-
- $u->load();
- }
-
- // Give general extensions, such as a captcha, a chance to abort logins
- $abort = self::ABORTED;
- if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
- return $abort;
- }
-
- global $wgBlockDisablesLogin;
- if ( !$u->checkPassword( $this->mPassword ) ) {
- if( $u->checkTemporaryPassword( $this->mPassword ) ) {
- // The e-mailed temporary password should not be used for actu-
- // al logins; that's a very sloppy habit, and insecure if an
- // attacker has a few seconds to click "search" on someone's o-
- // pen mail reader.
- //
- // Allow it to be used only to reset the password a single time
- // to a new value, which won't be in the user's e-mail ar-
- // chives.
- //
- // For backwards compatibility, we'll still recognize it at the
- // login form to minimize surprises for people who have been
- // logging in with a temporary password for some time.
- //
- // As a side-effect, we can authenticate the user's e-mail ad-
- // dress if it's not already done, since the temporary password
- // was sent via e-mail.
- if( !$u->isEmailConfirmed() ) {
- $u->confirmEmail();
- $u->saveSettings();
- }
-
- // At this point we just return an appropriate code/ indicating
- // that the UI should show a password reset form; bot inter-
- // faces etc will probably just fail cleanly here.
- $retval = self::RESET_PASS;
- } else {
- $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
- }
- } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
- // If we've enabled it, make it so that a blocked user cannot login
- $retval = self::USER_BLOCKED;
- } else {
- $wgAuth->updateUser( $u );
- $wgUser = $u;
-
- // Please reset throttle for successful logins, thanks!
- if( $throttleCount ) {
- $wgMemc->delete( $throttleKey );
- }
-
- if ( $isAutoCreated ) {
- // Must be run after $wgUser is set, for correct new user log
- wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
- }
-
- $retval = self::SUCCESS;
- }
- wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
- return $retval;