[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Part of the Joomla Framework OAuth2 Package 4 * 5 * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. 6 * @license GNU General Public License version 2 or later; see LICENSE 7 */ 8 9 namespace Joomla\OAuth2; 10 11 use Joomla\Application\WebApplicationInterface; 12 use Joomla\Http\Exception\UnexpectedResponseException; 13 use Joomla\Http\Http; 14 use Joomla\Http\HttpFactory; 15 use Joomla\Input\Input; 16 use Joomla\Uri\Uri; 17 18 /** 19 * Joomla Framework class for interacting with an OAuth 2.0 server. 20 * 21 * @since 1.0 22 */ 23 class Client 24 { 25 /** 26 * Options for the Client object. 27 * 28 * @var array|\ArrayAccess 29 * @since 1.0 30 */ 31 protected $options; 32 33 /** 34 * The HTTP client object to use in sending HTTP requests. 35 * 36 * @var Http 37 * @since 1.0 38 */ 39 protected $http; 40 41 /** 42 * The input object to use in retrieving GET/POST data. 43 * 44 * @var Input 45 * @since 1.0 46 */ 47 protected $input; 48 49 /** 50 * The application object to send HTTP headers for redirects. 51 * 52 * @var WebApplicationInterface 53 * @since 1.0 54 */ 55 protected $application; 56 57 /** 58 * Constructor. 59 * 60 * @param array|\ArrayAccess $options OAuth2 Client options object 61 * @param Http $http The HTTP client object 62 * @param Input $input The input object 63 * @param WebApplicationInterface $application The application object 64 * 65 * @since 1.0 66 */ 67 public function __construct($options = [], Http $http = null, Input $input = null, WebApplicationInterface $application = null) 68 { 69 if (!\is_array($options) && !($options instanceof \ArrayAccess)) 70 { 71 throw new \InvalidArgumentException( 72 'The options param must be an array or implement the ArrayAccess interface.' 73 ); 74 } 75 76 $this->options = $options; 77 $this->http = $http ?: HttpFactory::getHttp($this->options); 78 $this->input = $input ?: ($application ? $application->getInput() : new Input); 79 $this->application = $application; 80 } 81 82 /** 83 * Get the access token or redirect to the authentication URL. 84 * 85 * @return array|boolean The access token or false on failure 86 * 87 * @since 1.0 88 * @throws UnexpectedResponseException 89 * @throws \RuntimeException 90 */ 91 public function authenticate() 92 { 93 if ($data['code'] = $this->input->get('code', false, 'raw')) 94 { 95 $data = [ 96 'grant_type' => 'authorization_code', 97 'redirect_uri' => $this->getOption('redirecturi'), 98 'client_id' => $this->getOption('clientid'), 99 'client_secret' => $this->getOption('clientsecret'), 100 ]; 101 102 $response = $this->http->post($this->getOption('tokenurl'), $data); 103 104 if (!($response->code >= 200 && $response->code < 400)) 105 { 106 throw new UnexpectedResponseException( 107 $response, 108 sprintf( 109 'Error code %s received requesting access token: %s.', 110 $response->code, 111 $response->body 112 ) 113 ); 114 } 115 116 if (strpos($response->headers['Content-Type'], 'application/json') !== false) 117 { 118 $token = array_merge(json_decode($response->body, true), ['created' => time()]); 119 } 120 else 121 { 122 parse_str($response->body, $token); 123 $token = array_merge($token, ['created' => time()]); 124 } 125 126 $this->setToken($token); 127 128 return $token; 129 } 130 131 if ($this->getOption('sendheaders')) 132 { 133 if (!($this->application instanceof WebApplicationInterface)) 134 { 135 throw new \RuntimeException( 136 \sprintf('A "%s" implementation is required to process authentication.', WebApplicationInterface::class) 137 ); 138 } 139 140 $this->application->redirect($this->createUrl()); 141 } 142 143 return false; 144 } 145 146 /** 147 * Verify if the client has been authenticated 148 * 149 * @return boolean Is authenticated 150 * 151 * @since 1.0 152 */ 153 public function isAuthenticated() 154 { 155 $token = $this->getToken(); 156 157 if (!$token || !array_key_exists('access_token', $token)) 158 { 159 return false; 160 } 161 162 if (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20) 163 { 164 return false; 165 } 166 167 return true; 168 } 169 170 /** 171 * Create the URL for authentication. 172 * 173 * @return string 174 * 175 * @since 1.0 176 * @throws \InvalidArgumentException 177 */ 178 public function createUrl() 179 { 180 if (!$this->getOption('authurl') || !$this->getOption('clientid')) 181 { 182 throw new \InvalidArgumentException('Authorization URL and client_id are required'); 183 } 184 185 $url = new Uri($this->getOption('authurl')); 186 $url->setVar('response_type', 'code'); 187 $url->setVar('client_id', urlencode($this->getOption('clientid'))); 188 189 if ($redirect = $this->getOption('redirecturi')) 190 { 191 $url->setVar('redirect_uri', urlencode($redirect)); 192 } 193 194 if ($scope = $this->getOption('scope')) 195 { 196 $scope = \is_array($scope) ? implode(' ', $scope) : $scope; 197 $url->setVar('scope', urlencode($scope)); 198 } 199 200 if ($state = $this->getOption('state')) 201 { 202 $url->setVar('state', urlencode($state)); 203 } 204 205 if (\is_array($this->getOption('requestparams'))) 206 { 207 foreach ($this->getOption('requestparams') as $key => $value) 208 { 209 $url->setVar($key, urlencode($value)); 210 } 211 } 212 213 return (string) $url; 214 } 215 216 /** 217 * Send a signed OAuth request. 218 * 219 * @param string $url The URL for the request 220 * @param mixed $data Either an associative array or a string to be sent with the request 221 * @param array $headers The headers to send with the request 222 * @param string $method The method with which to send the request 223 * @param integer $timeout The timeout for the request 224 * 225 * @return \Joomla\Http\Response 226 * 227 * @since 1.0 228 * @throws \InvalidArgumentException 229 * @throws \RuntimeException 230 */ 231 public function query($url, $data = null, $headers = [], $method = 'get', $timeout = null) 232 { 233 $token = $this->getToken(); 234 235 if (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20) 236 { 237 if (!$this->getOption('userefresh')) 238 { 239 return false; 240 } 241 242 $token = $this->refreshToken($token['refresh_token']); 243 } 244 245 $url = new Uri($url); 246 247 if (!$this->getOption('authmethod') || $this->getOption('authmethod') == 'bearer') 248 { 249 $headers['Authorization'] = 'Bearer ' . $token['access_token']; 250 } 251 elseif ($this->getOption('authmethod') == 'get') 252 { 253 $url->setVar($this->getOption('getparam', 'access_token'), $token['access_token']); 254 } 255 256 switch ($method) 257 { 258 case 'head': 259 case 'get': 260 case 'delete': 261 case 'trace': 262 $response = $this->http->$method($url, $headers, $timeout); 263 264 break; 265 266 case 'post': 267 case 'put': 268 case 'patch': 269 $response = $this->http->$method($url, $data, $headers, $timeout); 270 271 break; 272 273 default: 274 throw new \InvalidArgumentException('Unknown HTTP request method: ' . $method . '.'); 275 } 276 277 if ($response->code < 200 || $response->code >= 400) 278 { 279 throw new UnexpectedResponseException( 280 $response, 281 sprintf( 282 'Error code %s received requesting data: %s.', 283 $response->code, 284 $response->body 285 ) 286 ); 287 } 288 289 return $response; 290 } 291 292 /** 293 * Get an option from the OAuth2 Client instance. 294 * 295 * @param string $key The name of the option to get 296 * @param mixed $default Optional default value, returned if the requested option does not exist. 297 * 298 * @return mixed The option value 299 * 300 * @since 1.0 301 */ 302 public function getOption($key, $default = null) 303 { 304 return $this->options[$key] ?? $default; 305 } 306 307 /** 308 * Set an option for the OAuth2 Client instance. 309 * 310 * @param string $key The name of the option to set 311 * @param mixed $value The option value to set 312 * 313 * @return Client This object for method chaining 314 * 315 * @since 1.0 316 */ 317 public function setOption($key, $value) 318 { 319 $this->options[$key] = $value; 320 321 return $this; 322 } 323 324 /** 325 * Get the access token from the Client instance. 326 * 327 * @return array The access token 328 * 329 * @since 1.0 330 */ 331 public function getToken() 332 { 333 return $this->getOption('accesstoken'); 334 } 335 336 /** 337 * Set an option for the Client instance. 338 * 339 * @param array $value The access token 340 * 341 * @return Client This object for method chaining 342 * 343 * @since 1.0 344 */ 345 public function setToken($value) 346 { 347 if (\is_array($value) && !array_key_exists('expires_in', $value) && array_key_exists('expires', $value)) 348 { 349 $value['expires_in'] = $value['expires']; 350 unset($value['expires']); 351 } 352 353 $this->setOption('accesstoken', $value); 354 355 return $this; 356 } 357 358 /** 359 * Refresh the access token instance. 360 * 361 * @param string $token The refresh token 362 * 363 * @return array The new access token 364 * 365 * @since 1.0 366 * @throws UnexpectedResponseException 367 * @throws \RuntimeException 368 */ 369 public function refreshToken($token = null) 370 { 371 if (!$this->getOption('userefresh')) 372 { 373 throw new \RuntimeException('Refresh token is not supported for this OAuth instance.'); 374 } 375 376 if (!$token) 377 { 378 $token = $this->getToken(); 379 380 if (!array_key_exists('refresh_token', $token)) 381 { 382 throw new \RuntimeException('No refresh token is available.'); 383 } 384 385 $token = $token['refresh_token']; 386 } 387 388 $data = [ 389 'grant_type' => 'refresh_token', 390 'refresh_token' => $token, 391 'client_id' => $this->getOption('clientid'), 392 'client_secret' => $this->getOption('clientsecret'), 393 ]; 394 395 $response = $this->http->post($this->getOption('tokenurl'), $data); 396 397 if (!($response->code >= 200 || $response->code < 400)) 398 { 399 throw new UnexpectedResponseException( 400 $response, 401 sprintf( 402 'Error code %s received refreshing token: %s.', 403 $response->code, 404 $response->body 405 ) 406 ); 407 } 408 409 if (strpos($response->headers['Content-Type'], 'application/json') !== false) 410 { 411 $token = array_merge(json_decode($response->body, true), ['created' => time()]); 412 } 413 else 414 { 415 parse_str($response->body, $token); 416 $token = array_merge($token, ['created' => time()]); 417 } 418 419 $this->setToken($token); 420 421 return $token; 422 } 423 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |