mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-24 07:42:39 +01:00
Support simpler, token-based Conduit authentication in Arcanist
Summary: Ref T5955. If the server supports token-based authentication, prefer it over certificate-based authentication. Also fixes T3117. Test Plan: - Used `arc install-certificate` to install credentials from both token-based and certificate-based hosts. - Used `arc list` with a token-based host. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T3117, T2878, T5955 Differential Revision: https://secure.phabricator.com/D10988
This commit is contained in:
parent
565a96e0ee
commit
5118987757
3 changed files with 123 additions and 32 deletions
|
@ -275,29 +275,34 @@ try {
|
|||
$host_config = idx($hosts_config, $conduit_uri, array());
|
||||
$user_name = idx($host_config, 'user');
|
||||
$certificate = idx($host_config, 'cert');
|
||||
$conduit_token = idx($host_config, 'token');
|
||||
|
||||
$description = implode(' ', $original_argv);
|
||||
$credentials = array(
|
||||
'user' => $user_name,
|
||||
'user' => $user_name,
|
||||
'certificate' => $certificate,
|
||||
'description' => $description,
|
||||
'token' => $conduit_token,
|
||||
);
|
||||
$workflow->setConduitCredentials($credentials);
|
||||
|
||||
if ($need_auth) {
|
||||
if (!$user_name || !$certificate) {
|
||||
if ((!$user_name || !$certificate) && (!$conduit_token)) {
|
||||
$arc = 'arc';
|
||||
if ($force_conduit) {
|
||||
$arc .= csprintf(' --conduit-uri=%s', $conduit_uri);
|
||||
}
|
||||
|
||||
$conduit_domain = id(new PhutilURI($conduit_uri))->getDomain();
|
||||
|
||||
throw new ArcanistUsageException(
|
||||
phutil_console_format(
|
||||
"YOU NEED TO __INSTALL A CERTIFICATE__ TO LOGIN TO PHABRICATOR\n\n".
|
||||
"You are trying to connect to '{$conduit_uri}' but do not have ".
|
||||
"a certificate installed for this host. Run:\n\n".
|
||||
" $ **{$arc} install-certificate**\n\n".
|
||||
"...to install one."));
|
||||
"YOU NEED TO AUTHENTICATE TO CONTINUE\n\n".
|
||||
"You are trying to connect to a server ({$conduit_domain}) that you ".
|
||||
"do not have any credentials stored for.\n\n".
|
||||
"To retrieve and store credentials for this server, ".
|
||||
"**run this command:**\n\n".
|
||||
" $ **{$arc} install-certificate**\n"));
|
||||
}
|
||||
$workflow->authenticateConduit();
|
||||
}
|
||||
|
|
|
@ -48,66 +48,126 @@ EOTEXT
|
|||
}
|
||||
|
||||
public function run() {
|
||||
$console = PhutilConsole::getConsole();
|
||||
|
||||
$uri = $this->determineConduitURI();
|
||||
$this->setConduitURI($uri);
|
||||
$configuration_manager = $this->getConfigurationManager();
|
||||
|
||||
echo "Installing certificate for '{$uri}'...\n";
|
||||
|
||||
$config = $configuration_manager->readUserConfigurationFile();
|
||||
|
||||
echo "Trying to connect to server...\n";
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
pht('Trying to connect to server...'));
|
||||
|
||||
$conduit = $this->establishConduit()->getConduit();
|
||||
try {
|
||||
$conduit->callMethodSynchronous('conduit.ping', array());
|
||||
} catch (Exception $ex) {
|
||||
throw new ArcanistUsageException(
|
||||
'Failed to connect to server: '.$ex->getMessage());
|
||||
pht(
|
||||
'Failed to connect to server (%s): %s',
|
||||
$uri,
|
||||
$ex->getMessage()));
|
||||
}
|
||||
echo "Connection OK!\n";
|
||||
|
||||
$token_uri = new PhutilURI($uri);
|
||||
$token_uri->setPath('/conduit/token/');
|
||||
|
||||
echo "\n";
|
||||
// Check if this server supports the more modern token-based login.
|
||||
$is_token_auth = false;
|
||||
try {
|
||||
$capabilities = $conduit->callMethodSynchronous(
|
||||
'conduit.getcapabilities',
|
||||
array());
|
||||
$auth = idx($capabilities, 'authentication', array());
|
||||
if (in_array('token', $auth)) {
|
||||
$token_uri->setPath('/conduit/login/');
|
||||
$is_token_auth = true;
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
echo phutil_console_format("**LOGIN TO PHABRICATOR**\n");
|
||||
echo "Open this page in your browser and login to Phabricator if ".
|
||||
"necessary:\n";
|
||||
echo "\n";
|
||||
echo " {$token_uri}\n";
|
||||
echo "\n";
|
||||
echo 'Then paste the token on that page below.';
|
||||
echo 'Then paste the API Token on that page below.';
|
||||
|
||||
|
||||
do {
|
||||
$token = phutil_console_prompt('Paste token from that page:');
|
||||
$token = phutil_console_prompt('Paste API Token from that page:');
|
||||
$token = trim($token);
|
||||
if (strlen($token)) {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
echo "\n";
|
||||
echo "Downloading authentication certificate...\n";
|
||||
$info = $conduit->callMethodSynchronous(
|
||||
'conduit.getcertificate',
|
||||
array(
|
||||
'token' => $token,
|
||||
'host' => $uri,
|
||||
));
|
||||
if ($is_token_auth) {
|
||||
if (strlen($token) != 32) {
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
'The token "%s" is not formatted correctly. API tokens should '.
|
||||
'be 32 characters long. Make sure you visited the correct URI '.
|
||||
'and copy/pasted the token correctly.',
|
||||
$token));
|
||||
}
|
||||
|
||||
$user = $info['username'];
|
||||
echo "Installing certificate for '{$user}'...\n";
|
||||
$config['hosts'][$uri] = array(
|
||||
'user' => $user,
|
||||
'cert' => $info['certificate'],
|
||||
);
|
||||
if (strncmp($token, 'cli-', 4) !== 0) {
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
'The token "%s" is not formatted correctly. Valid API tokens '.
|
||||
'should begin "cli-" and be 32 characters long. Make sure you '.
|
||||
'visited the correct URI and copy/pasted the token correctly.',
|
||||
$token));
|
||||
}
|
||||
|
||||
$conduit->setConduitToken($token);
|
||||
try {
|
||||
$conduit->callMethodSynchronous('user.whoami', array());
|
||||
} catch (Exception $ex) {
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
'The token "%s" is not a valid API Token. The server returned '.
|
||||
'this response when trying to use it as a token: %s',
|
||||
$token,
|
||||
$ex->getMessage()));
|
||||
}
|
||||
|
||||
$config['hosts'][$uri] = array(
|
||||
'token' => $token,
|
||||
);
|
||||
} else {
|
||||
echo "\n";
|
||||
echo "Downloading authentication certificate...\n";
|
||||
$info = $conduit->callMethodSynchronous(
|
||||
'conduit.getcertificate',
|
||||
array(
|
||||
'token' => $token,
|
||||
'host' => $uri,
|
||||
));
|
||||
|
||||
$user = $info['username'];
|
||||
echo "Installing certificate for '{$user}'...\n";
|
||||
$config['hosts'][$uri] = array(
|
||||
'user' => $user,
|
||||
'cert' => $info['certificate'],
|
||||
);
|
||||
}
|
||||
|
||||
echo "Writing ~/.arcrc...\n";
|
||||
$configuration_manager->writeUserConfigurationFile($config);
|
||||
|
||||
echo phutil_console_format(
|
||||
"<bg:green>** SUCCESS! **</bg> Certificate installed.\n");
|
||||
if ($is_token_auth) {
|
||||
echo phutil_console_format(
|
||||
"<bg:green>** SUCCESS! **</bg> API Token installed.\n");
|
||||
} else {
|
||||
echo phutil_console_format(
|
||||
"<bg:green>** SUCCESS! **</bg> Certificate installed.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -324,6 +324,31 @@ abstract class ArcanistWorkflow extends Phobject {
|
|||
'authenticating conduit!');
|
||||
}
|
||||
|
||||
// If we have `token`, this server supports the simpler, new-style
|
||||
// token-based authentication. Use that instead of all the certificate
|
||||
// stuff.
|
||||
if (isset($credentials['token'])) {
|
||||
$conduit = $this->getConduit();
|
||||
|
||||
$conduit->setConduitToken($credentials['token']);
|
||||
|
||||
try {
|
||||
$result = $this->getConduit()->callMethodSynchronous(
|
||||
'user.whoami',
|
||||
array());
|
||||
|
||||
$this->userName = $result['userName'];
|
||||
$this->userPHID = $result['phid'];
|
||||
|
||||
$this->conduitAuthenticated = true;
|
||||
|
||||
return;
|
||||
} catch (Exception $ex) {
|
||||
$conduit->setConduitToken(null);
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($credentials['user'])) {
|
||||
throw new ConduitClientException(
|
||||
'ERR-INVALID-USER',
|
||||
|
@ -351,7 +376,8 @@ abstract class ArcanistWorkflow extends Phobject {
|
|||
));
|
||||
} catch (ConduitClientException $ex) {
|
||||
if ($ex->getErrorCode() == 'ERR-NO-CERTIFICATE' ||
|
||||
$ex->getErrorCode() == 'ERR-INVALID-USER') {
|
||||
$ex->getErrorCode() == 'ERR-INVALID-USER' ||
|
||||
$ex->getErrorCode() == 'ERR-INVALID-AUTH') {
|
||||
$conduit_uri = $this->conduitURI;
|
||||
$message =
|
||||
"\n".
|
||||
|
|
Loading…
Reference in a new issue