mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-30 09:20:58 +01:00
Add bin/auth list-factors
and bin/auth strip
to remove multi-factor auth
Summary: Ref T4398. The major goals here is to let administrators strip auth factors in two cases: - A user lost their phone and needs access restored to their account; or - an install previously used an API-based factor like SMS, but want to stop supporting it (this isn't possible today). Test Plan: - Used `bin/auth list-factors` to show installed factors. - Used `bin/auth strip` with various mixtures of flags to selectively choose and strip factors from accounts. - Also ran `bin/auth refresh` to verify refreshing OAuth tokens works (small `OAuth` vs `OAuth2` tweak). Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T4398 Differential Revision: https://secure.phabricator.com/D8909
This commit is contained in:
parent
d41416faf0
commit
535cfa3ebe
4 changed files with 198 additions and 2 deletions
|
@ -1219,8 +1219,10 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php',
|
||||
'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php',
|
||||
'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php',
|
||||
'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php',
|
||||
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
|
||||
'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php',
|
||||
'PhabricatorAuthManagementStripWorkflow' => 'applications/auth/management/PhabricatorAuthManagementStripWorkflow.php',
|
||||
'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php',
|
||||
'PhabricatorAuthNeedsApprovalController' => 'applications/auth/controller/PhabricatorAuthNeedsApprovalController.php',
|
||||
'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php',
|
||||
|
@ -3982,8 +3984,10 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController',
|
||||
'PhabricatorAuthLoginController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||
'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||
'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||
'PhabricatorAuthManagementStripWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||
'PhabricatorAuthManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'PhabricatorAuthNeedsApprovalController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController',
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthManagementListFactorsWorkflow
|
||||
extends PhabricatorAuthManagementWorkflow {
|
||||
|
||||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('list-factors')
|
||||
->setExamples('**list-factors**')
|
||||
->setSynopsis(pht('List available multi-factor authentication factors.'))
|
||||
->setArguments(array());
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$factors = PhabricatorAuthFactor::getAllFactors();
|
||||
|
||||
$console = PhutilConsole::getConsole();
|
||||
foreach ($factors as $factor) {
|
||||
$console->writeOut(
|
||||
"%s\t%s\n",
|
||||
$factor->getFactorKey(),
|
||||
$factor->getFactorName());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -96,10 +96,10 @@ final class PhabricatorAuthManagementRefreshWorkflow
|
|||
}
|
||||
|
||||
$provider = $providers[$key];
|
||||
if (!($provider instanceof PhabricatorAuthProviderOAuth)) {
|
||||
if (!($provider instanceof PhabricatorAuthProviderOAuth2)) {
|
||||
$console->writeOut(
|
||||
"> %s\n",
|
||||
pht("Skipping, provider is not an OAuth provider."));
|
||||
pht("Skipping, provider is not an OAuth2 provider."));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthManagementStripWorkflow
|
||||
extends PhabricatorAuthManagementWorkflow {
|
||||
|
||||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('strip')
|
||||
->setExamples('**strip** [--user username] [--type type]')
|
||||
->setSynopsis(
|
||||
pht(
|
||||
'Remove multi-factor authentication from an account.'))
|
||||
->setArguments(
|
||||
array(
|
||||
array(
|
||||
'name' => 'user',
|
||||
'param' => 'username',
|
||||
'repeat' => true,
|
||||
'help' => pht('Strip factors from specified users.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'all-users',
|
||||
'help' => pht('Strip factors from all users.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'type',
|
||||
'param' => 'factortype',
|
||||
'repeat' => true,
|
||||
'help' => pht('Strip a specific factor type.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'all-types',
|
||||
'help' => pht('Strip all factors, regardless of type.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'force',
|
||||
'help' => pht('Strip factors without prompting.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'dry-run',
|
||||
'help' => pht('Show factors, but do not strip them.'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$usernames = $args->getArg('user');
|
||||
$all_users = $args->getArg('all-users');
|
||||
|
||||
if ($usernames && $all_users) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specify either specific users with --user, or all users with '.
|
||||
'--all-users, but not both.'));
|
||||
} else if (!$usernames && !$all_users) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Use --user to specify which user to strip factors from, or '.
|
||||
'--all-users to strip factors from all users.'));
|
||||
} else if ($usernames) {
|
||||
$users = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withUsernames($usernames)
|
||||
->execute();
|
||||
|
||||
$users_by_username = mpull($users, null, 'getUsername');
|
||||
foreach ($usernames as $username) {
|
||||
if (empty($users_by_username[$username])) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'No user exists with username "%s".',
|
||||
$username));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$users = null;
|
||||
}
|
||||
|
||||
$types = $args->getArg('type');
|
||||
$all_types = $args->getArg('all-types');
|
||||
if ($types && $all_types) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specify either specific factors with --type, or all factors with '.
|
||||
'--all-types, but not both.'));
|
||||
} else if (!$types && !$all_types) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Use --type to specify which factor to strip, or --all-types to '.
|
||||
'strip all factors. Use `auth list-factors` to show the available '.
|
||||
'factor types.'));
|
||||
}
|
||||
|
||||
if ($users && $types) {
|
||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
|
||||
'userPHID IN (%Ls) AND factorKey IN (%Ls)',
|
||||
mpull($users, 'getPHID'),
|
||||
$types);
|
||||
} else if ($users) {
|
||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
|
||||
'userPHID IN (%Ls)',
|
||||
mpull($users, 'getPHID'));
|
||||
} else if ($types) {
|
||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
|
||||
'factorKey IN (%Ls)',
|
||||
$types);
|
||||
} else {
|
||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAll();
|
||||
}
|
||||
|
||||
if (!$factors) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht('There are no matching factors to strip.'));
|
||||
}
|
||||
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(mpull($factors, 'getUserPHID'))
|
||||
->execute();
|
||||
|
||||
$console = PhutilConsole::getConsole();
|
||||
|
||||
$console->writeOut("%s\n\n", pht("These auth factors will be stripped:"));
|
||||
|
||||
foreach ($factors as $factor) {
|
||||
$impl = $factor->getImplementation();
|
||||
$console->writeOut(
|
||||
" %s\t%s\t%s\n",
|
||||
$handles[$factor->getUserPHID()]->getName(),
|
||||
$factor->getFactorKey(),
|
||||
($impl
|
||||
? $impl->getFactorName()
|
||||
: '?'));
|
||||
}
|
||||
|
||||
$is_dry_run = $args->getArg('dry-run');
|
||||
if ($is_dry_run) {
|
||||
$console->writeOut(
|
||||
"\n%s\n",
|
||||
pht('End of dry run.'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$force = $args->getArg('force');
|
||||
if (!$force) {
|
||||
if (!$console->confirm(pht('Strip these authentication factors?'))) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht('User aborted the workflow.'));
|
||||
}
|
||||
}
|
||||
|
||||
$console->writeOut("%s\n", pht('Stripping authentication factors...'));
|
||||
|
||||
foreach ($factors as $factor) {
|
||||
$factor->delete();
|
||||
}
|
||||
|
||||
$console->writeOut("%s\n", pht('Done.'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue