1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 22:10:55 +01:00

Add bin/auth unlimit and clean up a TODO

Summary:
I stumbled across this TODO and was worried that there was a glaring hole in MFA that I'd somehow forgotten about, but the TODO is just out of date.

These actions are rate limited properly by `PhabricatorAuthTryFactorAction`, which permits a maximum of 10 actions per hour.

  - Remove the TODO.
  - Add `bin/auth unlimit` to make it easier to reset rate limits if someone needs to do that for whatever reason.

Test Plan:
  - Tried to brute force through MFA.
  - Got rate limited properly after 10 failures.
  - Reset rate limit with `bin/auth unlimit`.
  - Saw the expected number of actions clear.

{F805288}

Reviewers: chad

Reviewed By: chad

Subscribers: joshuaspence

Differential Revision: https://secure.phabricator.com/D14105
This commit is contained in:
epriestley 2015-09-14 07:03:39 -07:00
parent 6bd8ee861c
commit 0449a07f53
4 changed files with 100 additions and 3 deletions

View file

@ -1621,6 +1621,7 @@ phutil_register_library_map(array(
'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php',
'PhabricatorAuthManagementStripWorkflow' => 'applications/auth/management/PhabricatorAuthManagementStripWorkflow.php',
'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php',
'PhabricatorAuthManagementUnlimitWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUnlimitWorkflow.php',
'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php',
'PhabricatorAuthManagementVerifyWorkflow' => 'applications/auth/management/PhabricatorAuthManagementVerifyWorkflow.php',
'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php',
@ -5472,6 +5473,7 @@ phutil_register_library_map(array(
'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementStripWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementUnlimitWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementVerifyWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementWorkflow' => 'PhabricatorManagementWorkflow',

View file

@ -192,9 +192,6 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
PhutilOpaqueEnvelope $key,
$code) {
// TODO: This should use rate limiting to prevent multiple attempts in a
// short period of time.
$now = (int)(time() / 30);
// Allow the user to enter a code a few minutes away on either side, in

View file

@ -0,0 +1,67 @@
<?php
final class PhabricatorAuthManagementUnlimitWorkflow
extends PhabricatorAuthManagementWorkflow {
protected function didConstruct() {
$this
->setName('unlimit')
->setExamples('**unlimit** --user __username__ --all')
->setSynopsis(
pht(
'Reset action counters so a user can continue taking '.
'rate-limited actions.'))
->setArguments(
array(
array(
'name' => 'user',
'param' => 'username',
'help' => pht('Reset action counters for this user.'),
),
array(
'name' => 'all',
'help' => pht('Reset all counters.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
$username = $args->getArg('user');
if (!strlen($username)) {
throw new PhutilArgumentUsageException(
pht(
'Use %s to choose a user to reset actions for.', '--user'));
}
$user = id(new PhabricatorPeopleQuery())
->setViewer($this->getViewer())
->withUsernames(array($username))
->executeOne();
if (!$user) {
throw new PhutilArgumentUsageException(
pht(
'No user exists with username "%s".',
$username));
}
$all = $args->getArg('all');
if (!$all) {
// TODO: Eventually, let users reset specific actions. For now, we
// require `--all` so that usage won't change when you can reset in a
// more tailored way.
throw new PhutilArgumentUsageException(
pht(
'Specify %s to reset all action counters.', '--all'));
}
$count = PhabricatorSystemActionEngine::resetActions(
array(
$user->getPHID(),
));
echo pht('Reset %s action(s).', new PhutilNumber($count))."\n";
return 0;
}
}

View file

@ -167,4 +167,35 @@ final class PhabricatorSystemActionEngine extends Phobject {
return phutil_units('1 hour in seconds');
}
/**
* Reset all action counts for actions taken by some set of actors in the
* previous action window.
*
* @param list<string> Actors to reset counts for.
* @return int Number of actions cleared.
*/
public static function resetActions(array $actors) {
$log = new PhabricatorSystemActionLog();
$conn_w = $log->establishConnection('w');
$now = PhabricatorTime::getNow();
$hashes = array();
foreach ($actors as $actor) {
$hashes[] = PhabricatorHash::digestForIndex($actor);
}
queryfx(
$conn_w,
'DELETE FROM %T
WHERE actorHash IN (%Ls) AND epoch BETWEEN %d AND %d',
$log->getTableName(),
$hashes,
$now - self::getWindow(),
$now);
return $conn_w->getAffectedRows();
}
}