Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
client.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage OAuth2
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * Joomla Platform class for interacting with an OAuth 2.0 server.
14  *
15  * @package Joomla.Platform
16  * @subpackage OAuth2
17  * @since 12.3
18  */
20 {
21  /**
22  * @var JRegistry Options for the JOAuth2Client object.
23  * @since 12.3
24  */
25  protected $options;
26 
27  /**
28  * @var JHttp The HTTP client object to use in sending HTTP requests.
29  * @since 12.3
30  */
31  protected $http;
32 
33  /**
34  * @var JInput The input object to use in retrieving GET/POST data.
35  * @since 12.3
36  */
37  protected $input;
38 
39  /**
40  * @var JApplicationWeb The application object to send HTTP headers for redirects.
41  * @since 12.3
42  */
43  protected $application;
44 
45  /**
46  * Constructor.
47  *
48  * @param JRegistry $options JOAuth2Client options object
49  * @param JHttp $http The HTTP client object
50  * @param JInput $input The input object
51  * @param JApplicationWeb $application The application object
52  *
53  * @since 12.3
54  */
55  public function __construct(JRegistry $options = null, JHttp $http = null, JInput $input = null, JApplicationWeb $application = null)
56  {
57  $this->options = isset($options) ? $options : new JRegistry;
58  $this->http = isset($http) ? $http : new JHttp($this->options);
59  $this->input = isset($input) ? $input : JFactory::getApplication()->input;
60  $this->application = isset($application) ? $application : new JApplicationWeb;
61  }
62 
63  /**
64  * Get the access token or redict to the authentication URL.
65  *
66  * @return string The access token
67  *
68  * @since 12.3
69  * @throws RuntimeException
70  */
71  public function authenticate()
72  {
73  if ($data['code'] = $this->input->get('code', false, 'raw'))
74  {
75  $data['grant_type'] = 'authorization_code';
76  $data['redirect_uri'] = $this->getOption('redirecturi');
77  $data['client_id'] = $this->getOption('clientid');
78  $data['client_secret'] = $this->getOption('clientsecret');
79  $response = $this->http->post($this->getOption('tokenurl'), $data);
80 
81  if ($response->code >= 200 && $response->code < 400)
82  {
83 
84  if ($response->headers['Content-Type'] == 'application/json')
85  {
86  $token = array_merge(json_decode($response->body, true), array('created' => time()));
87  }
88  else
89  {
90  parse_str($response->body, $token);
91  $token = array_merge($token, array('created' => time()));
92  }
93 
94  $this->setToken($token);
95 
96  return $token;
97  }
98  else
99  {
100  throw new RuntimeException('Error code ' . $response->code . ' received requesting access token: ' . $response->body . '.');
101  }
102  }
103 
104  if ($this->getOption('sendheaders'))
105  {
106  $this->application->redirect($this->createUrl());
107  }
108  return false;
109  }
110 
111  /**
112  * Verify if the client has been authenticated
113  *
114  * @return boolean Is authenticated
115  *
116  * @since 12.3
117  */
118  public function isAuthenticated()
119  {
120  $token = $this->getToken();
121 
122  if (!$token || !array_key_exists('access_token', $token))
123  {
124  return false;
125  }
126  elseif (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20)
127  {
128  return false;
129  }
130  else
131  {
132  return true;
133  }
134  }
135 
136  /**
137  * Create the URL for authentication.
138  *
139  * @return JHttpResponse The HTTP response
140  *
141  * @since 12.3
142  * @throws InvalidArgumentException
143  */
144  public function createUrl()
145  {
146  if (!$this->getOption('authurl') || !$this->getOption('clientid'))
147  {
148  throw new InvalidArgumentException('Authorization URL and client_id are required');
149  }
150 
151  $url = $this->getOption('authurl');
152 
153  if (strpos($url, '?'))
154  {
155  $url .= '&';
156  }
157  else
158  {
159  $url .= '?';
160  }
161 
162  $url .= 'response_type=code';
163  $url .= '&client_id=' . urlencode($this->getOption('clientid'));
164 
165  if ($this->getOption('redirecturi'))
166  {
167  $url .= '&redirect_uri=' . urlencode($this->getOption('redirecturi'));
168  }
169 
170  if ($this->getOption('scope'))
171  {
172  $scope = is_array($this->getOption('scope')) ? implode(' ', $this->getOption('scope')) : $this->getOption('scope');
173  $url .= '&scope=' . urlencode($scope);
174  }
175 
176  if ($this->getOption('state'))
177  {
178  $url .= '&state=' . urlencode($this->getOption('state'));
179  }
180 
181  if (is_array($this->getOption('requestparams')))
182  {
183  foreach ($this->getOption('requestparams') as $key => $value)
184  {
185  $url .= '&' . $key . '=' . urlencode($value);
186  }
187  }
188 
189  return $url;
190  }
191 
192  /**
193  * Send a signed Oauth request.
194  *
195  * @param string $url The URL forf the request.
196  * @param mixed $data The data to include in the request
197  * @param array $headers The headers to send with the request
198  * @param string $method The method with which to send the request
199  * @param int $timeout The timeout for the request
200  *
201  * @return string The URL.
202  *
203  * @since 12.3
204  * @throws InvalidArgumentException
205  * @throws RuntimeException
206  */
207  public function query($url, $data = null, $headers = array(), $method = 'get', $timeout = null)
208  {
209  $token = $this->getToken();
210 
211  if (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20)
212  {
213  if (!$this->getOption('userefresh'))
214  {
215  return false;
216  }
217  $token = $this->refreshToken($token['refresh_token']);
218  }
219 
220  if (!$this->getOption('authmethod') || $this->getOption('authmethod') == 'bearer')
221  {
222  $headers['Authorization'] = 'Bearer ' . $token['access_token'];
223  }
224  elseif ($this->getOption('authmethod') == 'get')
225  {
226  if (strpos($url, '?'))
227  {
228  $url .= '&';
229  }
230  else
231  {
232  $url .= '?';
233  }
234  $url .= $this->getOption('getparam') ? $this->getOption('getparam') : 'access_token';
235  $url .= '=' . $token['access_token'];
236  }
237 
238  switch ($method)
239  {
240  case 'head':
241  case 'get':
242  case 'delete':
243  case 'trace':
244  $response = $this->http->$method($url, $headers, $timeout);
245  break;
246  case 'post':
247  case 'put':
248  case 'patch':
249  $response = $this->http->$method($url, $data, $headers, $timeout);
250  break;
251  default:
252  throw new InvalidArgumentException('Unknown HTTP request method: ' . $method . '.');
253  }
254 
255  if ($response->code < 200 || $response->code >= 400)
256  {
257  throw new RuntimeException('Error code ' . $response->code . ' received requesting data: ' . $response->body . '.');
258  }
259  return $response;
260  }
261 
262  /**
263  * Get an option from the JOAuth2Client instance.
264  *
265  * @param string $key The name of the option to get
266  *
267  * @return mixed The option value
268  *
269  * @since 12.3
270  */
271  public function getOption($key)
272  {
273  return $this->options->get($key);
274  }
275 
276  /**
277  * Set an option for the JOAuth2Client instance.
278  *
279  * @param string $key The name of the option to set
280  * @param mixed $value The option value to set
281  *
282  * @return JOAuth2Client This object for method chaining
283  *
284  * @since 12.3
285  */
286  public function setOption($key, $value)
287  {
288  $this->options->set($key, $value);
289 
290  return $this;
291  }
292 
293  /**
294  * Get the access token from the JOAuth2Client instance.
295  *
296  * @return array The access token
297  *
298  * @since 12.3
299  */
300  public function getToken()
301  {
302  return $this->getOption('accesstoken');
303  }
304 
305  /**
306  * Set an option for the JOAuth2Client instance.
307  *
308  * @param array $value The access token
309  *
310  * @return JOAuth2Client This object for method chaining
311  *
312  * @since 12.3
313  */
314  public function setToken($value)
315  {
316  if (is_array($value) && !array_key_exists('expires_in', $value) && array_key_exists('expires', $value))
317  {
318  $value['expires_in'] = $value['expires'];
319  unset($value['expires']);
320  }
321  $this->setOption('accesstoken', $value);
322 
323  return $this;
324  }
325 
326  /**
327  * Refresh the access token instance.
328  *
329  * @param string $token The refresh token
330  *
331  * @return array The new access token
332  *
333  * @since 12.3
334  * @throws Exception
335  * @throws RuntimeException
336  */
337  public function refreshToken($token = null)
338  {
339  if (!$this->getOption('userefresh'))
340  {
341  throw new RuntimeException('Refresh token is not supported for this OAuth instance.');
342  }
343 
344  if (!$token)
345  {
346  $token = $this->getToken();
347 
348  if (!array_key_exists('refresh_token', $token))
349  {
350  throw new RuntimeException('No refresh token is available.');
351  }
352  $token = $token['refresh_token'];
353  }
354  $data['grant_type'] = 'refresh_token';
355  $data['refresh_token'] = $token;
356  $data['client_id'] = $this->getOption('clientid');
357  $data['client_secret'] = $this->getOption('clientsecret');
358  $response = $this->http->post($this->getOption('tokenurl'), $data);
359 
360  if ($response->code >= 200 || $response->code < 400)
361  {
362  if ($response->headers['Content-Type'] == 'application/json')
363  {
364  $token = array_merge(json_decode($response->body, true), array('created' => time()));
365  }
366  else
367  {
368  parse_str($response->body, $token);
369  $token = array_merge($token, array('created' => time()));
370  }
371 
372  $this->setToken($token);
373 
374  return $token;
375  }
376  else
377  {
378  throw new Exception('Error code ' . $response->code . ' received refreshing token: ' . $response->body . '.');
379  }
380  }
381 }