mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 05:50:55 +01:00
Add a Duo API future
Summary: Depends on D20025. Ref T13231. Although I'm not currently planning to actually upstream a Duo MFA provider, it's probably easiest to put most of the support pieces in the upstream until T5055. Test Plan: Used a test script to make some (mostly trivial) API calls and got valid results back, so I think the parameter signing is correct. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13231 Differential Revision: https://secure.phabricator.com/D20026
This commit is contained in:
parent
98c4cdc5be
commit
069160404f
3 changed files with 153 additions and 1 deletions
|
@ -2983,6 +2983,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDraftEngine' => 'applications/transactions/draft/PhabricatorDraftEngine.php',
|
||||
'PhabricatorDraftInterface' => 'applications/transactions/draft/PhabricatorDraftInterface.php',
|
||||
'PhabricatorDrydockApplication' => 'applications/drydock/application/PhabricatorDrydockApplication.php',
|
||||
'PhabricatorDuoFuture' => 'applications/auth/future/PhabricatorDuoFuture.php',
|
||||
'PhabricatorEdgeChangeRecord' => 'infrastructure/edges/util/PhabricatorEdgeChangeRecord.php',
|
||||
'PhabricatorEdgeChangeRecordTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeChangeRecordTestCase.php',
|
||||
'PhabricatorEdgeConfig' => 'infrastructure/edges/constants/PhabricatorEdgeConfig.php',
|
||||
|
@ -8829,6 +8830,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorDraftEngine' => 'Phobject',
|
||||
'PhabricatorDrydockApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorDuoFuture' => 'FutureProxy',
|
||||
'PhabricatorEdgeChangeRecord' => 'Phobject',
|
||||
'PhabricatorEdgeChangeRecordTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants',
|
||||
|
|
150
src/applications/auth/future/PhabricatorDuoFuture.php
Normal file
150
src/applications/auth/future/PhabricatorDuoFuture.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDuoFuture
|
||||
extends FutureProxy {
|
||||
|
||||
private $future;
|
||||
|
||||
private $integrationKey;
|
||||
private $secretKey;
|
||||
private $apiHostname;
|
||||
|
||||
private $httpMethod = 'POST';
|
||||
private $method;
|
||||
private $parameters;
|
||||
private $timeout;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(null);
|
||||
}
|
||||
|
||||
public function setIntegrationKey($integration_key) {
|
||||
$this->integrationKey = $integration_key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSecretKey(PhutilOpaqueEnvelope $key) {
|
||||
$this->secretKey = $key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAPIHostname($hostname) {
|
||||
$this->apiHostname = $hostname;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMethod($method, array $parameters) {
|
||||
$this->method = $method;
|
||||
$this->parameters = $parameters;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTimeout($timeout) {
|
||||
$this->timeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimeout() {
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
public function setHTTPMethod($method) {
|
||||
$this->httpMethod = $method;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHTTPMethod() {
|
||||
return $this->httpMethod;
|
||||
}
|
||||
|
||||
protected function getProxiedFuture() {
|
||||
if (!$this->future) {
|
||||
if ($this->integrationKey === null) {
|
||||
throw new PhutilInvalidStateException('setIntegrationKey');
|
||||
}
|
||||
|
||||
if ($this->secretKey === null) {
|
||||
throw new PhutilInvalidStateException('setSecretKey');
|
||||
}
|
||||
|
||||
if ($this->apiHostname === null) {
|
||||
throw new PhutilInvalidStateException('setAPIHostname');
|
||||
}
|
||||
|
||||
if ($this->method === null || $this->parameters === null) {
|
||||
throw new PhutilInvalidStateException('setMethod');
|
||||
}
|
||||
|
||||
$path = (string)urisprintf('/auth/v2/%s', $this->method);
|
||||
|
||||
$host = $this->apiHostname;
|
||||
$host = phutil_utf8_strtolower($host);
|
||||
|
||||
$uri = id(new PhutilURI(''))
|
||||
->setProtocol('https')
|
||||
->setDomain($host)
|
||||
->setPath($path);
|
||||
|
||||
$data = $this->parameters;
|
||||
$date = date('r');
|
||||
|
||||
$http_method = $this->getHTTPMethod();
|
||||
|
||||
ksort($data);
|
||||
$data_parts = array();
|
||||
foreach ($data as $key => $value) {
|
||||
$data_parts[] = rawurlencode($key).'='.rawurlencode($value);
|
||||
}
|
||||
$data_parts = implode('&', $data_parts);
|
||||
|
||||
$corpus = array(
|
||||
$date,
|
||||
$http_method,
|
||||
$host,
|
||||
$path,
|
||||
$data_parts,
|
||||
);
|
||||
$corpus = implode("\n", $corpus);
|
||||
|
||||
$signature = hash_hmac(
|
||||
'sha1',
|
||||
$corpus,
|
||||
$this->secretKey->openEnvelope());
|
||||
$signature = new PhutilOpaqueEnvelope($signature);
|
||||
|
||||
$future = id(new HTTPSFuture($uri, $data))
|
||||
->setHTTPBasicAuthCredentials($this->integrationKey, $signature)
|
||||
->setMethod($http_method)
|
||||
->addHeader('Accept', 'application/json')
|
||||
->addHeader('Date', $date);
|
||||
|
||||
$timeout = $this->getTimeout();
|
||||
if ($timeout) {
|
||||
$future->setTimeout($timeout);
|
||||
}
|
||||
|
||||
$this->future = $future;
|
||||
}
|
||||
|
||||
return $this->future;
|
||||
}
|
||||
|
||||
protected function didReceiveResult($result) {
|
||||
list($status, $body, $headers) = $result;
|
||||
|
||||
if ($status->isError()) {
|
||||
throw $status;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = phutil_json_decode($body);
|
||||
} catch (PhutilJSONParserException $ex) {
|
||||
throw new PhutilProxyException(
|
||||
pht('Expected JSON response from Duo.'),
|
||||
$ex);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
|
@ -58,7 +58,7 @@ final class PhabricatorTwilioFuture extends FutureProxy {
|
|||
$this->accountSID,
|
||||
$this->method);
|
||||
|
||||
$uri = id(new PhutilURI('https://api.twilio.com/2010-04-01/accounts/'))
|
||||
$uri = id(new PhutilURI('https://api.twilio.com/'))
|
||||
->setPath($path);
|
||||
|
||||
$data = $this->parameters;
|
||||
|
|
Loading…
Reference in a new issue