Path: blob/master/src/applications/auth/adapter/PhutilOAuth1AuthAdapter.php
12256 views
<?php12/**3* Abstract adapter for OAuth1 providers.4*/5abstract class PhutilOAuth1AuthAdapter extends PhutilAuthAdapter {67private $consumerKey;8private $consumerSecret;9private $token;10private $tokenSecret;11private $verifier;12private $handshakeData;13private $callbackURI;14private $privateKey;1516public function setPrivateKey(PhutilOpaqueEnvelope $private_key) {17$this->privateKey = $private_key;18return $this;19}2021public function getPrivateKey() {22return $this->privateKey;23}2425public function setCallbackURI($callback_uri) {26$this->callbackURI = $callback_uri;27return $this;28}2930public function getCallbackURI() {31return $this->callbackURI;32}3334public function setVerifier($verifier) {35$this->verifier = $verifier;36return $this;37}3839public function getVerifier() {40return $this->verifier;41}4243public function setConsumerSecret(PhutilOpaqueEnvelope $consumer_secret) {44$this->consumerSecret = $consumer_secret;45return $this;46}4748public function getConsumerSecret() {49return $this->consumerSecret;50}5152public function setConsumerKey($consumer_key) {53$this->consumerKey = $consumer_key;54return $this;55}5657public function getConsumerKey() {58return $this->consumerKey;59}6061public function setTokenSecret($token_secret) {62$this->tokenSecret = $token_secret;63return $this;64}6566public function getTokenSecret() {67return $this->tokenSecret;68}6970public function setToken($token) {71$this->token = $token;72return $this;73}7475public function getToken() {76return $this->token;77}7879protected function getHandshakeData() {80if ($this->handshakeData === null) {81$this->finishOAuthHandshake();82}83return $this->handshakeData;84}8586abstract protected function getRequestTokenURI();87abstract protected function getAuthorizeTokenURI();88abstract protected function getValidateTokenURI();8990protected function getSignatureMethod() {91return 'HMAC-SHA1';92}9394public function getContentSecurityPolicyFormActions() {95return array(96$this->getAuthorizeTokenURI(),97);98}99100protected function newOAuth1Future($uri, $data = array()) {101$future = id(new PhutilOAuth1Future($uri, $data))102->setMethod('POST')103->setSignatureMethod($this->getSignatureMethod());104105$consumer_key = $this->getConsumerKey();106if (strlen($consumer_key)) {107$future->setConsumerKey($consumer_key);108} else {109throw new Exception(110pht(111'%s is required!',112'setConsumerKey()'));113}114115$consumer_secret = $this->getConsumerSecret();116if ($consumer_secret) {117$future->setConsumerSecret($consumer_secret);118}119120if (strlen($this->getToken())) {121$future->setToken($this->getToken());122}123124if (strlen($this->getTokenSecret())) {125$future->setTokenSecret($this->getTokenSecret());126}127128if ($this->getPrivateKey()) {129$future->setPrivateKey($this->getPrivateKey());130}131132return $future;133}134135public function getClientRedirectURI() {136$request_token_uri = $this->getRequestTokenURI();137138$future = $this->newOAuth1Future($request_token_uri);139if (strlen($this->getCallbackURI())) {140$future->setCallbackURI($this->getCallbackURI());141}142143list($body) = $future->resolvex();144$data = id(new PhutilQueryStringParser())->parseQueryString($body);145146// NOTE: Per the spec, this value MUST be the string 'true'.147$confirmed = idx($data, 'oauth_callback_confirmed');148if ($confirmed !== 'true') {149throw new Exception(150pht("Expected '%s' to be '%s'!", 'oauth_callback_confirmed', 'true'));151}152153$this->readTokenAndTokenSecret($data);154155$authorize_token_uri = new PhutilURI($this->getAuthorizeTokenURI());156$authorize_token_uri->replaceQueryParam('oauth_token', $this->getToken());157158return phutil_string_cast($authorize_token_uri);159}160161protected function finishOAuthHandshake() {162$this->willFinishOAuthHandshake();163164if (!$this->getToken()) {165throw new Exception(pht('Expected token to finish OAuth handshake!'));166}167if (!$this->getVerifier()) {168throw new Exception(pht('Expected verifier to finish OAuth handshake!'));169}170171$validate_uri = $this->getValidateTokenURI();172$params = array(173'oauth_verifier' => $this->getVerifier(),174);175176list($body) = $this->newOAuth1Future($validate_uri, $params)->resolvex();177$data = id(new PhutilQueryStringParser())->parseQueryString($body);178179$this->readTokenAndTokenSecret($data);180181$this->handshakeData = $data;182}183184private function readTokenAndTokenSecret(array $data) {185$token = idx($data, 'oauth_token');186if (!$token) {187throw new Exception(pht("Expected '%s' in response!", 'oauth_token'));188}189190$token_secret = idx($data, 'oauth_token_secret');191if (!$token_secret) {192throw new Exception(193pht("Expected '%s' in response!", 'oauth_token_secret'));194}195196$this->setToken($token);197$this->setTokenSecret($token_secret);198199return $this;200}201202/**203* Hook that allows subclasses to take actions before the OAuth handshake204* is completed.205*/206protected function willFinishOAuthHandshake() {207return;208}209210}211212213