mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 17:22:42 +01:00
Allow Phabricator to accept Conduit requests signed with an SSH key
Summary: Ref T4209. Depends on D10402. This updates Conduit to support authenticating calls from other servers by signing the request parameters with the sending server's private key and verifying it with the public key stored in the database. Test Plan: - Made like 500 bad calls using the stuff in D10402. - Made a few valid calls using the stuff in D10402. Reviewers: hach-que, btrahan, #blessed_reviewers Reviewed By: btrahan, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T6240, T4209 Differential Revision: https://secure.phabricator.com/D10401
This commit is contained in:
parent
2ac987714b
commit
657b36dd06
2 changed files with 100 additions and 0 deletions
|
@ -99,4 +99,26 @@ final class PhabricatorAuthSSHPublicKey extends Phobject {
|
||||||
return PhabricatorHash::digestForIndex($body);
|
return PhabricatorHash::digestForIndex($body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEntireKey() {
|
||||||
|
$key = $this->type.' '.$this->body;
|
||||||
|
if (strlen($this->comment)) {
|
||||||
|
$key = $key.' '.$this->comment;
|
||||||
|
}
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toPCKS8() {
|
||||||
|
|
||||||
|
// TODO: Put a cache in front of this.
|
||||||
|
|
||||||
|
$tmp = new TempFile();
|
||||||
|
Filesystem::writeFile($tmp, $this->getEntireKey());
|
||||||
|
list($pem_key) = execx(
|
||||||
|
'ssh-keygen -e -m pcks8 -f %s',
|
||||||
|
$tmp);
|
||||||
|
unset($tmp);
|
||||||
|
|
||||||
|
return $pem_key;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,84 @@ final class PhabricatorConduitAPIController
|
||||||
$request->getUser());
|
$request->getUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$auth_type = idx($metadata, 'auth.type');
|
||||||
|
if ($auth_type === ConduitClient::AUTH_ASYMMETRIC) {
|
||||||
|
$host = idx($metadata, 'auth.host');
|
||||||
|
if (!$host) {
|
||||||
|
return array(
|
||||||
|
'ERR-INVALID-AUTH',
|
||||||
|
pht(
|
||||||
|
'Request is missing required "auth.host" parameter.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Validate that we are the host!
|
||||||
|
|
||||||
|
$raw_key = idx($metadata, 'auth.key');
|
||||||
|
$public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($raw_key);
|
||||||
|
$ssl_public_key = $public_key->toPCKS8();
|
||||||
|
|
||||||
|
// First, verify the signature.
|
||||||
|
try {
|
||||||
|
$protocol_data = $metadata;
|
||||||
|
|
||||||
|
// TODO: We should stop writing this into the protocol data when
|
||||||
|
// processing a request.
|
||||||
|
unset($protocol_data['scope']);
|
||||||
|
|
||||||
|
ConduitClient::verifySignature(
|
||||||
|
$this->method,
|
||||||
|
$api_request->getAllParameters(),
|
||||||
|
$protocol_data,
|
||||||
|
$ssl_public_key);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
return array(
|
||||||
|
'ERR-INVALID-AUTH',
|
||||||
|
pht(
|
||||||
|
'Signature verification failure. %s',
|
||||||
|
$ex->getMessage()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the signature is valid, find the user or device which is
|
||||||
|
// associated with this public key.
|
||||||
|
|
||||||
|
$stored_key = id(new PhabricatorAuthSSHKeyQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withKeys(array($public_key))
|
||||||
|
->executeOne();
|
||||||
|
if (!$stored_key) {
|
||||||
|
return array(
|
||||||
|
'ERR-INVALID-AUTH',
|
||||||
|
pht(
|
||||||
|
'No user or device is associated with that public key.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = $stored_key->getObject();
|
||||||
|
|
||||||
|
if ($object instanceof PhabricatorUser) {
|
||||||
|
$user = $object;
|
||||||
|
} else {
|
||||||
|
throw new Exception(
|
||||||
|
pht('Not Implemented: Would authenticate Almanac device.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->validateAuthenticatedUser(
|
||||||
|
$api_request,
|
||||||
|
$user);
|
||||||
|
} else if ($auth_type === null) {
|
||||||
|
// No specified authentication type, continue with other authentication
|
||||||
|
// methods below.
|
||||||
|
} else {
|
||||||
|
return array(
|
||||||
|
'ERR-INVALID-AUTH',
|
||||||
|
pht(
|
||||||
|
'Provided "auth.type" ("%s") is not recognized.',
|
||||||
|
$auth_type),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// handle oauth
|
// handle oauth
|
||||||
$access_token = $request->getStr('access_token');
|
$access_token = $request->getStr('access_token');
|
||||||
$method_scope = $metadata['scope'];
|
$method_scope = $metadata['scope'];
|
||||||
|
|
Loading…
Reference in a new issue