public function testAbstractPrimaryAuthenticationProvider() { $user = \User::newFromName('UTSysop'); $provider = $this->getMockForAbstractClass(AbstractPrimaryAuthenticationProvider::class); try { $provider->continuePrimaryAuthentication([]); $this->fail('Expected exception not thrown'); } catch (\BadMethodCallException $ex) { } try { $provider->continuePrimaryAccountCreation($user, $user, []); $this->fail('Expected exception not thrown'); } catch (\BadMethodCallException $ex) { } $req = $this->getMockForAbstractClass(AuthenticationRequest::class); $this->assertTrue($provider->providerAllowsPropertyChange('foo')); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, [])); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, AuthManager::AUTOCREATE_SOURCE_SESSION)); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, false)); $this->assertNull($provider->finishAccountCreation($user, $user, AuthenticationResponse::newPass())); $provider->autoCreatedAccount($user, AuthManager::AUTOCREATE_SOURCE_SESSION); $res = AuthenticationResponse::newPass(); $provider->postAuthentication($user, $res); $provider->postAccountCreation($user, $user, $res); $provider->postAccountLink($user, $res); $provider->expects($this->once())->method('testUserExists')->with($this->equalTo('foo'))->will($this->returnValue(true)); $this->assertTrue($provider->testUserCanAuthenticate('foo')); }
protected function doPrecheck(array &$predicates) { $status = StatusValue::newGood(); // Check if the source file exists if (!$this->fileExists($this->params['src'], $predicates)) { if ($this->getParam('ignoreMissingSource')) { $this->doOperation = false; // no-op // Update file existence predicates (cache 404s) $predicates['exists'][$this->params['src']] = false; $predicates['sha1'][$this->params['src']] = false; return $status; // nothing to do } else { $status->fatal('backend-fail-notexists', $this->params['src']); return $status; } // Check if a file can be placed/changed at the source } elseif (!$this->backend->isPathUsableInternal($this->params['src'])) { $status->fatal('backend-fail-usable', $this->params['src']); $status->fatal('backend-fail-delete', $this->params['src']); return $status; } // Update file existence predicates $predicates['exists'][$this->params['src']] = false; $predicates['sha1'][$this->params['src']] = false; return $status; // safe to call attempt() }
public function testAbstractSecondaryAuthenticationProvider() { $user = \User::newFromName('UTSysop'); $provider = $this->getMockForAbstractClass(AbstractSecondaryAuthenticationProvider::class); try { $provider->continueSecondaryAuthentication($user, []); $this->fail('Expected exception not thrown'); } catch (\BadMethodCallException $ex) { } try { $provider->continueSecondaryAccountCreation($user, $user, []); $this->fail('Expected exception not thrown'); } catch (\BadMethodCallException $ex) { } $req = $this->getMockForAbstractClass(AuthenticationRequest::class); $this->assertTrue($provider->providerAllowsPropertyChange('foo')); $this->assertEquals(\StatusValue::newGood('ignored'), $provider->providerAllowsAuthenticationDataChange($req)); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, [])); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, AuthManager::AUTOCREATE_SOURCE_SESSION)); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, false)); $provider->providerChangeAuthenticationData($req); $provider->autoCreatedAccount($user, AuthManager::AUTOCREATE_SOURCE_SESSION); $res = AuthenticationResponse::newPass(); $provider->postAuthentication($user, $res); $provider->postAccountCreation($user, $user, $res); }
public function execute($subPage) { $this->setHeaders(); $this->loadAuth($subPage); $this->outputHeader(); $status = $this->trySubmit(); if ($status === false || !$status->isOK()) { $this->displayForm($status); return; } /** @var AuthenticationResponse $response */ $response = $status->getValue(); if ($response->status === AuthenticationResponse::FAIL) { $this->displayForm(StatusValue::newFatal($response->message)); return; } $status = StatusValue::newGood(); $status->warning(wfMessage('unlinkaccounts-success')); $this->loadAuth($subPage, null, true); // update requests so the unlinked one doesn't show up // Reset sessions - if the user unlinked an account because it was compromised, // log attackers out from sessions obtained via that account. $session = $this->getRequest()->getSession(); $user = $this->getUser(); SessionManager::singleton()->invalidateSessionsForUser($user); $session->setUser($user); $session->resetId(); $this->displayForm($status); }
protected function doAttempt() { if (!$this->overwriteSameCase) { // Create the file at the destination return $this->backend->createInternal($this->setFlags($this->params)); } return StatusValue::newGood(); }
/** * Release the locks when this goes out of scope */ function __destruct() { $wasOk = $this->status->isOK(); $this->status->merge($this->manager->unlockByType($this->pathsByType)); if ($wasOk) { // Make sure StatusValue is OK, despite any unlockFiles() fatals $this->status->setResult(true, $this->status->value); } }
public function testDisabled() { $provider = new ThrottlePreAuthenticationProvider(['accountCreationThrottle' => [], 'passwordAttemptThrottle' => [], 'cache' => new \HashBagOStuff()]); $provider->setLogger(new \Psr\Log\NullLogger()); $provider->setConfig(new \HashConfig(['AccountCreationThrottle' => null, 'PasswordAttemptThrottle' => null])); $provider->setManager(AuthManager::singleton()); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation(\User::newFromName('Created'), \User::newFromName('Creator'), [])); $this->assertEquals(\StatusValue::newGood(), $provider->testForAuthentication([])); }
/** * @see QuorumLockManager::releaseAllLocks() * @return StatusValue */ protected function releaseAllLocks() { $status = StatusValue::newGood(); foreach ($this->conns as $lockDb => $db) { try { $db->query("SELECT pg_advisory_unlock_all()", __METHOD__); } catch (DBError $e) { $status->fatal('lockmanager-fail-db-release', $lockDb); } } return $status; }
protected function doAttempt() { if ($this->overwriteSameCase) { $status = StatusValue::newGood(); // nothing to do } elseif ($this->params['src'] === $this->params['dst']) { // Just update the destination file headers $headers = $this->getParam('headers') ?: []; $status = $this->backend->describeInternal($this->setFlags(['src' => $this->params['dst'], 'headers' => $headers])); } else { // Copy the file to the destination $status = $this->backend->copyInternal($this->setFlags($this->params)); } return $status; }
public function testAbstractPreAuthenticationProvider() { $user = \User::newFromName('UTSysop'); $provider = $this->getMockForAbstractClass(AbstractPreAuthenticationProvider::class); $this->assertEquals([], $provider->getAuthenticationRequests(AuthManager::ACTION_LOGIN, [])); $this->assertEquals(\StatusValue::newGood(), $provider->testForAuthentication([])); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, [])); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, AuthManager::AUTOCREATE_SOURCE_SESSION)); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, false)); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountLink($user)); $res = AuthenticationResponse::newPass(); $provider->postAuthentication($user, $res); $provider->postAccountCreation($user, $user, $res); $provider->postAccountLink($user, $res); }
/** * @dataProvider provideTestForAccountCreation * @param string $creatorname * @param bool $succeed * @param bool $hook */ public function testTestForAccountCreation($creatorname, $succeed, $hook) { $provider = new ThrottlePreAuthenticationProvider(['accountCreationThrottle' => [['count' => 2, 'seconds' => 86400]], 'cache' => new \HashBagOStuff()]); $provider->setLogger(new \Psr\Log\NullLogger()); $provider->setConfig(new \HashConfig(['AccountCreationThrottle' => null, 'PasswordAttemptThrottle' => null])); $provider->setManager(AuthManager::singleton()); $user = \User::newFromName('RandomUser'); $creator = \User::newFromName($creatorname); if ($hook) { $mock = $this->getMock('stdClass', ['onExemptFromAccountCreationThrottle']); $mock->expects($this->any())->method('onExemptFromAccountCreationThrottle')->will($this->returnValue(false)); $this->mergeMwGlobalArrayValue('wgHooks', ['ExemptFromAccountCreationThrottle' => [$mock]]); } $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $creator, []), 'attempt #1'); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $creator, []), 'attempt #2'); $this->assertEquals($succeed ? \StatusValue::newGood() : \StatusValue::newFatal('acct_creation_throttle_hit', 2), $provider->testForAccountCreation($user, $creator, []), 'attempt #3'); }
protected function doPrecheck(array &$predicates) { $status = StatusValue::newGood(); // Check if the source file exists if (!$this->fileExists($this->params['src'], $predicates)) { $status->fatal('backend-fail-notexists', $this->params['src']); return $status; // Check if a file can be placed/changed at the source } elseif (!$this->backend->isPathUsableInternal($this->params['src'])) { $status->fatal('backend-fail-usable', $this->params['src']); $status->fatal('backend-fail-describe', $this->params['src']); return $status; } // Update file existence predicates $predicates['exists'][$this->params['src']] = $this->fileExists($this->params['src'], $predicates); $predicates['sha1'][$this->params['src']] = $this->fileSha1($this->params['src'], $predicates); return $status; // safe to call attempt() }
public function testTestUserForCreation() { $provider = new CheckBlocksSecondaryAuthenticationProvider(['blockDisablesLogin' => false]); $provider->setLogger(new \Psr\Log\NullLogger()); $provider->setConfig(new \HashConfig()); $provider->setManager(AuthManager::singleton()); $unblockedUser = \User::newFromName('UTSysop'); $blockedUser = $this->getBlockedUser(); $user = \User::newFromName('RandomUser'); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($unblockedUser, AuthManager::AUTOCREATE_SOURCE_SESSION)); $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($unblockedUser, false)); $status = $provider->testUserForCreation($blockedUser, AuthManager::AUTOCREATE_SOURCE_SESSION); $this->assertInstanceOf('StatusValue', $status); $this->assertFalse($status->isOK()); $this->assertTrue($status->hasMessage('cantcreateaccount-text')); $status = $provider->testUserForCreation($blockedUser, false); $this->assertInstanceOf('StatusValue', $status); $this->assertFalse($status->isOK()); $this->assertTrue($status->hasMessage('cantcreateaccount-text')); }
protected function doAttempt() { if ($this->overwriteSameCase) { if ($this->params['src'] === $this->params['dst']) { // Do nothing to the destination (which is also the source) $status = StatusValue::newGood(); } else { // Just delete the source as the destination file needs no changes $status = $this->backend->deleteInternal($this->setFlags(['src' => $this->params['src']])); } } elseif ($this->params['src'] === $this->params['dst']) { // Just update the destination file headers $headers = $this->getParam('headers') ?: []; $status = $this->backend->describeInternal($this->setFlags(['src' => $this->params['dst'], 'headers' => $headers])); } else { // Move the file to the destination $status = $this->backend->moveInternal($this->setFlags($this->params)); } return $status; }
public function testTestForAccountCreation() { $user = \User::newFromName('foo'); $req = new PasswordAuthenticationRequest(); $req->action = AuthManager::ACTION_CREATE; $req->username = '******'; $req->password = '******'; $req->retype = 'Bar'; $reqs = [PasswordAuthenticationRequest::class => $req]; $provider = $this->getProvider(); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, []), 'No password request'); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, $reqs), 'Password request, validated'); $req->retype = 'Baz'; $this->assertEquals(\StatusValue::newFatal('badretype'), $provider->testForAccountCreation($user, $user, $reqs), 'Password request, bad retype'); $req->retype = 'Bar'; $this->validity->error('arbitrary warning'); $expect = \StatusValue::newGood(); $expect->error('arbitrary warning'); $this->assertEquals($expect, $provider->testForAccountCreation($user, $user, $reqs), 'Password request, not validated'); $provider = $this->getProvider(true); $this->validity->error('arbitrary warning'); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, $reqs), 'Password request, not validated, loginOnly'); }
/** * Splits this Status object into two new Status objects, one which contains only * the error messages, and one that contains the warnings, only. The returned array is * defined as: * [ * 0 => object(Status) # the Status with error messages, only * 1 => object(Status) # The Status with warning messages, only * ] * * @return Status[] */ public function splitByErrorType() { list($errorsOnlyStatus, $warningsOnlyStatus) = parent::splitByErrorType(); $errorsOnlyStatus->cleanCallback = $warningsOnlyStatus->cleanCallback = $this->cleanCallback; return [$errorsOnlyStatus, $warningsOnlyStatus]; }
public function testForAccountCreation($user, $creator, array $reqs) { /** @var TemporaryPasswordAuthenticationRequest $req */ $req = AuthenticationRequest::getRequestByClass($reqs, TemporaryPasswordAuthenticationRequest::class); $ret = \StatusValue::newGood(); if ($req) { if ($req->mailpassword && !$req->hasBackchannel) { if (!$this->emailEnabled) { $ret->merge(\StatusValue::newFatal('emaildisabled')); } elseif (!$user->getEmail()) { $ret->merge(\StatusValue::newFatal('noemailcreate')); } } $ret->merge($this->checkPasswordValidity($user->getName(), $req->password)); } return $ret; }
/** * Attempt a list of file operations sub-batches in series. * * The operations *in* each sub-batch will be done in parallel. * The caller is responsible for making sure the operations * within any given sub-batch do not depend on each other. * This will abort remaining ops on failure. * * @param array $pPerformOps Batches of file ops (batches use original indexes) * @param StatusValue $status */ protected static function runParallelBatches(array $pPerformOps, StatusValue $status) { $aborted = false; // set to true on unexpected errors foreach ($pPerformOps as $performOpsBatch) { /** @var FileOp[] $performOpsBatch */ if ($aborted) { // check batch op abort flag... // We can't continue (even with $ignoreErrors) as $predicates is wrong. // Log the remaining ops as failed for recovery... foreach ($performOpsBatch as $i => $fileOp) { $status->success[$i] = false; ++$status->failCount; $performOpsBatch[$i]->logFailure('attempt_aborted'); } continue; } /** @var StatusValue[] $statuses */ $statuses = []; $opHandles = []; // Get the backend; all sub-batch ops belong to a single backend /** @var FileBackendStore $backend */ $backend = reset($performOpsBatch)->getBackend(); // Get the operation handles or actually do it if there is just one. // If attemptAsync() returns a StatusValue, it was either due to an error // or the backend does not support async ops and did it synchronously. foreach ($performOpsBatch as $i => $fileOp) { if (!isset($status->success[$i])) { // didn't already fail in precheck() // Parallel ops may be disabled in config due to missing dependencies, // (e.g. needing popen()). When they are, $performOpsBatch has size 1. $subStatus = count($performOpsBatch) > 1 ? $fileOp->attemptAsync() : $fileOp->attempt(); if ($subStatus->value instanceof FileBackendStoreOpHandle) { $opHandles[$i] = $subStatus->value; // deferred } else { $statuses[$i] = $subStatus; // done already } } } // Try to do all the operations concurrently... $statuses = $statuses + $backend->executeOpHandlesInternal($opHandles); // Marshall and merge all the responses (blocking)... foreach ($performOpsBatch as $i => $fileOp) { if (!isset($status->success[$i])) { // didn't already fail in precheck() $subStatus = $statuses[$i]; $status->merge($subStatus); if ($subStatus->isOK()) { $status->success[$i] = true; ++$status->successCount; } else { $status->success[$i] = false; ++$status->failCount; $aborted = true; // set abort flag; we can't continue } } } } }
public function testTestForAccountCreation() { $user = \User::newFromName('foo'); $plugin = $this->getMock('AuthPlugin'); $plugin->expects($this->any())->method('domainList')->willReturn([]); $provider = new AuthPluginPrimaryAuthenticationProvider($plugin); $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, [])); }
/** * @see FileJournal::doPurgeOldLogs() * @return StatusValue */ protected function doPurgeOldLogs() { return StatusValue::newGood(); }
public function testForAccountCreation($user, $creator, array $reqs) { $req = AuthenticationRequest::getRequestByClass($reqs, PasswordAuthenticationRequest::class); $ret = \StatusValue::newGood(); if (!$this->loginOnly && $req && $req->username !== null && $req->password !== null) { if ($req->password !== $req->retype) { $ret->fatal('badretype'); } else { $ret->merge($this->checkPasswordValidity($user->getName(), $req->password)); } } return $ret; }
/** * @dataProvider provideTestUserForCreation * @param string|null $error * @param string|null $failMsg */ public function testTestUserForCreation($error, $failMsg) { $this->hook('AbortNewAccount', $this->never()); $this->hook('AbortAutoAccount', $this->once())->will($this->returnCallback(function ($user, &$abortError) use($error) { $this->assertInstanceOf('User', $user); $this->assertSame('UTSysop', $user->getName()); $abortError = $error; return $error === null; })); $status = $this->getProvider()->testUserForCreation(\User::newFromName('UTSysop'), AuthManager::AUTOCREATE_SOURCE_SESSION); $this->unhook('AbortNewAccount'); $this->unhook('AbortAutoAccount'); if ($failMsg === null) { $this->assertEquals(\StatusValue::newGood(), $status, 'should succeed'); } else { $this->assertInstanceOf('StatusValue', $status, 'should fail (type)'); $this->assertFalse($status->isOk(), 'should fail (ok)'); $errors = $status->getErrors(); $this->assertEquals($failMsg, $errors[0]['message'], 'should fail (message)'); } $this->hook('AbortAutoAccount', $this->never()); $this->hook('AbortNewAccount', $this->once())->will($this->returnCallback(function ($user, &$abortError, &$abortStatus) use($error) { $this->assertInstanceOf('User', $user); $this->assertSame('UTSysop', $user->getName()); $abortError = $error; return $error === null; })); $status = $this->getProvider()->testUserForCreation(\User::newFromName('UTSysop'), false); $this->unhook('AbortNewAccount'); $this->unhook('AbortAutoAccount'); if ($failMsg === null) { $this->assertEquals(\StatusValue::newGood(), $status, 'should succeed'); } else { $this->assertInstanceOf('StatusValue', $status, 'should fail (type)'); $this->assertFalse($status->isOk(), 'should fail (ok)'); $errors = $status->getErrors(); $msg = $errors[0]['message']; $this->assertInstanceOf(\Message::class, $msg); $this->assertEquals('createaccount-hook-aborted', $msg->getKey(), 'should fail (message)'); } if ($error !== false) { $this->hook('AbortAutoAccount', $this->never()); $this->hook('AbortNewAccount', $this->once())->will($this->returnCallback(function ($user, &$abortError, &$abortStatus) use($error) { $this->assertInstanceOf('User', $user); $this->assertSame('UTSysop', $user->getName()); $abortStatus = $error ? \Status::newFatal($error) : \Status::newGood(); return $error === null; })); $status = $this->getProvider()->testUserForCreation(\User::newFromName('UTSysop'), false); $this->unhook('AbortNewAccount'); $this->unhook('AbortAutoAccount'); if ($failMsg === null) { $this->assertEquals(\StatusValue::newGood(), $status, 'should succeed'); } else { $this->assertInstanceOf('StatusValue', $status, 'should fail (type)'); $this->assertFalse($status->isOk(), 'should fail (ok)'); $errors = $status->getErrors(); $this->assertEquals($failMsg, $errors[0]['message'], 'should fail (message)'); } } }
public function testContinueLinkAttempt() { $user = \User::newFromName('UTSysop'); $obj = new \stdClass(); $reqs = $this->getLinkRequests(); $done = [false, false, false]; // First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest $mock = $this->getMockBuilder(ConfirmLinkSecondaryAuthenticationProvider::class)->setMethods(['beginLinkAttempt'])->getMock(); $mock->expects($this->once())->method('beginLinkAttempt')->with($this->identicalTo($user), $this->identicalTo('state'))->will($this->returnValue($obj)); $this->assertSame($obj, \TestingAccessWrapper::newFromObject($mock)->continueLinkAttempt($user, 'state', $reqs)); // Now test the actual functioning $provider = $this->getMockBuilder(ConfirmLinkSecondaryAuthenticationProvider::class)->setMethods(['beginLinkAttempt', 'providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'])->getMock(); $provider->expects($this->never())->method('beginLinkAttempt'); $provider->expects($this->any())->method('providerAllowsAuthenticationDataChange')->will($this->returnCallback(function ($req) use($reqs) { return $req->getUniqueId() === 'Request3' ? \StatusValue::newFatal('foo') : \StatusValue::newGood(); })); $provider->expects($this->any())->method('providerChangeAuthenticationData')->will($this->returnCallback(function ($req) use(&$done) { $done[$req->id] = true; })); $config = new \HashConfig(['AuthManagerConfig' => ['preauth' => [], 'primaryauth' => [], 'secondaryauth' => [['factory' => function () use($provider) { return $provider; }]]]]); $request = new \FauxRequest(); $manager = new AuthManager($request, $config); $provider->setManager($manager); $provider = \TestingAccessWrapper::newFromObject($provider); $req = new ConfirmLinkAuthenticationRequest($reqs); $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->continueLinkAttempt($user, 'state', [$req])); $request->getSession()->setSecret('state', ['maybeLink' => []]); $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->continueLinkAttempt($user, 'state', [$req])); $request->getSession()->setSecret('state', ['maybeLink' => $reqs]); $this->assertEquals(AuthenticationResponse::newPass(), $res = $provider->continueLinkAttempt($user, 'state', [$req])); $this->assertSame([false, false, false], $done); $request->getSession()->setSecret('state', ['maybeLink' => [$reqs['Request2']]]); $req->confirmedLinkIDs = ['Request1', 'Request2']; $res = $provider->continueLinkAttempt($user, 'state', [$req]); $this->assertEquals(AuthenticationResponse::newPass(), $res); $this->assertSame([false, true, false], $done); $done = [false, false, false]; $request->getSession()->setSecret('state', ['maybeLink' => $reqs]); $req->confirmedLinkIDs = ['Request1', 'Request2']; $res = $provider->continueLinkAttempt($user, 'state', [$req]); $this->assertEquals(AuthenticationResponse::newPass(), $res); $this->assertSame([true, true, false], $done); $done = [false, false, false]; $request->getSession()->setSecret('state', ['maybeLink' => $reqs]); $req->confirmedLinkIDs = ['Request1', 'Request3']; $res = $provider->continueLinkAttempt($user, 'state', [$req]); $this->assertEquals(AuthenticationResponse::UI, $res->status); $this->assertCount(1, $res->neededRequests); $this->assertInstanceOf(ButtonAuthenticationRequest::class, $res->neededRequests[0]); $this->assertSame([true, false, false], $done); $done = [false, false, false]; $res = $provider->continueLinkAttempt($user, 'state', [$res->neededRequests[0]]); $this->assertEquals(AuthenticationResponse::newPass(), $res); $this->assertSame([false, false, false], $done); }
protected function freeLocksOnServer($lockSrv, array $pathsByType) { return StatusValue::newGood(); }
/** * @return string */ public function __toString() { return $this->sv->__toString(); }
/** * Check for errors with regards to the destination file already existing. * Also set the destExists, overwriteSameCase and sourceSha1 member variables. * A bad StatusValue will be returned if there is no chance it can be overwritten. * * @param array $predicates * @return StatusValue */ protected function precheckDestExistence(array $predicates) { $status = StatusValue::newGood(); // Get hash of source file/string and the destination file $this->sourceSha1 = $this->getSourceSha1Base36(); // FS file or data string if ($this->sourceSha1 === null) { // file in storage? $this->sourceSha1 = $this->fileSha1($this->params['src'], $predicates); } $this->overwriteSameCase = false; $this->destExists = $this->fileExists($this->params['dst'], $predicates); if ($this->destExists) { if ($this->getParam('overwrite')) { return $status; // OK } elseif ($this->getParam('overwriteSame')) { $dhash = $this->fileSha1($this->params['dst'], $predicates); // Check if hashes are valid and match each other... if (!strlen($this->sourceSha1) || !strlen($dhash)) { $status->fatal('backend-fail-hashes'); } elseif ($this->sourceSha1 !== $dhash) { // Give an error if the files are not identical $status->fatal('backend-fail-notsame', $this->params['dst']); } else { $this->overwriteSameCase = true; // OK } return $status; // do nothing; either OK or bad status } else { $status->fatal('backend-fail-alreadyexists', $this->params['dst']); return $status; } } return $status; }
public function testContinueAccountCreation() { $creator = \User::newFromName('UTSysop'); $username = self::usernameForCreation(); $this->logger = new \TestLogger(false, function ($message, $level) { return $level === LogLevel::DEBUG ? null : $message; }); $this->initializeManager(); $session = ['userid' => 0, 'username' => $username, 'creatorid' => 0, 'creatorname' => $username, 'reqs' => [], 'primary' => null, 'primaryResponse' => null, 'secondary' => [], 'ranPreTests' => true]; $this->hook('LocalUserCreated', $this->never()); try { $this->manager->continueAccountCreation([]); $this->fail('Expected exception not thrown'); } catch (\LogicException $ex) { $this->assertEquals('Account creation is not possible', $ex->getMessage()); } $this->unhook('LocalUserCreated'); $mock = $this->getMockForAbstractClass(PrimaryAuthenticationProvider::class); $mock->expects($this->any())->method('getUniqueId')->will($this->returnValue('X')); $mock->expects($this->any())->method('accountCreationType')->will($this->returnValue(PrimaryAuthenticationProvider::TYPE_CREATE)); $mock->expects($this->any())->method('testUserExists')->will($this->returnValue(false)); $mock->expects($this->any())->method('beginPrimaryAccountCreation')->will($this->returnValue(AuthenticationResponse::newFail($this->message('fail')))); $this->primaryauthMocks = [$mock]; $this->initializeManager(true); $this->request->getSession()->setSecret('AuthManager::accountCreationState', null); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->continueAccountCreation([]); $this->unhook('LocalUserCreated'); $this->assertSame(AuthenticationResponse::FAIL, $ret->status); $this->assertSame('authmanager-create-not-in-progress', $ret->message->getKey()); $this->request->getSession()->setSecret('AuthManager::accountCreationState', ['username' => "{$username}<>"] + $session); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->continueAccountCreation([]); $this->unhook('LocalUserCreated'); $this->assertSame(AuthenticationResponse::FAIL, $ret->status); $this->assertSame('noname', $ret->message->getKey()); $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState')); $this->request->getSession()->setSecret('AuthManager::accountCreationState', $session); $this->hook('LocalUserCreated', $this->never()); $cache = \ObjectCache::getLocalClusterInstance(); $lock = $cache->getScopedLock($cache->makeGlobalKey('account', md5($username))); $ret = $this->manager->continueAccountCreation([]); unset($lock); $this->unhook('LocalUserCreated'); $this->assertSame(AuthenticationResponse::FAIL, $ret->status); $this->assertSame('usernameinprogress', $ret->message->getKey()); // This error shouldn't remove the existing session, because the // raced-with process "owns" it. $this->assertSame($session, $this->request->getSession()->getSecret('AuthManager::accountCreationState')); $this->request->getSession()->setSecret('AuthManager::accountCreationState', ['username' => $creator->getName()] + $session); $this->setMwGlobals(['wgReadOnly' => 'Because']); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->continueAccountCreation([]); $this->unhook('LocalUserCreated'); $this->assertSame(AuthenticationResponse::FAIL, $ret->status); $this->assertSame('readonlytext', $ret->message->getKey()); $this->assertSame(['Because'], $ret->message->getParams()); $this->setMwGlobals(['wgReadOnly' => false]); $this->request->getSession()->setSecret('AuthManager::accountCreationState', ['username' => $creator->getName()] + $session); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->continueAccountCreation([]); $this->unhook('LocalUserCreated'); $this->assertSame(AuthenticationResponse::FAIL, $ret->status); $this->assertSame('userexists', $ret->message->getKey()); $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState')); $this->request->getSession()->setSecret('AuthManager::accountCreationState', ['userid' => $creator->getId()] + $session); $this->hook('LocalUserCreated', $this->never()); try { $ret = $this->manager->continueAccountCreation([]); $this->fail('Expected exception not thrown'); } catch (\UnexpectedValueException $ex) { $this->assertEquals("User \"{$username}\" should exist now, but doesn't!", $ex->getMessage()); } $this->unhook('LocalUserCreated'); $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState')); $id = $creator->getId(); $name = $creator->getName(); $this->request->getSession()->setSecret('AuthManager::accountCreationState', ['username' => $name, 'userid' => $id + 1] + $session); $this->hook('LocalUserCreated', $this->never()); try { $ret = $this->manager->continueAccountCreation([]); $this->fail('Expected exception not thrown'); } catch (\UnexpectedValueException $ex) { $this->assertEquals("User \"{$name}\" exists, but ID {$id} != " . ($id + 1) . '!', $ex->getMessage()); } $this->unhook('LocalUserCreated'); $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState')); $req = $this->getMockBuilder(UserDataAuthenticationRequest::class)->setMethods(['populateUser'])->getMock(); $req->expects($this->any())->method('populateUser')->willReturn(\StatusValue::newFatal('populatefail')); $this->request->getSession()->setSecret('AuthManager::accountCreationState', ['reqs' => [$req]] + $session); $ret = $this->manager->continueAccountCreation([]); $this->assertSame(AuthenticationResponse::FAIL, $ret->status); $this->assertSame('populatefail', $ret->message->getKey()); $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState')); }
public function testAccountCreationEmail() { $creator = \User::newFromName('Foo'); $user = \User::newFromName('UTSysop'); $reset = new \ScopedCallback(function ($email) use($user) { $user->setEmail($email); $user->saveSettings(); }, [$user->getEmail()]); $user->setEmail(null); $req = TemporaryPasswordAuthenticationRequest::newRandom(); $req->username = $user->getName(); $req->mailpassword = true; $provider = $this->getProvider(['emailEnabled' => false]); $status = $provider->testForAccountCreation($user, $creator, [$req]); $this->assertEquals(\StatusValue::newFatal('emaildisabled'), $status); $req->hasBackchannel = true; $status = $provider->testForAccountCreation($user, $creator, [$req]); $this->assertFalse($status->hasMessage('emaildisabled')); $req->hasBackchannel = false; $provider = $this->getProvider(['emailEnabled' => true]); $status = $provider->testForAccountCreation($user, $creator, [$req]); $this->assertEquals(\StatusValue::newFatal('noemailcreate'), $status); $req->hasBackchannel = true; $status = $provider->testForAccountCreation($user, $creator, [$req]); $this->assertFalse($status->hasMessage('noemailcreate')); $req->hasBackchannel = false; $user->setEmail('*****@*****.**'); $status = $provider->testForAccountCreation($user, $creator, [$req]); $this->assertEquals(\StatusValue::newGood(), $status); $mailed = false; $resetMailer = $this->hookMailer(function ($headers, $to, $from, $subject, $body) use(&$mailed, $req) { $mailed = true; $this->assertSame('*****@*****.**', $to[0]->address); $this->assertContains($req->password, $body); return false; }); $expect = AuthenticationResponse::newPass('UTSysop'); $expect->createRequest = clone $req; $expect->createRequest->username = '******'; $res = $provider->beginPrimaryAccountCreation($user, $creator, [$req]); $this->assertEquals($expect, $res); $this->assertTrue($this->manager->getAuthenticationSessionData('no-email')); $this->assertFalse($mailed); $this->assertSame('byemail', $provider->finishAccountCreation($user, $creator, $res)); $this->assertTrue($mailed); \ScopedCallback::consume($resetMailer); $this->assertTrue($mailed); }
/** * Log changes made by a batch file operation. * * @param array $entries List of file operations (each an array of parameters) which contain: * op : Basic operation name (create, update, delete) * path : The storage path of the file * newSha1 : The final base 36 SHA-1 of the file * Note that 'false' should be used as the SHA-1 for non-existing files. * @param string $batchId UUID string that identifies the operation batch * @return StatusValue */ public final function logChangeBatch(array $entries, $batchId) { if (!count($entries)) { return StatusValue::newGood(); } return $this->doLogChangeBatch($entries, $batchId); }
/** * @see FileJournal::purgeOldLogs() * @return StatusValue * @throws DBError */ protected function doPurgeOldLogs() { $status = StatusValue::newGood(); if ($this->ttlDays <= 0) { return $status; // nothing to do } $dbw = $this->getMasterDB(); $dbCutoff = $dbw->timestamp(time() - 86400 * $this->ttlDays); $dbw->delete('filejournal', ['fj_timestamp < ' . $dbw->addQuotes($dbCutoff)], __METHOD__); return $status; }