Commit | Line | Data |
---|---|---|
3e123368 | 1 | <?php |
3e123368 DC |
2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
469fb5d6 DP |
17 | |
18 | defined('MOODLE_INTERNAL') || die(); | |
19 | ||
20 | require_once($CFG->libdir.'/filelib.php'); | |
21 | ||
3e123368 DC |
22 | /** |
23 | * OAuth helper class | |
24 | * | |
25 | * 1. You can extends oauth_helper to add specific functions, such as twitter extends oauth_helper | |
26 | * 2. Call request_token method to get oauth_token and oauth_token_secret, and redirect user to authorize_url, | |
27 | * developer needs to store oauth_token and oauth_token_secret somewhere, we will use them to request | |
28 | * access token later on | |
29 | * 3. User approved the request, and get back to moodle | |
30 | * 4. Call get_access_token, it takes previous oauth_token and oauth_token_secret as arguments, oauth_token | |
31 | * will be used in OAuth request, oauth_token_secret will be used to bulid signature, this method will | |
32 | * return access_token and access_secret, store these two values in database or session | |
33 | * 5. Now you can access oauth protected resources by access_token and access_secret using oauth_helper::request | |
34 | * method (or get() post()) | |
35 | * | |
36 | * Note: | |
37 | * 1. This class only support HMAC-SHA1 | |
38 | * 2. oauth_helper class don't store tokens and secrets, you must store them manually | |
39 | * 3. Some functions are based on http://code.google.com/p/oauth/ | |
40 | * | |
41 | * @package moodlecore | |
42 | * @copyright 2010 Dongsheng Cai <dongsheng@moodle.com> | |
43 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
44 | */ | |
45 | ||
46 | class oauth_helper { | |
47 | /** @var string consumer key, issued by oauth provider*/ | |
48 | protected $consumer_key; | |
49 | /** @var string consumer secret, issued by oauth provider*/ | |
50 | protected $consumer_secret; | |
51 | /** @var string oauth root*/ | |
52 | protected $api_root; | |
53 | /** @var string request token url*/ | |
54 | protected $request_token_api; | |
55 | /** @var string authorize url*/ | |
56 | protected $authorize_url; | |
57 | protected $http_method; | |
58 | /** @var string */ | |
59 | protected $access_token_api; | |
60 | /** @var curl */ | |
61 | protected $http; | |
8d8a6009 MG |
62 | /** @var array options to pass to the next curl request */ |
63 | protected $http_options; | |
3e123368 DC |
64 | |
65 | /** | |
66 | * Contructor for oauth_helper. | |
67 | * Subclass can override construct to build its own $this->http | |
68 | * | |
69 | * @param array $args requires at least three keys, oauth_consumer_key | |
70 | * oauth_consumer_secret and api_root, oauth_helper will | |
71 | * guess request_token_api, authrize_url and access_token_api | |
72 | * based on api_root, but it not always works | |
73 | */ | |
74 | function __construct($args) { | |
75 | if (!empty($args['api_root'])) { | |
76 | $this->api_root = $args['api_root']; | |
77 | } else { | |
78 | $this->api_root = ''; | |
79 | } | |
80 | $this->consumer_key = $args['oauth_consumer_key']; | |
81 | $this->consumer_secret = $args['oauth_consumer_secret']; | |
82 | ||
83 | if (empty($args['request_token_api'])) { | |
84 | $this->request_token_api = $this->api_root . '/request_token'; | |
85 | } else { | |
86 | $this->request_token_api = $args['request_token_api']; | |
87 | } | |
88 | ||
89 | if (empty($args['authorize_url'])) { | |
90 | $this->authorize_url = $this->api_root . '/authorize'; | |
91 | } else { | |
92 | $this->authorize_url = $args['authorize_url']; | |
93 | } | |
94 | ||
95 | if (empty($args['access_token_api'])) { | |
96 | $this->access_token_api = $this->api_root . '/access_token'; | |
97 | } else { | |
98 | $this->access_token_api = $args['access_token_api']; | |
99 | } | |
100 | ||
101 | if (!empty($args['oauth_callback'])) { | |
102 | $this->oauth_callback = new moodle_url($args['oauth_callback']); | |
103 | } | |
104 | if (!empty($args['access_token'])) { | |
105 | $this->access_token = $args['access_token']; | |
106 | } | |
107 | if (!empty($args['access_token_secret'])) { | |
108 | $this->access_token_secret = $args['access_token_secret']; | |
109 | } | |
110 | $this->http = new curl(array('debug'=>false)); | |
8d8a6009 | 111 | $this->http_options = array(); |
3e123368 DC |
112 | } |
113 | ||
114 | /** | |
115 | * Build parameters list: | |
116 | * oauth_consumer_key="0685bd9184jfhq22", | |
117 | * oauth_nonce="4572616e48616d6d65724c61686176", | |
118 | * oauth_token="ad180jjd733klru7", | |
119 | * oauth_signature_method="HMAC-SHA1", | |
120 | * oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", | |
121 | * oauth_timestamp="137131200", | |
122 | * oauth_version="1.0" | |
123 | * oauth_verifier="1.0" | |
124 | * @param array $param | |
125 | * @return string | |
126 | */ | |
127 | function get_signable_parameters($params){ | |
128 | $sorted = $params; | |
129 | ksort($sorted); | |
130 | ||
131 | $total = array(); | |
132 | foreach ($sorted as $k => $v) { | |
133 | if ($k == 'oauth_signature') { | |
134 | continue; | |
135 | } | |
136 | ||
137 | $total[] = rawurlencode($k) . '=' . rawurlencode($v); | |
138 | } | |
139 | return implode('&', $total); | |
140 | } | |
141 | ||
142 | /** | |
143 | * Create signature for oauth request | |
144 | * @param string $url | |
145 | * @param string $secret | |
146 | * @param array $params | |
147 | * @return string | |
148 | */ | |
149 | public function sign($http_method, $url, $params, $secret) { | |
150 | $sig = array( | |
151 | strtoupper($http_method), | |
152 | preg_replace('/%7E/', '~', rawurlencode($url)), | |
153 | rawurlencode($this->get_signable_parameters($params)), | |
154 | ); | |
155 | ||
156 | $base_string = implode('&', $sig); | |
157 | $sig = base64_encode(hash_hmac('sha1', $base_string, $secret, true)); | |
158 | return $sig; | |
159 | } | |
160 | ||
161 | /** | |
162 | * Initilize oauth request parameters, including: | |
163 | * oauth_consumer_key="0685bd9184jfhq22", | |
164 | * oauth_token="ad180jjd733klru7", | |
165 | * oauth_signature_method="HMAC-SHA1", | |
166 | * oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", | |
167 | * oauth_timestamp="137131200", | |
168 | * oauth_nonce="4572616e48616d6d65724c61686176", | |
169 | * oauth_version="1.0" | |
170 | * To access protected resources, oauth_token should be defined | |
171 | * | |
172 | * @param string $url | |
173 | * @param string $token | |
174 | * @param string $http_method | |
175 | * @return array | |
176 | */ | |
177 | public function prepare_oauth_parameters($url, $params, $http_method = 'POST') { | |
178 | if (is_array($params)) { | |
179 | $oauth_params = $params; | |
180 | } else { | |
181 | $oauth_params = array(); | |
182 | } | |
183 | $oauth_params['oauth_version'] = '1.0'; | |
184 | $oauth_params['oauth_nonce'] = $this->get_nonce(); | |
185 | $oauth_params['oauth_timestamp'] = $this->get_timestamp(); | |
186 | $oauth_params['oauth_consumer_key'] = $this->consumer_key; | |
187 | if (!empty($this->oauth_callback)) { | |
188 | $oauth_params['oauth_callback'] = $this->oauth_callback->out(false); | |
189 | } | |
190 | $oauth_params['oauth_signature_method'] = 'HMAC-SHA1'; | |
191 | $oauth_params['oauth_signature'] = $this->sign($http_method, $url, $oauth_params, $this->sign_secret); | |
192 | return $oauth_params; | |
193 | } | |
194 | ||
195 | public function setup_oauth_http_header($params) { | |
196 | ||
197 | $total = array(); | |
198 | ksort($params); | |
199 | foreach ($params as $k => $v) { | |
200 | $total[] = rawurlencode($k) . '="' . rawurlencode($v).'"'; | |
201 | } | |
202 | $str = implode(', ', $total); | |
203 | $str = 'Authorization: OAuth '.$str; | |
204 | $this->http->setHeader('Expect:'); | |
205 | $this->http->setHeader($str); | |
206 | } | |
207 | ||
8d8a6009 MG |
208 | /** |
209 | * Sets the options for the next curl request | |
210 | * | |
211 | * @param array $options | |
212 | */ | |
213 | public function setup_oauth_http_options($options) { | |
214 | $this->http_options = $options; | |
215 | } | |
216 | ||
3e123368 DC |
217 | /** |
218 | * Request token for authentication | |
219 | * This is the first step to use OAuth, it will return oauth_token and oauth_token_secret | |
220 | * @return array | |
221 | */ | |
222 | public function request_token() { | |
223 | $this->sign_secret = $this->consumer_secret.'&'; | |
224 | $params = $this->prepare_oauth_parameters($this->request_token_api, array(), 'GET'); | |
8d8a6009 | 225 | $content = $this->http->get($this->request_token_api, $params, $this->http_options); |
3e123368 DC |
226 | // Including: |
227 | // oauth_token | |
228 | // oauth_token_secret | |
229 | $result = $this->parse_result($content); | |
230 | if (empty($result['oauth_token'])) { | |
0e6ee5e9 | 231 | throw new moodle_exception('Error while requesting an oauth token'); |
3e123368 DC |
232 | } |
233 | // build oauth authrize url | |
234 | if (!empty($this->oauth_callback)) { | |
235 | // url must be rawurlencode | |
236 | $result['authorize_url'] = $this->authorize_url . '?oauth_token='.$result['oauth_token'].'&oauth_callback='.rawurlencode($this->oauth_callback->out(false)); | |
237 | } else { | |
238 | // no callback | |
239 | $result['authorize_url'] = $this->authorize_url . '?oauth_token='.$result['oauth_token']; | |
240 | } | |
241 | return $result; | |
242 | } | |
243 | ||
244 | /** | |
245 | * Set oauth access token for oauth request | |
246 | * @param string $token | |
247 | * @param string $secret | |
248 | */ | |
249 | public function set_access_token($token, $secret) { | |
250 | $this->access_token = $token; | |
251 | $this->access_token_secret = $secret; | |
252 | } | |
253 | ||
254 | /** | |
255 | * Request oauth access token from server | |
256 | * @param string $method | |
257 | * @param string $url | |
258 | * @param string $token | |
259 | * @param string $secret | |
260 | */ | |
261 | public function get_access_token($token, $secret, $verifier='') { | |
262 | $this->sign_secret = $this->consumer_secret.'&'.$secret; | |
263 | $params = $this->prepare_oauth_parameters($this->access_token_api, array('oauth_token'=>$token, 'oauth_verifier'=>$verifier), 'POST'); | |
264 | $this->setup_oauth_http_header($params); | |
926a3512 FM |
265 | // Should never send the callback in this request. |
266 | unset($params['oauth_callback']); | |
8d8a6009 | 267 | $content = $this->http->post($this->access_token_api, $params, $this->http_options); |
3e123368 DC |
268 | $keys = $this->parse_result($content); |
269 | $this->set_access_token($keys['oauth_token'], $keys['oauth_token_secret']); | |
270 | return $keys; | |
271 | } | |
272 | ||
273 | /** | |
274 | * Request oauth protected resources | |
275 | * @param string $method | |
276 | * @param string $url | |
277 | * @param string $token | |
278 | * @param string $secret | |
279 | */ | |
280 | public function request($method, $url, $params=array(), $token='', $secret='') { | |
281 | if (empty($token)) { | |
282 | $token = $this->access_token; | |
283 | } | |
284 | if (empty($secret)) { | |
285 | $secret = $this->access_token_secret; | |
286 | } | |
287 | // to access protected resource, sign_secret will alwasy be consumer_secret+token_secret | |
288 | $this->sign_secret = $this->consumer_secret.'&'.$secret; | |
6ec68429 MG |
289 | if (strtolower($method) === 'post' && !empty($params)) { |
290 | $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token) + $params, $method); | |
291 | } else { | |
292 | $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token), $method); | |
293 | } | |
3e123368 | 294 | $this->setup_oauth_http_header($oauth_params); |
8d8a6009 | 295 | $content = call_user_func_array(array($this->http, strtolower($method)), array($url, $params, $this->http_options)); |
7e1e775f MG |
296 | // reset http header and options to prepare for the next request |
297 | $this->http->resetHeader(); | |
298 | // return request return value | |
3e123368 DC |
299 | return $content; |
300 | } | |
301 | ||
302 | /** | |
303 | * shortcut to start http get request | |
304 | */ | |
305 | public function get($url, $params=array(), $token='', $secret='') { | |
306 | return $this->request('GET', $url, $params, $token, $secret); | |
307 | } | |
308 | ||
309 | /** | |
310 | * shortcut to start http post request | |
311 | */ | |
312 | public function post($url, $params=array(), $token='', $secret='') { | |
313 | return $this->request('POST', $url, $params, $token, $secret); | |
314 | } | |
315 | ||
316 | /** | |
317 | * A method to parse oauth response to get oauth_token and oauth_token_secret | |
318 | * @param string $str | |
319 | * @return array | |
320 | */ | |
321 | public function parse_result($str) { | |
322 | if (empty($str)) { | |
323 | throw new moodle_exception('error'); | |
324 | } | |
325 | $parts = explode('&', $str); | |
326 | $result = array(); | |
327 | foreach ($parts as $part){ | |
328 | list($k, $v) = explode('=', $part, 2); | |
329 | $result[urldecode($k)] = urldecode($v); | |
330 | } | |
331 | if (empty($result)) { | |
332 | throw new moodle_exception('error'); | |
333 | } | |
334 | return $result; | |
335 | } | |
336 | ||
337 | /** | |
338 | * Set nonce | |
339 | */ | |
340 | function set_nonce($str) { | |
341 | $this->nonce = $str; | |
342 | } | |
343 | /** | |
344 | * Set timestamp | |
345 | */ | |
346 | function set_timestamp($time) { | |
347 | $this->timestamp = $time; | |
348 | } | |
349 | /** | |
350 | * Generate timestamp | |
351 | */ | |
352 | function get_timestamp() { | |
353 | if (!empty($this->timestamp)) { | |
354 | $timestamp = $this->timestamp; | |
355 | unset($this->timestamp); | |
356 | return $timestamp; | |
357 | } | |
358 | return time(); | |
359 | } | |
360 | /** | |
361 | * Generate nonce for oauth request | |
362 | */ | |
363 | function get_nonce() { | |
364 | if (!empty($this->nonce)) { | |
365 | $nonce = $this->nonce; | |
366 | unset($this->nonce); | |
367 | return $nonce; | |
368 | } | |
369 | $mt = microtime(); | |
370 | $rand = mt_rand(); | |
371 | ||
372 | return md5($mt . $rand); | |
373 | } | |
374 | } | |
469fb5d6 DP |
375 | |
376 | /** | |
377 | * OAuth 2.0 Client for using web access tokens. | |
378 | * | |
379 | * http://tools.ietf.org/html/draft-ietf-oauth-v2-22 | |
380 | * | |
381 | * @package core | |
382 | * @copyright Dan Poltawski <talktodan@gmail.com> | |
383 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
384 | */ | |
385 | abstract class oauth2_client extends curl { | |
72fd103a | 386 | /** @var string $clientid client identifier issued to the client */ |
469fb5d6 | 387 | private $clientid = ''; |
72fd103a | 388 | /** @var string $clientsecret The client secret. */ |
469fb5d6 | 389 | private $clientsecret = ''; |
72fd103a | 390 | /** @var moodle_url $returnurl URL to return to after authenticating */ |
db7602af | 391 | private $returnurl = null; |
72fd103a | 392 | /** @var string $scope of the authentication request */ |
931c0234 | 393 | protected $scope = ''; |
72fd103a | 394 | /** @var stdClass $accesstoken access token object */ |
469fb5d6 | 395 | private $accesstoken = null; |
72fd103a | 396 | /** @var string $refreshtoken refresh token string */ |
60237253 | 397 | private $refreshtoken = ''; |
72fd103a | 398 | /** @var string $mocknextresponse string */ |
931c0234 | 399 | private $mocknextresponse = ''; |
72fd103a | 400 | /** @var array $upgradedcodes list of upgraded codes in this request */ |
2fad1410 | 401 | private static $upgradedcodes = []; |
469fb5d6 DP |
402 | |
403 | /** | |
404 | * Returns the auth url for OAuth 2.0 request | |
405 | * @return string the auth url | |
406 | */ | |
407 | abstract protected function auth_url(); | |
408 | ||
409 | /** | |
410 | * Returns the token url for OAuth 2.0 request | |
411 | * @return string the auth url | |
412 | */ | |
413 | abstract protected function token_url(); | |
414 | ||
415 | /** | |
416 | * Constructor. | |
417 | * | |
418 | * @param string $clientid | |
419 | * @param string $clientsecret | |
db7602af | 420 | * @param moodle_url $returnurl |
469fb5d6 DP |
421 | * @param string $scope |
422 | */ | |
db7602af | 423 | public function __construct($clientid, $clientsecret, moodle_url $returnurl, $scope) { |
469fb5d6 DP |
424 | parent::__construct(); |
425 | $this->clientid = $clientid; | |
426 | $this->clientsecret = $clientsecret; | |
427 | $this->returnurl = $returnurl; | |
428 | $this->scope = $scope; | |
429 | $this->accesstoken = $this->get_stored_token(); | |
430 | } | |
431 | ||
432 | /** | |
433 | * Is the user logged in? Note that if this is called | |
434 | * after the first part of the authorisation flow the token | |
435 | * is upgraded to an accesstoken. | |
436 | * | |
437 | * @return boolean true if logged in | |
438 | */ | |
439 | public function is_logged_in() { | |
440 | // Has the token expired? | |
441 | if (isset($this->accesstoken->expires) && time() >= $this->accesstoken->expires) { | |
442 | $this->log_out(); | |
443 | return false; | |
444 | } | |
445 | ||
446 | // We have a token so we are logged in. | |
447 | if (isset($this->accesstoken->token)) { | |
8445556b | 448 | // Check that the access token has all the requested scopes. |
2fad1410 | 449 | $scopemissing = false; |
8445556b DW |
450 | $scopecheck = ' ' . $this->accesstoken->scope . ' '; |
451 | ||
452 | $requiredscopes = explode(' ', $this->scope); | |
453 | foreach ($requiredscopes as $requiredscope) { | |
454 | if (strpos($scopecheck, ' ' . $requiredscope . ' ') === false) { | |
2fad1410 DW |
455 | $scopemissing = true; |
456 | break; | |
8445556b DW |
457 | } |
458 | } | |
2fad1410 DW |
459 | if (!$scopemissing) { |
460 | return true; | |
461 | } | |
462 | } | |
463 | ||
464 | // If we've been passed then authorization code generated by the | |
465 | // authorization server try and upgrade the token to an access token. | |
466 | $code = optional_param('oauth2code', null, PARAM_RAW); | |
467 | // Note - sometimes we may call is_logged_in twice in the same request - we don't want to attempt | |
468 | // to upgrade the same token twice. | |
469 | if ($code && !in_array($code, self::$upgradedcodes) && $this->upgrade_token($code)) { | |
469fb5d6 DP |
470 | return true; |
471 | } | |
472 | ||
469fb5d6 DP |
473 | return false; |
474 | } | |
475 | ||
476 | /** | |
477 | * Callback url where the request is returned to. | |
478 | * | |
479 | * @return moodle_url url of callback | |
480 | */ | |
481 | public static function callback_url() { | |
482 | global $CFG; | |
483 | ||
484 | return new moodle_url('/admin/oauth2callback.php'); | |
485 | } | |
486 | ||
931c0234 DW |
487 | /** |
488 | * An additional array of url params to pass with a login request. | |
489 | * | |
490 | * @return array of name value pairs. | |
491 | */ | |
60237253 DW |
492 | public function get_additional_login_parameters() { |
493 | return []; | |
494 | } | |
495 | ||
469fb5d6 DP |
496 | /** |
497 | * Returns the login link for this oauth request | |
498 | * | |
499 | * @return moodle_url login url | |
500 | */ | |
501 | public function get_login_url() { | |
502 | ||
503 | $callbackurl = self::callback_url(); | |
60237253 DW |
504 | $params = array_merge( |
505 | [ | |
506 | 'client_id' => $this->clientid, | |
507 | 'response_type' => 'code', | |
508 | 'redirect_uri' => $callbackurl->out(false), | |
509 | 'state' => $this->returnurl->out_as_local_url(false), | |
510 | 'scope' => $this->scope, | |
511 | ], | |
512 | $this->get_additional_login_parameters() | |
513 | ); | |
514 | ||
515 | return new moodle_url($this->auth_url(), $params); | |
516 | } | |
517 | ||
518 | /** | |
519 | * Given an array of name value pairs - build a valid HTTP POST application/x-www-form-urlencoded string. | |
520 | * | |
521 | * @param array $params Name / value pairs. | |
522 | * @return string POST data. | |
523 | */ | |
524 | public function build_post_data($params) { | |
525 | $result = []; | |
526 | foreach ($params as $name => $value) { | |
527 | $result[] = str_replace('&', '%26', $name) . '=' . str_replace('&', '%26', $value); | |
528 | } | |
529 | return implode('&', $result); | |
469fb5d6 DP |
530 | } |
531 | ||
532 | /** | |
533 | * Upgrade a authorization token from oauth 2.0 to an access token | |
534 | * | |
535 | * @param string $code the code returned from the oauth authenticaiton | |
536 | * @return boolean true if token is upgraded succesfully | |
537 | */ | |
538 | public function upgrade_token($code) { | |
539 | $callbackurl = self::callback_url(); | |
60237253 DW |
540 | $params = array('code' => $code, |
541 | 'client_id' => $this->clientid, | |
469fb5d6 DP |
542 | 'client_secret' => $this->clientsecret, |
543 | 'grant_type' => 'authorization_code', | |
469fb5d6 DP |
544 | 'redirect_uri' => $callbackurl->out(false), |
545 | ); | |
546 | ||
547 | // Requests can either use http GET or POST. | |
548 | if ($this->use_http_get()) { | |
549 | $response = $this->get($this->token_url(), $params); | |
550 | } else { | |
60237253 | 551 | $response = $this->post($this->token_url(), $this->build_post_data($params)); |
469fb5d6 DP |
552 | } |
553 | ||
eb4ab7c4 | 554 | if ($this->info['http_code'] !== 200) { |
469fb5d6 DP |
555 | throw new moodle_exception('Could not upgrade oauth token'); |
556 | } | |
557 | ||
558 | $r = json_decode($response); | |
559 | ||
8445556b DW |
560 | if (!empty($r->error)) { |
561 | throw new moodle_exception($r->error . ' ' . $r->error_description); | |
562 | } | |
563 | ||
469fb5d6 DP |
564 | if (!isset($r->access_token)) { |
565 | return false; | |
566 | } | |
567 | ||
60237253 DW |
568 | if (isset($r->refresh_token)) { |
569 | $this->refreshtoken = $r->refresh_token; | |
570 | } | |
571 | ||
469fb5d6 DP |
572 | // Store the token an expiry time. |
573 | $accesstoken = new stdClass; | |
574 | $accesstoken->token = $r->access_token; | |
3a4c497c AN |
575 | if (isset($r->expires_in)) { |
576 | // Expires 10 seconds before actual expiry. | |
577 | $accesstoken->expires = (time() + ($r->expires_in - 10)); | |
578 | } | |
141ee541 | 579 | $accesstoken->scope = $this->scope; |
8445556b | 580 | // Also add the scopes. |
2fad1410 | 581 | self::$upgradedcodes[] = $code; |
469fb5d6 DP |
582 | $this->store_token($accesstoken); |
583 | ||
584 | return true; | |
585 | } | |
586 | ||
587 | /** | |
588 | * Logs out of a oauth request, clearing any stored tokens | |
589 | */ | |
590 | public function log_out() { | |
591 | $this->store_token(null); | |
592 | } | |
593 | ||
594 | /** | |
595 | * Make a HTTP request, adding the access token we have | |
596 | * | |
597 | * @param string $url The URL to request | |
598 | * @param array $options | |
599 | * @return bool | |
600 | */ | |
601 | protected function request($url, $options = array()) { | |
602 | $murl = new moodle_url($url); | |
603 | ||
604 | if ($this->accesstoken) { | |
605 | if ($this->use_http_get()) { | |
606 | // If using HTTP GET add as a parameter. | |
607 | $murl->param('access_token', $this->accesstoken->token); | |
608 | } else { | |
609 | $this->setHeader('Authorization: Bearer '.$this->accesstoken->token); | |
610 | } | |
611 | } | |
612 | ||
60237253 DW |
613 | $response = parent::request($murl->out(false), $options); |
614 | ||
615 | $this->resetHeader(); | |
616 | ||
617 | return $response; | |
469fb5d6 DP |
618 | } |
619 | ||
620 | /** | |
621 | * Multiple HTTP Requests | |
622 | * This function could run multi-requests in parallel. | |
623 | * | |
624 | * @param array $requests An array of files to request | |
625 | * @param array $options An array of options to set | |
626 | * @return array An array of results | |
627 | */ | |
628 | protected function multi($requests, $options = array()) { | |
629 | if ($this->accesstoken) { | |
630 | $this->setHeader('Authorization: Bearer '.$this->accesstoken->token); | |
631 | } | |
632 | return parent::multi($requests, $options); | |
633 | } | |
634 | ||
635 | /** | |
636 | * Returns the tokenname for the access_token to be stored | |
637 | * through multiple requests. | |
638 | * | |
639 | * The default implentation is to use the classname combiend | |
640 | * with the scope. | |
641 | * | |
642 | * @return string tokenname for prefernce storage | |
643 | */ | |
644 | protected function get_tokenname() { | |
645 | // This is unusual but should work for most purposes. | |
646 | return get_class($this).'-'.md5($this->scope); | |
647 | } | |
648 | ||
649 | /** | |
650 | * Store a token between requests. Currently uses | |
651 | * session named by get_tokenname | |
652 | * | |
653 | * @param stdClass|null $token token object to store or null to clear | |
654 | */ | |
655 | protected function store_token($token) { | |
656 | global $SESSION; | |
657 | ||
658 | $this->accesstoken = $token; | |
659 | $name = $this->get_tokenname(); | |
660 | ||
661 | if ($token !== null) { | |
662 | $SESSION->{$name} = $token; | |
663 | } else { | |
664 | unset($SESSION->{$name}); | |
665 | } | |
666 | } | |
667 | ||
60237253 DW |
668 | /** |
669 | * Get a refresh token!!! | |
670 | * | |
671 | * @return string | |
672 | */ | |
673 | public function get_refresh_token() { | |
674 | return $this->refreshtoken; | |
675 | } | |
676 | ||
469fb5d6 DP |
677 | /** |
678 | * Retrieve a token stored. | |
679 | * | |
680 | * @return stdClass|null token object | |
681 | */ | |
682 | protected function get_stored_token() { | |
683 | global $SESSION; | |
684 | ||
685 | $name = $this->get_tokenname(); | |
686 | ||
687 | if (isset($SESSION->{$name})) { | |
688 | return $SESSION->{$name}; | |
689 | } | |
690 | ||
691 | return null; | |
692 | } | |
693 | ||
79d89136 FM |
694 | /** |
695 | * Get access token. | |
696 | * | |
697 | * This is just a getter to read the private property. | |
698 | * | |
699 | * @return string | |
700 | */ | |
701 | public function get_accesstoken() { | |
702 | return $this->accesstoken; | |
703 | } | |
704 | ||
705 | /** | |
706 | * Get the client ID. | |
707 | * | |
708 | * This is just a getter to read the private property. | |
709 | * | |
710 | * @return string | |
711 | */ | |
712 | public function get_clientid() { | |
713 | return $this->clientid; | |
714 | } | |
715 | ||
716 | /** | |
717 | * Get the client secret. | |
718 | * | |
719 | * This is just a getter to read the private property. | |
720 | * | |
721 | * @return string | |
722 | */ | |
723 | public function get_clientsecret() { | |
724 | return $this->clientsecret; | |
725 | } | |
726 | ||
469fb5d6 DP |
727 | /** |
728 | * Should HTTP GET be used instead of POST? | |
729 | * Some APIs do not support POST and want oauth to use | |
730 | * GET instead (with the auth_token passed as a GET param). | |
731 | * | |
732 | * @return bool true if GET should be used | |
733 | */ | |
734 | protected function use_http_get() { | |
735 | return false; | |
736 | } | |
737 | } |