-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathoauth-validator.php
432 lines (386 loc) · 10.9 KB
/
oauth-validator.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
<?php
namespace Jublo;
/**
* A library for validating OAuth signatures in PHP.
*
* @package oauth-validator
* @version 1.0.1
* @author Jublo Solutions <[email protected]>
* @copyright 2014 Jublo Solutions <[email protected]>
* @license http://opensource.org/licenses/GPL-3.0 GNU General Public License 3.0
* @link https://github.com/jublonet/oauth-validator-php
*/
/**
* A library for validating OAuth signatures in PHP.
*
* @package oauth-validator
* @subpackage oauth-validator-php
*/
class Oauth_Validator
{
/**
* The current singleton instance
*/
private static $_instance = null;
/**
* The OAuth consumer key of your registered app
*/
protected static $_oauth_consumer_key = null;
/**
* The corresponding consumer secret
*/
protected static $_oauth_consumer_secret = null;
/**
* The Request or access token. Used to sign requests
*/
protected $_oauth_token = null;
/**
* The corresponding request or access token secret
*/
protected $_oauth_token_secret = null;
/**
* The current OAuth Validator version
*/
protected $_version = '1.0.1';
/**
* Returns singleton class instance
* Always use this method unless you're working with multiple authenticated users at once
*
* @return Codebird The instance
*/
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self;
}
return self::$_instance;
}
/**
* Sets the OAuth consumer key and secret (App key)
*
* @param string $key OAuth consumer key
* @param string $secret OAuth consumer secret
*
* @return void
*/
public static function setConsumerKey($key, $secret)
{
self::$_oauth_consumer_key = $key;
self::$_oauth_consumer_secret = $secret;
}
/**
* Gets the current OAuth validator version
*
* @return string The version number
*/
public function getVersion()
{
return $this->_version;
}
/**
* Sets the OAuth request or access token and secret (User key)
*
* @param string $token OAuth request or access token
* @param string $secret OAuth request or access token secret
*
* @return void
*/
public function setToken($token, $secret)
{
$this->_oauth_token = $token;
$this->_oauth_token_secret = $secret;
}
/**
* Validate OAuth signature of an API call
*
* @param string $authorization Signature to validate
* @param string $httpmethod HTTP method used for making the request
* @param string $url API URL called
* @param array $params Parameters sent along
* @param bool $multipart Whether multipart/form-data was used
*
* @return bool $is_valid_signature
*/
public function validate(
$authorization, $httpmethod, $url, $params = array(), $multipart = false
)
{
// parse parameters
$apiparams = $this->_parseApiParams($params);
// stringify null and boolean parameters
$apiparams = $this->_stringifyNullBoolParams($apiparams);
// check whether OAuth was used
if (! is_string($authorization) || substr($authorization, 0, 6) !== 'OAuth ') {
trigger_error('Invalid authorization string supplied.');
return false;
}
// split authorization parameters
$authorization_params = $this->splitAuthorizationParams($authorization);
// check for required OAuth parameters
if (! $this->_checkAuthorizationParams($authorization_params)) {
return false;
}
// extract timestamp and nonce from authorization
$timestamp = $authorization_params['timestamp'];
$nonce = $authorization_params['nonce'];
$correct_authorization = null;
if ($httpmethod === 'GET' || ! $multipart) {
$correct_authorization = $this->_sign(
$httpmethod, $url, $params, $timestamp, $nonce
);
} else {
$correct_authorization = $this->_sign(
$httpmethod, $url, array(), $timestamp, $nonce
);
}
return $correct_authorization === $authorization;
}
/**
* Split authorization string into parameters array
*
* @param string $authorization OAuth authorization string
*
* @return array $authorization_params
*/
public function splitAuthorizationParams($authorization)
{
$authorization_params = array();
$authorization = substr($authorization, 6);
$temp = explode(', ', $authorization);
if (! is_array($temp)) {
return $authorization_params;
}
for ($i = 0; $i < count($temp); $i++) {
$param = explode('=', $temp[$i], 2);
if (! is_array($param) || count($param) < 2) {
continue;
}
list ($key, $value) = $param;
// strip "oauth_" prefix
if (substr($key, 0, 6) === 'oauth_') {
$key = substr($key, 6);
}
if (substr($value, 0, 1) === '"'
&& substr($value, -1) === '"'
) {
$value = substr($value, 1, strlen($value) - 2);
}
$authorization_params[$key] = $value;
}
return $authorization_params;
}
/**
* Parse given params, detect query-style params
*
* @param array|string $params Parameters to parse
*
* @return array $apiparams
*/
protected function _parseApiParams($params)
{
$apiparams = array();
if (count($params) === 0) {
return $apiparams;
}
if (is_array($params)) {
// given parameters are array
return $params;
}
// user gave us query-style params
parse_str($params[0], $apiparams);
if (! is_array($apiparams)) {
$apiparams = array();
}
if (! get_magic_quotes_gpc()) {
return $apiparams;
}
// remove auto-added slashes recursively if on magic quotes steroids
foreach($apiparams as $key => $value) {
if (is_array($value)) {
$apiparams[$key] = array_map('stripslashes', $value);
} else {
$apiparams[$key] = stripslashes($value);
}
}
return $apiparams;
}
/**
* Replace null and boolean parameters with their string representations
*
* @param array $apiparams Parameter array to replace in
*
* @return array $apiparams
*/
protected function _stringifyNullBoolParams($apiparams)
{
foreach ($apiparams as $key => $value) {
if (! is_scalar($value)) {
// no need to try replacing arrays
continue;
}
if (is_null($value)) {
$apiparams[$key] = 'null';
} elseif (is_bool($value)) {
$apiparams[$key] = $value ? 'true' : 'false';
}
}
return $apiparams;
}
/**
* Check for required OAuth authorization parameters
*
* @param array $authorization_params Param array to check
*
* @return bool $is_valid Whether all required parameters are present
*/
protected function _checkAuthorizationParams($authorization_params)
{
static $required_params = array(
'consumer_key', 'nonce', 'signature', 'signature_method',
'timestamp', 'version'
);
$keys = array_keys($authorization_params);
foreach ($required_params as $param) {
if (! in_array($param, $keys)) {
trigger_error(
'Required authorization parameter missing: '
. $param . '.'
);
return false;
}
}
// check for details
if ($authorization_params['signature_method'] !== 'HMAC-SHA1') {
trigger_error('OAuth signature method must be HMAC-SHA1.');
return false;
}
$time_difference = abs(time() - $authorization_params['timestamp']);
if ($time_difference > 180) {
trigger_error(
'Too much difference between client and server time ('
. $time_difference . ' seconds).'
);
return false;
}
if ($authorization_params['version'] !== '1.0') {
trigger_error('OAuth version must be 1.0.');
return false;
}
return true;
}
/**
* Signing helpers
*/
/**
* URL-encodes the given data
*
* @param mixed $data
*
* @return mixed The encoded data
*/
protected function _url($data)
{
if (is_array($data)) {
return array_map(array(
$this,
'_url'
), $data);
} elseif (is_scalar($data)) {
return str_replace(array(
'+',
'!',
'*',
"'",
'(',
')'
), array(
' ',
'%21',
'%2A',
'%27',
'%28',
'%29'
), rawurlencode($data));
} else {
return '';
}
}
/**
* Gets the base64-encoded SHA1 hash for the given data
*
* @param string $data The data to calculate the hash from
*
* @return string The hash
*/
protected function _sha1($data)
{
if (self::$_oauth_consumer_secret === null) {
throw new \Exception('To generate a hash, the consumer secret must be set.');
}
if (!function_exists('hash_hmac')) {
throw new \Exception('To generate a hash, the PHP hash extension must be available.');
}
return base64_encode(hash_hmac(
'sha1',
$data,
self::$_oauth_consumer_secret
. '&'
. ($this->_oauth_token_secret != null
? $this->_oauth_token_secret
: ''
),
true
));
}
/**
* Generates an OAuth signature
*
* @param string $httpmethod Usually either 'GET' or 'POST' or 'DELETE'
* @param string $method API method to call
* @param array $params API call parameters, associative
* @param int $timestamp Authorization timestamp
* @param string $nonce Nonce used
*
* @return string Authorization HTTP header
*/
protected function _sign($httpmethod, $method, $params, $timestamp, $nonce)
{
if (self::$_oauth_consumer_key === null) {
throw new \Exception('To generate a signature, the consumer key must be set.');
}
$sign_params = array(
'consumer_key' => self::$_oauth_consumer_key,
'version' => '1.0',
'timestamp' => $timestamp,
'nonce' => $nonce,
'signature_method' => 'HMAC-SHA1'
);
$sign_base_params = array();
foreach ($sign_params as $key => $value) {
$sign_base_params['oauth_' . $key] = $this->_url($value);
}
if ($this->_oauth_token != null) {
$sign_base_params['oauth_token'] = $this->_url($this->_oauth_token);
}
$oauth_params = $sign_base_params;
foreach ($params as $key => $value) {
$sign_base_params[$key] = $this->_url($value);
}
ksort($sign_base_params);
$sign_base_string = '';
foreach ($sign_base_params as $key => $value) {
$sign_base_string .= $key . '=' . $value . '&';
}
$sign_base_string = substr($sign_base_string, 0, -1);
$signature = $this->_sha1($httpmethod . '&' . $this->_url($method) . '&' . $this->_url($sign_base_string));
$params = $oauth_params;
$params['oauth_signature'] = $signature;
$keys = $params;
ksort($keys);
$authorization = 'OAuth ';
foreach ($keys as $key => $value) {
$authorization .= $key . "=\"" . $this->_url($value) . "\", ";
}
return substr($authorization, 0, -2);
}
}