@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+181 -45
+3
src/__phutil_library_map__.php
··· 2254 2254 'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php', 2255 2255 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', 2256 2256 'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php', 2257 + 'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListMFAProvidersWorkflow.php', 2257 2258 'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php', 2258 2259 'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php', 2259 2260 'PhabricatorAuthManagementRevokeWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php', ··· 7892 7893 'PhabricatorAuthFactorConfig' => array( 7893 7894 'PhabricatorAuthDAO', 7894 7895 'PhabricatorPolicyInterface', 7896 + 'PhabricatorDestructibleInterface', 7895 7897 ), 7896 7898 'PhabricatorAuthFactorConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7897 7899 'PhabricatorAuthFactorProvider' => array( ··· 7948 7950 'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow', 7949 7951 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow', 7950 7952 'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow', 7953 + 'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'PhabricatorAuthManagementWorkflow', 7951 7954 'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow', 7952 7955 'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow', 7953 7956 'PhabricatorAuthManagementRevokeWorkflow' => 'PhabricatorAuthManagementWorkflow',
+1 -2
src/applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php
··· 14 14 public function execute(PhutilArgumentParser $args) { 15 15 $factors = PhabricatorAuthFactor::getAllFactors(); 16 16 17 - $console = PhutilConsole::getConsole(); 18 17 foreach ($factors as $factor) { 19 - $console->writeOut( 18 + echo tsprintf( 20 19 "%s\t%s\n", 21 20 $factor->getFactorKey(), 22 21 $factor->getFactorName());
+33
src/applications/auth/management/PhabricatorAuthManagementListMFAProvidersWorkflow.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthManagementListMFAProvidersWorkflow 4 + extends PhabricatorAuthManagementWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this 8 + ->setName('list-mfa-providers') 9 + ->setExamples('**list-mfa-providerrs**') 10 + ->setSynopsis( 11 + pht( 12 + 'List available multi-factor authentication providers.')) 13 + ->setArguments(array()); 14 + } 15 + 16 + public function execute(PhutilArgumentParser $args) { 17 + $viewer = $this->getViewer(); 18 + 19 + $providers = id(new PhabricatorAuthFactorProviderQuery()) 20 + ->setViewer($viewer) 21 + ->execute(); 22 + 23 + foreach ($providers as $provider) { 24 + echo tsprintf( 25 + "%s\t%s\n", 26 + $provider->getPHID(), 27 + $provider->getDisplayName()); 28 + } 29 + 30 + return 0; 31 + } 32 + 33 + }
+88 -41
src/applications/auth/management/PhabricatorAuthManagementStripWorkflow.php
··· 24 24 'name' => 'type', 25 25 'param' => 'factortype', 26 26 'repeat' => true, 27 - 'help' => pht('Strip a specific factor type.'), 27 + 'help' => pht( 28 + 'Strip a specific factor type. Use `bin/auth list-factors` for '. 29 + 'a list of factor types.'), 28 30 ), 29 31 array( 30 32 'name' => 'all-types', 31 33 'help' => pht('Strip all factors, regardless of type.'), 32 34 ), 33 35 array( 36 + 'name' => 'provider', 37 + 'param' => 'phid', 38 + 'repeat' => true, 39 + 'help' => pht( 40 + 'Strip factors for a specific provider. Use '. 41 + '`bin/auth list-mfa-providers` for a list of providers.'), 42 + ), 43 + array( 34 44 'name' => 'force', 35 45 'help' => pht('Strip factors without prompting.'), 36 46 ), ··· 42 52 } 43 53 44 54 public function execute(PhutilArgumentParser $args) { 55 + $viewer = $this->getViewer(); 56 + 45 57 $usernames = $args->getArg('user'); 46 58 $all_users = $args->getArg('all-users'); 47 59 ··· 55 67 } else if (!$usernames && !$all_users) { 56 68 throw new PhutilArgumentUsageException( 57 69 pht( 58 - 'Use %s to specify which user to strip factors from, or '. 59 - '%s to strip factors from all users.', 60 - '--user', 61 - '--all-users')); 70 + 'Use "--user <username>" to specify which user to strip factors '. 71 + 'from, or "--all-users" to strip factors from all users.')); 62 72 } else if ($usernames) { 63 73 $users = id(new PhabricatorPeopleQuery()) 64 74 ->setViewer($this->getViewer()) ··· 79 89 } 80 90 81 91 $types = $args->getArg('type'); 92 + $provider_phids = $args->getArg('provider'); 82 93 $all_types = $args->getArg('all-types'); 83 94 if ($types && $all_types) { 84 95 throw new PhutilArgumentUsageException( 85 96 pht( 86 - 'Specify either specific factors with --type, or all factors with '. 87 - '--all-types, but not both.')); 88 - } else if (!$types && !$all_types) { 97 + 'Specify either specific factors with "--type", or all factors with '. 98 + '"--all-types", but not both.')); 99 + } else if ($provider_phids && $all_types) { 100 + throw new PhutilArgumentUsageException( 101 + pht( 102 + 'Specify either specific factors with "--provider", or all factors '. 103 + 'with "--all-types", but not both.')); 104 + } else if (!$types && !$all_types && !$provider_phids) { 89 105 throw new PhutilArgumentUsageException( 90 106 pht( 91 - 'Use --type to specify which factor to strip, or --all-types to '. 92 - 'strip all factors. Use `auth list-factors` to show the available '. 93 - 'factor types.')); 107 + 'Use "--type <type>" or "--provider <phid>" to specify which '. 108 + 'factors to strip, or "--all-types" to strip all factors. '. 109 + 'Use `bin/auth list-factors` to show the available factor types '. 110 + 'or `bin/auth list-mfa-providers` to show available providers.')); 94 111 } 95 112 96 - if ($users && $types) { 97 - $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere( 98 - 'userPHID IN (%Ls) AND factorKey IN (%Ls)', 99 - mpull($users, 'getPHID'), 100 - $types); 101 - } else if ($users) { 102 - $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere( 103 - 'userPHID IN (%Ls)', 104 - mpull($users, 'getPHID')); 105 - } else if ($types) { 106 - $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere( 107 - 'factorKey IN (%Ls)', 108 - $types); 113 + $type_map = PhabricatorAuthFactor::getAllFactors(); 114 + 115 + if ($types) { 116 + foreach ($types as $type) { 117 + if (!isset($type_map[$type])) { 118 + throw new PhutilArgumentUsageException( 119 + pht( 120 + 'Factor type "%s" is unknown. Use `bin/auth list-factors` to '. 121 + 'get a list of known factor types.', 122 + $type)); 123 + } 124 + } 125 + } 126 + 127 + $provider_query = id(new PhabricatorAuthFactorProviderQuery()) 128 + ->setViewer($viewer); 129 + 130 + if ($provider_phids) { 131 + $provider_query->withPHIDs($provider_phids); 132 + } 133 + 134 + if ($types) { 135 + $provider_query->withProviderFactorKeys($types); 136 + } 137 + 138 + $providers = $provider_query->execute(); 139 + $providers = mpull($providers, null, 'getPHID'); 140 + 141 + if ($provider_phids) { 142 + foreach ($provider_phids as $provider_phid) { 143 + if (!isset($providers[$provider_phid])) { 144 + throw new PhutilArgumentUsageException( 145 + pht( 146 + 'No provider with PHID "%s" exists. '. 147 + 'Use `bin/auth list-mfa-providers` to list providers.', 148 + $provider_phid)); 149 + } 150 + } 109 151 } else { 110 - $factors = id(new PhabricatorAuthFactorConfig())->loadAll(); 152 + if (!$providers) { 153 + throw new PhutilArgumentUsageException( 154 + pht( 155 + 'There are no configured multi-factor providers.')); 156 + } 111 157 } 112 158 159 + $factor_query = id(new PhabricatorAuthFactorConfigQuery()) 160 + ->setViewer($viewer) 161 + ->withFactorProviderPHIDs(array_keys($providers)); 162 + 163 + if ($users) { 164 + $factor_query->withUserPHIDs(mpull($users, 'getPHID')); 165 + } 166 + 167 + $factors = $factor_query->execute(); 168 + 113 169 if (!$factors) { 114 170 throw new PhutilArgumentUsageException( 115 171 pht('There are no matching factors to strip.')); ··· 125 181 $console->writeOut("%s\n\n", pht('These auth factors will be stripped:')); 126 182 127 183 foreach ($factors as $factor) { 128 - $impl = $factor->getImplementation(); 129 - $console->writeOut( 184 + $provider = $factor->getFactorProvider(); 185 + 186 + echo tsprintf( 130 187 " %s\t%s\t%s\n", 131 188 $handles[$factor->getUserPHID()]->getName(), 132 - $factor->getFactorKey(), 133 - ($impl 134 - ? $impl->getFactorName() 135 - : '?')); 189 + $provider->getProviderFactorKey(), 190 + $provider->getDisplayName()); 136 191 } 137 192 138 193 $is_dry_run = $args->getArg('dry-run'); ··· 154 209 155 210 $console->writeOut("%s\n", pht('Stripping authentication factors...')); 156 211 212 + $engine = new PhabricatorDestructionEngine(); 157 213 foreach ($factors as $factor) { 158 - $user = id(new PhabricatorPeopleQuery()) 159 - ->setViewer($this->getViewer()) 160 - ->withPHIDs(array($factor->getUserPHID())) 161 - ->executeOne(); 162 - 163 - $factor->delete(); 164 - 165 - if ($user) { 166 - $user->updateMultiFactorEnrollment(); 167 - } 214 + $engine->destroyObject($factor); 168 215 } 169 216 170 217 $console->writeOut("%s\n", pht('Done.'));
+13
src/applications/auth/query/PhabricatorAuthFactorConfigQuery.php
··· 6 6 private $ids; 7 7 private $phids; 8 8 private $userPHIDs; 9 + private $factorProviderPHIDs; 9 10 10 11 public function withIDs(array $ids) { 11 12 $this->ids = $ids; ··· 19 20 20 21 public function withUserPHIDs(array $user_phids) { 21 22 $this->userPHIDs = $user_phids; 23 + return $this; 24 + } 25 + 26 + public function withFactorProviderPHIDs(array $provider_phids) { 27 + $this->factorProviderPHIDs = $provider_phids; 22 28 return $this; 23 29 } 24 30 ··· 52 58 $conn, 53 59 'userPHID IN (%Ls)', 54 60 $this->userPHIDs); 61 + } 62 + 63 + if ($this->factorProviderPHIDs !== null) { 64 + $where[] = qsprintf( 65 + $conn, 66 + 'factorProviderPHID IN (%Ls)', 67 + $this->factorProviderPHIDs); 55 68 } 56 69 57 70 return $where;
+23 -1
src/applications/auth/storage/PhabricatorAuthFactorConfig.php
··· 1 1 <?php 2 2 3 + 3 4 final class PhabricatorAuthFactorConfig 4 5 extends PhabricatorAuthDAO 5 - implements PhabricatorPolicyInterface { 6 + implements 7 + PhabricatorPolicyInterface, 8 + PhabricatorDestructibleInterface { 6 9 7 10 protected $userPHID; 8 11 protected $factorProviderPHID; ··· 75 78 76 79 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 77 80 return false; 81 + } 82 + 83 + 84 + /* -( PhabricatorDestructibleInterface )----------------------------------- */ 85 + 86 + 87 + public function destroyObjectPermanently( 88 + PhabricatorDestructionEngine $engine) { 89 + 90 + $user = id(new PhabricatorPeopleQuery()) 91 + ->setViewer($engine->getViewer()) 92 + ->withPHIDs(array($this->getUserPHID())) 93 + ->executeOne(); 94 + 95 + $this->delete(); 96 + 97 + if ($user) { 98 + $user->updateMultiFactorEnrollment(); 99 + } 78 100 } 79 101 80 102 }
+20 -1
src/docs/user/userguide/multi_factor_auth.diviner
··· 126 126 arguments. 127 127 128 128 This command can selectively strip types of factors. You can use 129 - `bin/auth list-factors` for a list of available factor types. 129 + `bin/auth list-factors` to get a list of available factor types. 130 130 131 131 ```lang=console 132 132 # Show supported factor types. 133 133 phabricator/ $ ./bin/auth list-factors 134 134 ``` 135 + 136 + Once you've identified the factor types you want to strip, you can strip them 137 + using the `--type` flag to specify one or more factor types: 138 + 139 + ```lang=console 140 + # Strip all SMS and TOTP factors for a user. 141 + phabricator/ $ ./bin/auth strip --user <username> --type sms --type totp 142 + ``` 143 + 144 + The `bin/auth strip` command can also selectively strip factors for certain 145 + providers. This is more granular than stripping all factors of a given type. 146 + You can use `bin/auth list-mfa-providers` to get a list of providers. 147 + 148 + Once you have a provider PHID, use `--provider` to select factors to strip: 149 + 150 + ```lang=console 151 + # Strip all factors for a particular provider. 152 + phabricator/ $ ./bin/auth strip --user <username> --provider <providerPHID> 153 + ```