public function testTestUserCanAuthenticate() { $user = $this->getMutableTestUser()->getUser(); $userName = $user->getName(); $dbw = wfGetDB(DB_MASTER); $provider = $this->getProvider(); $this->assertFalse($provider->testUserCanAuthenticate('<invalid>')); $this->assertFalse($provider->testUserCanAuthenticate('DoesNotExist')); $this->assertTrue($provider->testUserCanAuthenticate($userName)); $lowerInitialUserName = mb_strtolower($userName[0]) . substr($userName, 1); $this->assertTrue($provider->testUserCanAuthenticate($lowerInitialUserName)); $dbw->update('user', ['user_password' => \PasswordFactory::newInvalidPassword()->toString()], ['user_name' => $userName]); $this->assertFalse($provider->testUserCanAuthenticate($userName)); // Really old format $dbw->update('user', ['user_password' => '0123456789abcdef0123456789abcdef'], ['user_name' => $userName]); $this->assertTrue($provider->testUserCanAuthenticate($userName)); }
/** * Check if the given clear-text password matches the temporary password * sent by e-mail for password reset operations. * * @deprecated since 1.27. AuthManager is coming. * @param string $plaintext * @return bool True if matches, false otherwise */ public function checkTemporaryPassword($plaintext) { global $wgNewPasswordExpiry; $this->load(); $passwordFactory = new PasswordFactory(); $passwordFactory->init(RequestContext::getMain()->getConfig()); $db = $this->queryFlagsUsed & self::READ_LATEST ? wfGetDB(DB_MASTER) : wfGetDB(DB_SLAVE); $row = $db->selectRow('user', array('user_newpassword', 'user_newpass_time'), array('user_id' => $this->getId()), __METHOD__); try { $newPassword = $passwordFactory->newFromCiphertext($row->user_newpassword); } catch (PasswordError $e) { wfDebug('Invalid password hash found in database.'); $newPassword = PasswordFactory::newInvalidPassword(); } if ($newPassword->equals($plaintext)) { if (is_null($row->user_newpass_time)) { return true; } $expiry = wfTimestamp(TS_UNIX, $row->user_newpass_time) + $wgNewPasswordExpiry; return time() < $expiry; } else { return false; } }
/** * Invalidate all passwords for a user, by central ID * @param int $centralId * @return bool Whether any passwords were invalidated */ public static function invalidateAllPasswordsForCentralId($centralId) { global $wgEnableBotPasswords; if (!$wgEnableBotPasswords) { return false; } $dbw = self::getDB(DB_MASTER); $dbw->update('bot_passwords', array('bp_password' => PasswordFactory::newInvalidPassword()->toString()), array('bp_user' => $centralId), __METHOD__); return (bool) $dbw->affectedRows(); }
public function testTestUserCanAuthenticate() { $dbw = wfGetDB(DB_MASTER); $passwordFactory = new \PasswordFactory(); $passwordFactory->init(\RequestContext::getMain()->getConfig()); // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only $passwordFactory->setDefaultType('A'); $pwhash = $passwordFactory->newFromPlaintext('password')->toString(); $provider = $this->getProvider(); $providerPriv = \TestingAccessWrapper::newFromObject($provider); $this->assertFalse($provider->testUserCanAuthenticate('<invalid>')); $this->assertFalse($provider->testUserCanAuthenticate('DoesNotExist')); $dbw->update('user', ['user_newpassword' => \PasswordFactory::newInvalidPassword()->toString(), 'user_newpass_time' => null], ['user_name' => 'UTSysop']); $this->assertFalse($provider->testUserCanAuthenticate('UTSysop')); $dbw->update('user', ['user_newpassword' => $pwhash, 'user_newpass_time' => null], ['user_name' => 'UTSysop']); $this->assertTrue($provider->testUserCanAuthenticate('UTSysop')); $this->assertTrue($provider->testUserCanAuthenticate('uTSysop')); $dbw->update('user', ['user_newpassword' => $pwhash, 'user_newpass_time' => $dbw->timestamp(time() - 10)], ['user_name' => 'UTSysop']); $providerPriv->newPasswordExpiry = 100; $this->assertTrue($provider->testUserCanAuthenticate('UTSysop')); $providerPriv->newPasswordExpiry = 1; $this->assertFalse($provider->testUserCanAuthenticate('UTSysop')); $dbw->update('user', ['user_newpassword' => \PasswordFactory::newInvalidPassword()->toString(), 'user_newpass_time' => null], ['user_name' => 'UTSysop']); }
/** * Add this existing user object to the database. If the user already * exists, a fatal status object is returned, and the user object is * initialised with the data from the database. * * Previously, this function generated a DB error due to a key conflict * if the user already existed. Many extension callers use this function * in code along the lines of: * * $user = User::newFromName( $name ); * if ( !$user->isLoggedIn() ) { * $user->addToDatabase(); * } * // do something with $user... * * However, this was vulnerable to a race condition (bug 16020). By * initialising the user object if the user exists, we aim to support this * calling sequence as far as possible. * * Note that if the user exists, this function will acquire a write lock, * so it is still advisable to make the call conditional on isLoggedIn(), * and to commit the transaction after calling. * * @throws MWException * @return Status */ public function addToDatabase() { $this->load(); if (!$this->mToken) { $this->setToken(); // init token } $this->mTouched = $this->newTouchedTimestamp(); $noPass = PasswordFactory::newInvalidPassword()->toString(); $dbw = wfGetDB(DB_MASTER); $seqVal = $dbw->nextSequenceValue('user_user_id_seq'); $dbw->insert('user', ['user_id' => $seqVal, 'user_name' => $this->mName, 'user_password' => $noPass, 'user_newpassword' => $noPass, 'user_email' => $this->mEmail, 'user_email_authenticated' => $dbw->timestampOrNull($this->mEmailAuthenticated), 'user_real_name' => $this->mRealName, 'user_token' => strval($this->mToken), 'user_registration' => $dbw->timestamp($this->mRegistration), 'user_editcount' => 0, 'user_touched' => $dbw->timestamp($this->mTouched)], __METHOD__, ['IGNORE']); if (!$dbw->affectedRows()) { // Use locking reads to bypass any REPEATABLE-READ snapshot. $this->mId = $dbw->selectField('user', 'user_id', ['user_name' => $this->mName], __METHOD__, ['LOCK IN SHARE MODE']); $loaded = false; if ($this->mId) { if ($this->loadFromDatabase(self::READ_LOCKING)) { $loaded = true; } } if (!$loaded) { throw new MWException(__METHOD__ . ": hit a key conflict attempting " . "to insert user '{$this->mName}' row, but it was not present in select!"); } return Status::newFatal('userexists'); } $this->mId = $dbw->insertId(); self::$idCacheByName[$this->mName] = $this->mId; // Clear instance cache other than user table data, which is already accurate $this->clearInstanceCache(); $this->saveOptions(); return Status::newGood(); }