[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/joomla/oauth2/src/ -> Client.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer