Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/auth/adapter/PhutilOAuth1AuthAdapter.php
12256 views
1
<?php
2
3
/**
4
* Abstract adapter for OAuth1 providers.
5
*/
6
abstract class PhutilOAuth1AuthAdapter extends PhutilAuthAdapter {
7
8
private $consumerKey;
9
private $consumerSecret;
10
private $token;
11
private $tokenSecret;
12
private $verifier;
13
private $handshakeData;
14
private $callbackURI;
15
private $privateKey;
16
17
public function setPrivateKey(PhutilOpaqueEnvelope $private_key) {
18
$this->privateKey = $private_key;
19
return $this;
20
}
21
22
public function getPrivateKey() {
23
return $this->privateKey;
24
}
25
26
public function setCallbackURI($callback_uri) {
27
$this->callbackURI = $callback_uri;
28
return $this;
29
}
30
31
public function getCallbackURI() {
32
return $this->callbackURI;
33
}
34
35
public function setVerifier($verifier) {
36
$this->verifier = $verifier;
37
return $this;
38
}
39
40
public function getVerifier() {
41
return $this->verifier;
42
}
43
44
public function setConsumerSecret(PhutilOpaqueEnvelope $consumer_secret) {
45
$this->consumerSecret = $consumer_secret;
46
return $this;
47
}
48
49
public function getConsumerSecret() {
50
return $this->consumerSecret;
51
}
52
53
public function setConsumerKey($consumer_key) {
54
$this->consumerKey = $consumer_key;
55
return $this;
56
}
57
58
public function getConsumerKey() {
59
return $this->consumerKey;
60
}
61
62
public function setTokenSecret($token_secret) {
63
$this->tokenSecret = $token_secret;
64
return $this;
65
}
66
67
public function getTokenSecret() {
68
return $this->tokenSecret;
69
}
70
71
public function setToken($token) {
72
$this->token = $token;
73
return $this;
74
}
75
76
public function getToken() {
77
return $this->token;
78
}
79
80
protected function getHandshakeData() {
81
if ($this->handshakeData === null) {
82
$this->finishOAuthHandshake();
83
}
84
return $this->handshakeData;
85
}
86
87
abstract protected function getRequestTokenURI();
88
abstract protected function getAuthorizeTokenURI();
89
abstract protected function getValidateTokenURI();
90
91
protected function getSignatureMethod() {
92
return 'HMAC-SHA1';
93
}
94
95
public function getContentSecurityPolicyFormActions() {
96
return array(
97
$this->getAuthorizeTokenURI(),
98
);
99
}
100
101
protected function newOAuth1Future($uri, $data = array()) {
102
$future = id(new PhutilOAuth1Future($uri, $data))
103
->setMethod('POST')
104
->setSignatureMethod($this->getSignatureMethod());
105
106
$consumer_key = $this->getConsumerKey();
107
if (strlen($consumer_key)) {
108
$future->setConsumerKey($consumer_key);
109
} else {
110
throw new Exception(
111
pht(
112
'%s is required!',
113
'setConsumerKey()'));
114
}
115
116
$consumer_secret = $this->getConsumerSecret();
117
if ($consumer_secret) {
118
$future->setConsumerSecret($consumer_secret);
119
}
120
121
if (strlen($this->getToken())) {
122
$future->setToken($this->getToken());
123
}
124
125
if (strlen($this->getTokenSecret())) {
126
$future->setTokenSecret($this->getTokenSecret());
127
}
128
129
if ($this->getPrivateKey()) {
130
$future->setPrivateKey($this->getPrivateKey());
131
}
132
133
return $future;
134
}
135
136
public function getClientRedirectURI() {
137
$request_token_uri = $this->getRequestTokenURI();
138
139
$future = $this->newOAuth1Future($request_token_uri);
140
if (strlen($this->getCallbackURI())) {
141
$future->setCallbackURI($this->getCallbackURI());
142
}
143
144
list($body) = $future->resolvex();
145
$data = id(new PhutilQueryStringParser())->parseQueryString($body);
146
147
// NOTE: Per the spec, this value MUST be the string 'true'.
148
$confirmed = idx($data, 'oauth_callback_confirmed');
149
if ($confirmed !== 'true') {
150
throw new Exception(
151
pht("Expected '%s' to be '%s'!", 'oauth_callback_confirmed', 'true'));
152
}
153
154
$this->readTokenAndTokenSecret($data);
155
156
$authorize_token_uri = new PhutilURI($this->getAuthorizeTokenURI());
157
$authorize_token_uri->replaceQueryParam('oauth_token', $this->getToken());
158
159
return phutil_string_cast($authorize_token_uri);
160
}
161
162
protected function finishOAuthHandshake() {
163
$this->willFinishOAuthHandshake();
164
165
if (!$this->getToken()) {
166
throw new Exception(pht('Expected token to finish OAuth handshake!'));
167
}
168
if (!$this->getVerifier()) {
169
throw new Exception(pht('Expected verifier to finish OAuth handshake!'));
170
}
171
172
$validate_uri = $this->getValidateTokenURI();
173
$params = array(
174
'oauth_verifier' => $this->getVerifier(),
175
);
176
177
list($body) = $this->newOAuth1Future($validate_uri, $params)->resolvex();
178
$data = id(new PhutilQueryStringParser())->parseQueryString($body);
179
180
$this->readTokenAndTokenSecret($data);
181
182
$this->handshakeData = $data;
183
}
184
185
private function readTokenAndTokenSecret(array $data) {
186
$token = idx($data, 'oauth_token');
187
if (!$token) {
188
throw new Exception(pht("Expected '%s' in response!", 'oauth_token'));
189
}
190
191
$token_secret = idx($data, 'oauth_token_secret');
192
if (!$token_secret) {
193
throw new Exception(
194
pht("Expected '%s' in response!", 'oauth_token_secret'));
195
}
196
197
$this->setToken($token);
198
$this->setTokenSecret($token_secret);
199
200
return $this;
201
}
202
203
/**
204
* Hook that allows subclasses to take actions before the OAuth handshake
205
* is completed.
206
*/
207
protected function willFinishOAuthHandshake() {
208
return;
209
}
210
211
}
212
213