mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 01:02:42 +01:00
Update bin/auth
MFA commands for the new "MFA Provider" indirection layer
Summary: Ref T13222. This updates the CLI tools and documentation for the changes in D19975. The flags `--type` and `--all-types` retain their current meaning. In most cases, `bin/auth strip --type totp` is sufficient and you don't need to bother looking up the relevant provider PHID. The existing `bin/auth list-factors` is also unchanged. The new `--provider` flag allows you to select configs from a particular provider in a more granular way. The new `bin/auth list-mfa-providers` provides an easy way to get PHIDs. (In the Phacility cluster, the "Strip MFA" action just reaches into the database and deletes rows manually, so this isn't terribly important. I verified that the code should still work properly.) Test Plan: - Ran `bin/auth list-mfa-providers`. - Stripped by user / type / provider. - Grepped for `list-factors` and `auth strip`. - Hit all (?) of the various possible error cases. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13222 Differential Revision: https://secure.phabricator.com/D19976
This commit is contained in:
parent
0fcff78253
commit
aa48373889
7 changed files with 182 additions and 46 deletions
|
@ -2254,6 +2254,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php',
|
'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php',
|
||||||
'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php',
|
'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php',
|
||||||
'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php',
|
'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php',
|
||||||
|
'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListMFAProvidersWorkflow.php',
|
||||||
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
|
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
|
||||||
'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php',
|
'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php',
|
||||||
'PhabricatorAuthManagementRevokeWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php',
|
'PhabricatorAuthManagementRevokeWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php',
|
||||||
|
@ -7892,6 +7893,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthFactorConfig' => array(
|
'PhabricatorAuthFactorConfig' => array(
|
||||||
'PhabricatorAuthDAO',
|
'PhabricatorAuthDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorDestructibleInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorAuthFactorConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorAuthFactorConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorAuthFactorProvider' => array(
|
'PhabricatorAuthFactorProvider' => array(
|
||||||
|
@ -7948,6 +7950,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow',
|
'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
|
'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
'PhabricatorAuthManagementRevokeWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
'PhabricatorAuthManagementRevokeWorkflow' => 'PhabricatorAuthManagementWorkflow',
|
||||||
|
|
|
@ -14,9 +14,8 @@ final class PhabricatorAuthManagementListFactorsWorkflow
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
$factors = PhabricatorAuthFactor::getAllFactors();
|
$factors = PhabricatorAuthFactor::getAllFactors();
|
||||||
|
|
||||||
$console = PhutilConsole::getConsole();
|
|
||||||
foreach ($factors as $factor) {
|
foreach ($factors as $factor) {
|
||||||
$console->writeOut(
|
echo tsprintf(
|
||||||
"%s\t%s\n",
|
"%s\t%s\n",
|
||||||
$factor->getFactorKey(),
|
$factor->getFactorKey(),
|
||||||
$factor->getFactorName());
|
$factor->getFactorName());
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAuthManagementListMFAProvidersWorkflow
|
||||||
|
extends PhabricatorAuthManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('list-mfa-providers')
|
||||||
|
->setExamples('**list-mfa-providerrs**')
|
||||||
|
->setSynopsis(
|
||||||
|
pht(
|
||||||
|
'List available multi-factor authentication providers.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$providers = id(new PhabricatorAuthFactorProviderQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
foreach ($providers as $provider) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\t%s\n",
|
||||||
|
$provider->getPHID(),
|
||||||
|
$provider->getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,12 +24,22 @@ final class PhabricatorAuthManagementStripWorkflow
|
||||||
'name' => 'type',
|
'name' => 'type',
|
||||||
'param' => 'factortype',
|
'param' => 'factortype',
|
||||||
'repeat' => true,
|
'repeat' => true,
|
||||||
'help' => pht('Strip a specific factor type.'),
|
'help' => pht(
|
||||||
|
'Strip a specific factor type. Use `bin/auth list-factors` for '.
|
||||||
|
'a list of factor types.'),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'all-types',
|
'name' => 'all-types',
|
||||||
'help' => pht('Strip all factors, regardless of type.'),
|
'help' => pht('Strip all factors, regardless of type.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'provider',
|
||||||
|
'param' => 'phid',
|
||||||
|
'repeat' => true,
|
||||||
|
'help' => pht(
|
||||||
|
'Strip factors for a specific provider. Use '.
|
||||||
|
'`bin/auth list-mfa-providers` for a list of providers.'),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'force',
|
'name' => 'force',
|
||||||
'help' => pht('Strip factors without prompting.'),
|
'help' => pht('Strip factors without prompting.'),
|
||||||
|
@ -42,6 +52,8 @@ final class PhabricatorAuthManagementStripWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$usernames = $args->getArg('user');
|
$usernames = $args->getArg('user');
|
||||||
$all_users = $args->getArg('all-users');
|
$all_users = $args->getArg('all-users');
|
||||||
|
|
||||||
|
@ -55,10 +67,8 @@ final class PhabricatorAuthManagementStripWorkflow
|
||||||
} else if (!$usernames && !$all_users) {
|
} else if (!$usernames && !$all_users) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht(
|
pht(
|
||||||
'Use %s to specify which user to strip factors from, or '.
|
'Use "--user <username>" to specify which user to strip factors '.
|
||||||
'%s to strip factors from all users.',
|
'from, or "--all-users" to strip factors from all users.'));
|
||||||
'--user',
|
|
||||||
'--all-users'));
|
|
||||||
} else if ($usernames) {
|
} else if ($usernames) {
|
||||||
$users = id(new PhabricatorPeopleQuery())
|
$users = id(new PhabricatorPeopleQuery())
|
||||||
->setViewer($this->getViewer())
|
->setViewer($this->getViewer())
|
||||||
|
@ -79,37 +89,83 @@ final class PhabricatorAuthManagementStripWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
$types = $args->getArg('type');
|
$types = $args->getArg('type');
|
||||||
|
$provider_phids = $args->getArg('provider');
|
||||||
$all_types = $args->getArg('all-types');
|
$all_types = $args->getArg('all-types');
|
||||||
if ($types && $all_types) {
|
if ($types && $all_types) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht(
|
pht(
|
||||||
'Specify either specific factors with --type, or all factors with '.
|
'Specify either specific factors with "--type", or all factors with '.
|
||||||
'--all-types, but not both.'));
|
'"--all-types", but not both.'));
|
||||||
} else if (!$types && !$all_types) {
|
} else if ($provider_phids && $all_types) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht(
|
pht(
|
||||||
'Use --type to specify which factor to strip, or --all-types to '.
|
'Specify either specific factors with "--provider", or all factors '.
|
||||||
'strip all factors. Use `auth list-factors` to show the available '.
|
'with "--all-types", but not both.'));
|
||||||
'factor types.'));
|
} else if (!$types && !$all_types && !$provider_phids) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Use "--type <type>" or "--provider <phid>" to specify which '.
|
||||||
|
'factors to strip, or "--all-types" to strip all factors. '.
|
||||||
|
'Use `bin/auth list-factors` to show the available factor types '.
|
||||||
|
'or `bin/auth list-mfa-providers` to show available providers.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($users && $types) {
|
$type_map = PhabricatorAuthFactor::getAllFactors();
|
||||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
|
|
||||||
'userPHID IN (%Ls) AND factorKey IN (%Ls)',
|
if ($types) {
|
||||||
mpull($users, 'getPHID'),
|
foreach ($types as $type) {
|
||||||
$types);
|
if (!isset($type_map[$type])) {
|
||||||
} else if ($users) {
|
throw new PhutilArgumentUsageException(
|
||||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
|
pht(
|
||||||
'userPHID IN (%Ls)',
|
'Factor type "%s" is unknown. Use `bin/auth list-factors` to '.
|
||||||
mpull($users, 'getPHID'));
|
'get a list of known factor types.',
|
||||||
} else if ($types) {
|
$type));
|
||||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
|
}
|
||||||
'factorKey IN (%Ls)',
|
}
|
||||||
$types);
|
|
||||||
} else {
|
|
||||||
$factors = id(new PhabricatorAuthFactorConfig())->loadAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$provider_query = id(new PhabricatorAuthFactorProviderQuery())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
if ($provider_phids) {
|
||||||
|
$provider_query->withPHIDs($provider_phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($types) {
|
||||||
|
$provider_query->withProviderFactorKeys($types);
|
||||||
|
}
|
||||||
|
|
||||||
|
$providers = $provider_query->execute();
|
||||||
|
$providers = mpull($providers, null, 'getPHID');
|
||||||
|
|
||||||
|
if ($provider_phids) {
|
||||||
|
foreach ($provider_phids as $provider_phid) {
|
||||||
|
if (!isset($providers[$provider_phid])) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'No provider with PHID "%s" exists. '.
|
||||||
|
'Use `bin/auth list-mfa-providers` to list providers.',
|
||||||
|
$provider_phid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$providers) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'There are no configured multi-factor providers.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$factor_query = id(new PhabricatorAuthFactorConfigQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withFactorProviderPHIDs(array_keys($providers));
|
||||||
|
|
||||||
|
if ($users) {
|
||||||
|
$factor_query->withUserPHIDs(mpull($users, 'getPHID'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$factors = $factor_query->execute();
|
||||||
|
|
||||||
if (!$factors) {
|
if (!$factors) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht('There are no matching factors to strip.'));
|
pht('There are no matching factors to strip.'));
|
||||||
|
@ -125,14 +181,13 @@ final class PhabricatorAuthManagementStripWorkflow
|
||||||
$console->writeOut("%s\n\n", pht('These auth factors will be stripped:'));
|
$console->writeOut("%s\n\n", pht('These auth factors will be stripped:'));
|
||||||
|
|
||||||
foreach ($factors as $factor) {
|
foreach ($factors as $factor) {
|
||||||
$impl = $factor->getImplementation();
|
$provider = $factor->getFactorProvider();
|
||||||
$console->writeOut(
|
|
||||||
|
echo tsprintf(
|
||||||
" %s\t%s\t%s\n",
|
" %s\t%s\t%s\n",
|
||||||
$handles[$factor->getUserPHID()]->getName(),
|
$handles[$factor->getUserPHID()]->getName(),
|
||||||
$factor->getFactorKey(),
|
$provider->getProviderFactorKey(),
|
||||||
($impl
|
$provider->getDisplayName());
|
||||||
? $impl->getFactorName()
|
|
||||||
: '?'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_dry_run = $args->getArg('dry-run');
|
$is_dry_run = $args->getArg('dry-run');
|
||||||
|
@ -154,17 +209,9 @@ final class PhabricatorAuthManagementStripWorkflow
|
||||||
|
|
||||||
$console->writeOut("%s\n", pht('Stripping authentication factors...'));
|
$console->writeOut("%s\n", pht('Stripping authentication factors...'));
|
||||||
|
|
||||||
|
$engine = new PhabricatorDestructionEngine();
|
||||||
foreach ($factors as $factor) {
|
foreach ($factors as $factor) {
|
||||||
$user = id(new PhabricatorPeopleQuery())
|
$engine->destroyObject($factor);
|
||||||
->setViewer($this->getViewer())
|
|
||||||
->withPHIDs(array($factor->getUserPHID()))
|
|
||||||
->executeOne();
|
|
||||||
|
|
||||||
$factor->delete();
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
$user->updateMultiFactorEnrollment();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$console->writeOut("%s\n", pht('Done.'));
|
$console->writeOut("%s\n", pht('Done.'));
|
||||||
|
|
|
@ -6,6 +6,7 @@ final class PhabricatorAuthFactorConfigQuery
|
||||||
private $ids;
|
private $ids;
|
||||||
private $phids;
|
private $phids;
|
||||||
private $userPHIDs;
|
private $userPHIDs;
|
||||||
|
private $factorProviderPHIDs;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -22,6 +23,11 @@ final class PhabricatorAuthFactorConfigQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withFactorProviderPHIDs(array $provider_phids) {
|
||||||
|
$this->factorProviderPHIDs = $provider_phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newResultObject() {
|
||||||
return new PhabricatorAuthFactorConfig();
|
return new PhabricatorAuthFactorConfig();
|
||||||
}
|
}
|
||||||
|
@ -54,6 +60,13 @@ final class PhabricatorAuthFactorConfigQuery
|
||||||
$this->userPHIDs);
|
$this->userPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->factorProviderPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'factorProviderPHID IN (%Ls)',
|
||||||
|
$this->factorProviderPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
return $where;
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
final class PhabricatorAuthFactorConfig
|
final class PhabricatorAuthFactorConfig
|
||||||
extends PhabricatorAuthDAO
|
extends PhabricatorAuthDAO
|
||||||
implements PhabricatorPolicyInterface {
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorDestructibleInterface {
|
||||||
|
|
||||||
protected $userPHID;
|
protected $userPHID;
|
||||||
protected $factorProviderPHID;
|
protected $factorProviderPHID;
|
||||||
|
@ -77,4 +80,23 @@ final class PhabricatorAuthFactorConfig
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function destroyObjectPermanently(
|
||||||
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
|
$user = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer($engine->getViewer())
|
||||||
|
->withPHIDs(array($this->getUserPHID()))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$this->delete();
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
$user->updateMultiFactorEnrollment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,9 +126,28 @@ You can run `bin/auth help strip` for more detail and all available flags and
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
This command can selectively strip types of factors. You can use
|
This command can selectively strip types of factors. You can use
|
||||||
`bin/auth list-factors` for a list of available factor types.
|
`bin/auth list-factors` to get a list of available factor types.
|
||||||
|
|
||||||
```lang=console
|
```lang=console
|
||||||
# Show supported factor types.
|
# Show supported factor types.
|
||||||
phabricator/ $ ./bin/auth list-factors
|
phabricator/ $ ./bin/auth list-factors
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Once you've identified the factor types you want to strip, you can strip them
|
||||||
|
using the `--type` flag to specify one or more factor types:
|
||||||
|
|
||||||
|
```lang=console
|
||||||
|
# Strip all SMS and TOTP factors for a user.
|
||||||
|
phabricator/ $ ./bin/auth strip --user <username> --type sms --type totp
|
||||||
|
```
|
||||||
|
|
||||||
|
The `bin/auth strip` command can also selectively strip factors for certain
|
||||||
|
providers. This is more granular than stripping all factors of a given type.
|
||||||
|
You can use `bin/auth list-mfa-providers` to get a list of providers.
|
||||||
|
|
||||||
|
Once you have a provider PHID, use `--provider` to select factors to strip:
|
||||||
|
|
||||||
|
```lang=console
|
||||||
|
# Strip all factors for a particular provider.
|
||||||
|
phabricator/ $ ./bin/auth strip --user <username> --provider <providerPHID>
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in a new issue