diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2306,12 +2306,14 @@ 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', 'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php', 'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListMFAProvidersWorkflow.php', + 'PhabricatorAuthManagementLockWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLockWorkflow.php', 'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php', 'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php', 'PhabricatorAuthManagementRevokeWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php', 'PhabricatorAuthManagementStripWorkflow' => 'applications/auth/management/PhabricatorAuthManagementStripWorkflow.php', 'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php', 'PhabricatorAuthManagementUnlimitWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUnlimitWorkflow.php', + 'PhabricatorAuthManagementUnlockWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUnlockWorkflow.php', 'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php', 'PhabricatorAuthManagementVerifyWorkflow' => 'applications/auth/management/PhabricatorAuthManagementVerifyWorkflow.php', 'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php', @@ -8172,12 +8174,14 @@ 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'PhabricatorAuthManagementWorkflow', + 'PhabricatorAuthManagementLockWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRevokeWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementStripWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementUnlimitWorkflow' => 'PhabricatorAuthManagementWorkflow', + 'PhabricatorAuthManagementUnlockWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementVerifyWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementWorkflow' => 'PhabricatorManagementWorkflow', diff --git a/src/applications/auth/management/PhabricatorAuthManagementLockWorkflow.php b/src/applications/auth/management/PhabricatorAuthManagementLockWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/management/PhabricatorAuthManagementLockWorkflow.php @@ -0,0 +1,32 @@ +setName('lock') + ->setExamples('**lock**') + ->setSynopsis( + pht( + 'Lock authentication provider config, to prevent changes to '. + 'the config without doing **bin/auth unlock**.')); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + + $key = 'auth.lock-config'; + $config_entry = PhabricatorConfigEntry::loadConfigEntry($key); + $config_entry->setValue(true); + + // If the entry has been deleted, resurrect it. + $config_entry->setIsDeleted(0); + + $config_entry->save(); + + $console->writeOut( + "%s\n", + pht('Locked the authentication provider configuration.')); + } +} diff --git a/src/applications/auth/management/PhabricatorAuthManagementUnlockWorkflow.php b/src/applications/auth/management/PhabricatorAuthManagementUnlockWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/management/PhabricatorAuthManagementUnlockWorkflow.php @@ -0,0 +1,33 @@ +setName('unlock') + ->setExamples('**unlock**') + ->setSynopsis( + pht( + 'Unlock the authentication provider config, to make it possible '. + 'to edit the config using the web UI. Make sure to do '. + '**bin/auth unlock** when done editing the configuration.')); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + + $key = 'auth.lock-config'; + $config_entry = PhabricatorConfigEntry::loadConfigEntry($key); + $config_entry->setValue(false); + + // If the entry has been deleted, resurrect it. + $config_entry->setIsDeleted(0); + + $config_entry->save(); + + $console->writeOut( + "%s\n", + pht('Unlocked the authentication provider configuration.')); + } +} diff --git a/src/applications/config/check/PhabricatorAuthSetupCheck.php b/src/applications/config/check/PhabricatorAuthSetupCheck.php --- a/src/applications/config/check/PhabricatorAuthSetupCheck.php +++ b/src/applications/config/check/PhabricatorAuthSetupCheck.php @@ -36,5 +36,34 @@ ->setMessage($message) ->addLink('/auth/', pht('Auth Application')); } + + // This check is also meant for new administrators, but also serves as a + // reminder to administrators to go back and do a `bin/auth lock` after + // they make their desired changes. + $is_locked = PhabricatorEnv::getEnvConfig('auth.lock-config'); + if (!$is_locked) { + $message = pht( + 'Your authentication provider configuration is unlocked. This '. + 'increases the damage that a compromised administrator account can '. + 'do to your install, by, for example, changing the authentication '. + 'provider to a server they control and intercepting usernames and '. + 'passwords.'. + "\n\n". + 'To prevent this attack, you should configure your authentication '. + 'providers, and then lock the configuration by doing `%s` '. + 'from the command line. This will prevent changes to the '. + 'authentication provider config without first doing `%s`.', + 'bin/auth lock', + 'bin/auth unlock'); + $this + ->newIssue('auth.config-unlocked') + ->setShortName(pht('Auth Config Unlocked')) + ->setName(pht('Authenticaton Provider Configuration Unlocked')) + ->setMessage($message) + ->addRelatedPhabricatorConfig('auth.lock-config') + ->addCommand( + hsprintf( + 'phabricator/ $ ./bin/auth lock')); + } } } diff --git a/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php b/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php --- a/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php +++ b/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php @@ -73,6 +73,26 @@ ->addExample( "yourcompany.com\nmail.yourcompany.com", pht('Valid Setting')), + $this->newOption('auth.lock-config', 'bool', false) + ->setBoolOptions( + array( + pht('Auth provider config must be unlocked before editing'), + pht('Auth provider config can be edited without unlocking'), + )) + ->setSummary( + pht( + 'Require administrators to unlock the authentication provider '. + 'configuration from the CLI before it can be edited.')) + ->setDescription( + pht( + 'Normally, administrators configure authentication providers only '. + 'once, immediately after instance creation. To further secure '. + 'your instance, you can set this configuration option to `true`, '. + 'which will require an adminstrator with CLI access to run '. + '`bin/auth unlock` to make any later changes to authentication '. + "provider configuration.\n\nAfter changing the config, you should ". + 'do `bin/auth lock` again from the CLI.')) + ->setLocked(true), $this->newOption('account.editable', 'bool', true) ->setBoolOptions( array(