mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-30 02:32:42 +01:00
Manage OAuth1 request token secrets in core OAuth1 workflow
Summary: Ref T5096. Ref T4251. See D9202 for discussion. - Twitter seems to accept either one (?!?!?!??). - JIRA uses RSA-SHA1, which does not depend on the token secret. - This change makes Bitbucket work. Test Plan: - OAuthed with Twitter. - OAuthed with JIRA. - OAuthed with some Bitbucket code I had partially laying around in a partial state, which works after this change. Reviewers: csteipp, btrahan, 20after4 Reviewed By: 20after4 Subscribers: epriestley Maniphest Tasks: T4251, T5096 Differential Revision: https://secure.phabricator.com/D9760
This commit is contained in:
parent
3088692a8b
commit
2d36afeaab
2 changed files with 78 additions and 0 deletions
|
@ -9,6 +9,8 @@ abstract class PhabricatorAuthProviderOAuth1
|
||||||
const PROPERTY_CONSUMER_SECRET = 'oauth1:consumer:secret';
|
const PROPERTY_CONSUMER_SECRET = 'oauth1:consumer:secret';
|
||||||
const PROPERTY_PRIVATE_KEY = 'oauth1:private:key';
|
const PROPERTY_PRIVATE_KEY = 'oauth1:private:key';
|
||||||
|
|
||||||
|
const TEMPORARY_TOKEN_TYPE = 'oauth1:request:secret';
|
||||||
|
|
||||||
protected function getIDKey() {
|
protected function getIDKey() {
|
||||||
return self::PROPERTY_CONSUMER_KEY;
|
return self::PROPERTY_CONSUMER_KEY;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +57,11 @@ abstract class PhabricatorAuthProviderOAuth1
|
||||||
$adapter->setCallbackURI($callback_uri);
|
$adapter->setCallbackURI($callback_uri);
|
||||||
|
|
||||||
$uri = $adapter->getClientRedirectURI();
|
$uri = $adapter->getClientRedirectURI();
|
||||||
|
|
||||||
|
$this->saveHandshakeTokenSecret(
|
||||||
|
$client_code,
|
||||||
|
$adapter->getTokenSecret());
|
||||||
|
|
||||||
$response = id(new AphrontRedirectResponse())->setURI($uri);
|
$response = id(new AphrontRedirectResponse())->setURI($uri);
|
||||||
return array($account, $response);
|
return array($account, $response);
|
||||||
}
|
}
|
||||||
|
@ -85,6 +92,10 @@ abstract class PhabricatorAuthProviderOAuth1
|
||||||
$adapter->setToken($token);
|
$adapter->setToken($token);
|
||||||
$adapter->setVerifier($verifier);
|
$adapter->setVerifier($verifier);
|
||||||
|
|
||||||
|
$client_code = $this->getAuthCSRFCode($request);
|
||||||
|
$token_secret = $this->loadHandshakeTokenSecret($client_code);
|
||||||
|
$adapter->setTokenSecret($token_secret);
|
||||||
|
|
||||||
// NOTE: As a side effect, this will cause the OAuth adapter to request
|
// NOTE: As a side effect, this will cause the OAuth adapter to request
|
||||||
// an access token.
|
// an access token.
|
||||||
|
|
||||||
|
@ -197,4 +208,68 @@ abstract class PhabricatorAuthProviderOAuth1
|
||||||
parent::willRenderLinkedAccount($viewer, $item, $account);
|
parent::willRenderLinkedAccount($viewer, $item, $account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Temporary Secrets )-------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
private function saveHandshakeTokenSecret($client_code, $secret) {
|
||||||
|
$key = $this->getHandshakeTokenKeyFromClientCode($client_code);
|
||||||
|
$type = $this->getTemporaryTokenType(self::TEMPORARY_TOKEN_TYPE);
|
||||||
|
|
||||||
|
// Wipe out an existing token, if one exists.
|
||||||
|
$token = id(new PhabricatorAuthTemporaryTokenQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withObjectPHIDs(array($key))
|
||||||
|
->withTokenTypes(array($type))
|
||||||
|
->executeOne();
|
||||||
|
if ($token) {
|
||||||
|
$token->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the new secret.
|
||||||
|
id(new PhabricatorAuthTemporaryToken())
|
||||||
|
->setObjectPHID($key)
|
||||||
|
->setTokenType($type)
|
||||||
|
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
||||||
|
->setTokenCode($secret)
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadHandshakeTokenSecret($client_code) {
|
||||||
|
$key = $this->getHandshakeTokenKeyFromClientCode($client_code);
|
||||||
|
$type = $this->getTemporaryTokenType(self::TEMPORARY_TOKEN_TYPE);
|
||||||
|
|
||||||
|
$token = id(new PhabricatorAuthTemporaryTokenQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withObjectPHIDs(array($key))
|
||||||
|
->withTokenTypes(array($type))
|
||||||
|
->withExpired(false)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if (!$token) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unable to load your OAuth1 token secret from storage. It may '.
|
||||||
|
'have expired. Try authenticating again.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token->getTokenCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTemporaryTokenType($core_type) {
|
||||||
|
// Namespace the type so that multiple providers don't step on each
|
||||||
|
// others' toes if a user starts Mediawiki and Bitbucket auth at the
|
||||||
|
// same time.
|
||||||
|
|
||||||
|
return $core_type.':'.$this->getProviderConfig()->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHandshakeTokenKeyFromClientCode($client_code) {
|
||||||
|
// NOTE: This is very slightly coersive since the TemporaryToken table
|
||||||
|
// expects an "objectPHID" as an identifier, but nothing about the storage
|
||||||
|
// is bound to PHIDs.
|
||||||
|
|
||||||
|
return 'oauth1:secret/'.$client_code;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
|
final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
|
||||||
implements PhabricatorPolicyInterface {
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
|
// TODO: OAuth1 stores a client identifier here, which is not a real PHID.
|
||||||
|
// At some point, we should rename this column to be a little more generic.
|
||||||
protected $objectPHID;
|
protected $objectPHID;
|
||||||
|
|
||||||
protected $tokenType;
|
protected $tokenType;
|
||||||
protected $tokenExpires;
|
protected $tokenExpires;
|
||||||
protected $tokenCode;
|
protected $tokenCode;
|
||||||
|
|
Loading…
Reference in a new issue