[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Part of the Joomla Framework OAuth1 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\OAuth1;
  10  
  11  use Joomla\Application\SessionAwareWebApplicationInterface;
  12  use Joomla\Http\Http;
  13  use Joomla\Http\HttpFactory;
  14  use Joomla\Input\Input;
  15  use Joomla\Uri\Uri;
  16  
  17  /**
  18   * Joomla Framework class for interacting with an OAuth 1.0 and 1.0a server.
  19   *
  20   * @since  1.0
  21   */
  22  abstract class Client
  23  {
  24      /**
  25       * Options for the Client object.
  26       *
  27       * @var    array|\ArrayAccess
  28       * @since  1.0
  29       */
  30      protected $options;
  31  
  32      /**
  33       * Contains access token key, secret and verifier.
  34       *
  35       * @var    array
  36       * @since  1.0
  37       */
  38      protected $token = [];
  39  
  40      /**
  41       * The HTTP client object to use in sending HTTP requests.
  42       *
  43       * @var    Http
  44       * @since  1.0
  45       */
  46      protected $client;
  47  
  48      /**
  49       * The input object to use in retrieving GET/POST data.
  50       *
  51       * @var    Input
  52       * @since  1.0
  53       */
  54      protected $input;
  55  
  56      /**
  57       * The application object to send HTTP headers for redirects.
  58       *
  59       * @var    SessionAwareWebApplicationInterface
  60       * @since  1.0
  61       */
  62      protected $application;
  63  
  64      /**
  65       * Selects which version of OAuth to use: 1.0 or 1.0a.
  66       *
  67       * @var    string
  68       * @since  1.0
  69       */
  70      protected $version;
  71  
  72      /**
  73       * Constructor.
  74       *
  75       * @param   SessionAwareWebApplicationInterface  $application  The application object
  76       * @param   Http                                 $client       The HTTP client object.
  77       * @param   Input                                $input        The input object
  78       * @param   array|\ArrayAccess                   $options      OAuth1 Client options.
  79       * @param   string                               $version      Specify the OAuth version. By default we are using 1.0a.
  80       *
  81       * @since   1.0
  82       */
  83  	public function __construct(
  84          SessionAwareWebApplicationInterface $application,
  85          Http $client = null,
  86          Input $input = null,
  87          $options = [],
  88          $version = '1.0a'
  89      )
  90      {
  91          if (!\is_array($options) && !($options instanceof \ArrayAccess))
  92          {
  93              throw new \InvalidArgumentException(
  94                  'The options param must be an array or implement the ArrayAccess interface.'
  95              );
  96          }
  97  
  98          $this->application = $application;
  99          $this->client      = $client ?: HttpFactory::getHttp($options);
 100          $this->input       = $input ?: $application->getInput();
 101          $this->options     = $options;
 102          $this->version     = $version;
 103      }
 104  
 105      /**
 106       * Method to form the oauth flow.
 107       *
 108       * @return  array|null  The access token.
 109       *
 110       * @since   1.0
 111       * @throws  \DomainException
 112       */
 113  	public function authenticate()
 114      {
 115          // Already got some credentials stored?
 116          if ($this->token)
 117          {
 118              $response = $this->verifyCredentials();
 119  
 120              if ($response)
 121              {
 122                  return $this->token;
 123              }
 124  
 125              $this->token = null;
 126          }
 127  
 128          // Check for callback.
 129          if (strcmp($this->version, '1.0a') === 0)
 130          {
 131              $verifier = $this->input->get('oauth_verifier');
 132          }
 133          else
 134          {
 135              $verifier = $this->input->get('oauth_token');
 136          }
 137  
 138          if (!empty($verifier))
 139          {
 140              $session = $this->application->getSession();
 141  
 142              // Get token form session.
 143              $this->token = [
 144                  'key'    => $session->get('oauth_token.key'),
 145                  'secret' => $session->get('oauth_token.secret'),
 146              ];
 147  
 148              // Verify the returned request token.
 149              if (strcmp($this->token['key'], $this->input->get('oauth_token')) !== 0)
 150              {
 151                  throw new \DomainException('Bad session!');
 152              }
 153  
 154              // Set token verifier for 1.0a.
 155              if (strcmp($this->version, '1.0a') === 0)
 156              {
 157                  $this->token['verifier'] = $this->input->get('oauth_verifier');
 158              }
 159  
 160              // Generate access token.
 161              $this->generateAccessToken();
 162  
 163              // Return the access token.
 164              return $this->token;
 165          }
 166  
 167          // Generate a request token.
 168          $this->generateRequestToken();
 169  
 170          // Authenticate the user and authorise the app.
 171          $this->authorise();
 172      }
 173  
 174      /**
 175       * Method used to get a request token.
 176       *
 177       * @return  void
 178       *
 179       * @since   1.1.2
 180       * @throws  \DomainException
 181       */
 182  	private function generateRequestToken()
 183      {
 184          $parameters = [];
 185  
 186          // Set the callback URL.
 187          if ($this->getOption('callback'))
 188          {
 189              $parameters['oauth_callback'] = $this->getOption('callback');
 190          }
 191  
 192          // Make an OAuth request for the Request Token.
 193          $response = $this->oauthRequest($this->getOption('requestTokenURL'), 'POST', $parameters);
 194  
 195          parse_str($response->body, $params);
 196  
 197          if (strcmp($this->version, '1.0a') === 0 && strcmp($params['oauth_callback_confirmed'], 'true') !== 0)
 198          {
 199              throw new \DomainException('Bad request token!');
 200          }
 201  
 202          // Save the request token.
 203          $this->token = ['key' => $params['oauth_token'], 'secret' => $params['oauth_token_secret']];
 204  
 205          // Save the request token in session
 206          $session = $this->application->getSession();
 207          $session->set('oauth_token.key', $this->token['key']);
 208          $session->set('oauth_token.secret', $this->token['secret']);
 209      }
 210  
 211      /**
 212       * Method used to authorise the application.
 213       *
 214       * @return  void
 215       *
 216       * @since   1.1.2
 217       */
 218  	private function authorise()
 219      {
 220          $url = $this->getOption('authoriseURL') . '?oauth_token=' . $this->token['key'];
 221  
 222          if ($this->getOption('scope'))
 223          {
 224              $scope = \is_array($this->getOption('scope')) ? implode(' ', $this->getOption('scope')) : $this->getOption('scope');
 225              $url .= '&scope=' . urlencode($scope);
 226          }
 227  
 228          if ($this->getOption('sendheaders'))
 229          {
 230              $this->application->redirect($url);
 231          }
 232      }
 233  
 234      /**
 235       * Method used to get an access token.
 236       *
 237       * @return  void
 238       *
 239       * @since   1.1.2
 240       */
 241  	private function generateAccessToken()
 242      {
 243          // Set the parameters.
 244          $parameters = [
 245              'oauth_token' => $this->token['key'],
 246          ];
 247  
 248          if (strcmp($this->version, '1.0a') === 0)
 249          {
 250              $parameters = array_merge($parameters, ['oauth_verifier' => $this->token['verifier']]);
 251          }
 252  
 253          // Make an OAuth request for the Access Token.
 254          $response = $this->oauthRequest($this->getOption('accessTokenURL'), 'POST', $parameters);
 255  
 256          parse_str($response->body, $params);
 257  
 258          // Save the access token.
 259          $this->token = ['key' => $params['oauth_token'], 'secret' => $params['oauth_token_secret']];
 260      }
 261  
 262      /**
 263       * Method used to make an OAuth request.
 264       *
 265       * @param   string  $url         The request URL.
 266       * @param   string  $method      The request method.
 267       * @param   array   $parameters  Array containing request parameters.
 268       * @param   mixed   $data        The POST request data.
 269       * @param   array   $headers     An array of name-value pairs to include in the header of the request
 270       *
 271       * @return  \Joomla\Http\Response
 272       *
 273       * @since   1.0
 274       * @throws  \DomainException
 275       */
 276  	public function oauthRequest($url, $method, $parameters, $data = [], $headers = [])
 277      {
 278          // Set the parameters.
 279          $defaults = [
 280              'oauth_consumer_key'     => $this->getOption('consumer_key'),
 281              'oauth_signature_method' => 'HMAC-SHA1',
 282              'oauth_version'          => '1.0',
 283              'oauth_nonce'            => $this->generateNonce(),
 284              'oauth_timestamp'        => time(),
 285          ];
 286  
 287          $parameters = array_merge($parameters, $defaults);
 288  
 289          // Do not encode multipart parameters. Do not include $data in the signature if $data is not array.
 290          if (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'multipart/form-data') !== false || !\is_array($data))
 291          {
 292              $oauthHeaders = $parameters;
 293          }
 294          else
 295          {
 296              // Use all parameters for the signature.
 297              $oauthHeaders = array_merge($parameters, $data);
 298          }
 299  
 300          // Sign the request.
 301          $oauthHeaders = $this->signRequest($url, $method, $oauthHeaders);
 302  
 303          // Get parameters for the Authorisation header.
 304          if (\is_array($data))
 305          {
 306              $oauthHeaders = array_diff_key($oauthHeaders, $data);
 307          }
 308  
 309          // Send the request.
 310          switch ($method)
 311          {
 312              case 'GET':
 313                  $url      = $this->toUrl($url, $data);
 314                  $response = $this->client->get($url, ['Authorization' => $this->createHeader($oauthHeaders)]);
 315  
 316                  break;
 317  
 318              case 'POST':
 319                  $headers  = array_merge($headers, ['Authorization' => $this->createHeader($oauthHeaders)]);
 320                  $response = $this->client->post($url, $data, $headers);
 321  
 322                  break;
 323  
 324              case 'PUT':
 325                  $headers  = array_merge($headers, ['Authorization' => $this->createHeader($oauthHeaders)]);
 326                  $response = $this->client->put($url, $data, $headers);
 327  
 328                  break;
 329  
 330              case 'DELETE':
 331                  $headers  = array_merge($headers, ['Authorization' => $this->createHeader($oauthHeaders)]);
 332                  $response = $this->client->delete($url, $headers);
 333  
 334                  break;
 335          }
 336  
 337          // Validate the response code.
 338          $this->validateResponse($url, $response);
 339  
 340          return $response;
 341      }
 342  
 343      /**
 344       * Method to validate a response.
 345       *
 346       * @param   string    $url       The request URL.
 347       * @param   Response  $response  The response to validate.
 348       *
 349       * @return  void
 350       *
 351       * @since   1.0
 352       * @throws  \DomainException
 353       */
 354      abstract public function validateResponse($url, $response);
 355  
 356      /**
 357       * Method used to create the header for the POST request.
 358       *
 359       * @param   array  $parameters  Array containing request parameters.
 360       *
 361       * @return  string  The header.
 362       *
 363       * @since   1.1.2
 364       */
 365  	private function createHeader(array $parameters): string
 366      {
 367          $header = 'OAuth ';
 368  
 369          foreach ($parameters as $key => $value)
 370          {
 371              if (!strcmp($header, 'OAuth '))
 372              {
 373                  $header .= $key . '="' . $this->safeEncode($value) . '"';
 374              }
 375              else
 376              {
 377                  $header .= ', ' . $key . '="' . $value . '"';
 378              }
 379          }
 380  
 381          return $header;
 382      }
 383  
 384      /**
 385       * Method to create the URL formed string with the parameters.
 386       *
 387       * @param   string  $url         The request URL.
 388       * @param   array   $parameters  Array containing request parameters.
 389       *
 390       * @return  string  The formed URL.
 391       *
 392       * @since   1.0
 393       */
 394  	public function toUrl($url, $parameters)
 395      {
 396          $uri = new Uri($url);
 397          $uri->setQuery($parameters);
 398  
 399          return (string) $uri;
 400      }
 401  
 402      /**
 403       * Method used to sign requests.
 404       *
 405       * @param   string  $url         The URL to sign.
 406       * @param   string  $method      The request method.
 407       * @param   array   $parameters  Array containing request parameters.
 408       *
 409       * @return  array  The array containing the request parameters, including signature.
 410       *
 411       * @since   1.1.2
 412       */
 413  	private function signRequest(string $url, string $method, array $parameters): array
 414      {
 415          // Create the signature base string.
 416          $base = $this->baseString($url, $method, $parameters);
 417  
 418          $parameters['oauth_signature'] = $this->safeEncode(
 419              base64_encode(
 420                  hash_hmac('sha1', $base, $this->prepareSigningKey(), true)
 421              )
 422          );
 423  
 424          return $parameters;
 425      }
 426  
 427      /**
 428       * Prepare the signature base string.
 429       *
 430       * @param   string  $url         The URL to sign.
 431       * @param   string  $method      The request method.
 432       * @param   array   $parameters  Array containing request parameters.
 433       *
 434       * @return  string  The base string.
 435       *
 436       * @since   1.1.2
 437       */
 438  	private function baseString(string $url, string $method, array $parameters): string
 439      {
 440          // Sort the parameters alphabetically
 441          uksort($parameters, 'strcmp');
 442  
 443          // Encode parameters.
 444          foreach ($parameters as $key => $value)
 445          {
 446              $key = $this->safeEncode($key);
 447  
 448              if (\is_array($value))
 449              {
 450                  foreach ($value as $k => $v)
 451                  {
 452                      $v    = $this->safeEncode($v);
 453                      $kv[] = "{$key}={$v}";
 454                  }
 455              }
 456              else
 457              {
 458                  $value = $this->safeEncode($value);
 459                  $kv[]  = "{$key}={$value}";
 460              }
 461          }
 462  
 463          // Form the parameter string.
 464          $params = implode('&', $kv);
 465  
 466          // Signature base string elements.
 467          $base = [
 468              $method,
 469              $url,
 470              $params,
 471          ];
 472  
 473          // Return the base string.
 474          return implode('&', $this->safeEncode($base));
 475      }
 476  
 477      /**
 478       * Encodes the string or array passed in a way compatible with OAuth.
 479       * If an array is passed each array value will will be encoded.
 480       *
 481       * @param   mixed  $data  The scalar or array to encode.
 482       *
 483       * @return  string  $data encoded in a way compatible with OAuth.
 484       *
 485       * @since   1.0
 486       */
 487  	public function safeEncode($data)
 488      {
 489          if (\is_array($data))
 490          {
 491              return array_map([$this, 'safeEncode'], $data);
 492          }
 493  
 494          if (is_scalar($data))
 495          {
 496              return str_ireplace(
 497                  ['+', '%7E'],
 498                  [' ', '~'],
 499                  rawurlencode($data)
 500              );
 501          }
 502  
 503          return '';
 504      }
 505  
 506      /**
 507       * Method used to generate the current nonce.
 508       *
 509       * @return  string  The current nonce.
 510       *
 511       * @since   1.0
 512       */
 513  	public static function generateNonce()
 514      {
 515          // The md5s look nicer than numbers.
 516          return md5(microtime() . random_bytes(16));
 517      }
 518  
 519      /**
 520       * Prepares the OAuth signing key.
 521       *
 522       * @return  string  The prepared signing key.
 523       *
 524       * @since   1.1.2
 525       */
 526  	private function prepareSigningKey(): string
 527      {
 528          return $this->safeEncode($this->getOption('consumer_secret')) . '&' . $this->safeEncode(($this->token) ? $this->token['secret'] : '');
 529      }
 530  
 531      /**
 532       * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
 533       * returns a 401 status code and an error message if not.
 534       *
 535       * @return  array  The decoded JSON response
 536       *
 537       * @since   1.0
 538       */
 539      abstract public function verifyCredentials();
 540  
 541      /**
 542       * Get an option from the OAuth1 Client instance.
 543       *
 544       * @param   string  $key      The name of the option to get
 545       * @param   mixed   $default  Optional default value if the option does not exist
 546       *
 547       * @return  mixed  The option value
 548       *
 549       * @since   1.0
 550       */
 551  	public function getOption($key, $default = null)
 552      {
 553          return $this->options[$key] ?? $default;
 554      }
 555  
 556      /**
 557       * Set an option for the OAuth1 Client instance.
 558       *
 559       * @param   string  $key    The name of the option to set
 560       * @param   mixed   $value  The option value to set
 561       *
 562       * @return  $this
 563       *
 564       * @since   1.0
 565       */
 566  	public function setOption($key, $value)
 567      {
 568          $this->options[$key] = $value;
 569  
 570          return $this;
 571      }
 572  
 573      /**
 574       * Get the oauth token key or secret.
 575       *
 576       * @return  array  The oauth token key and secret.
 577       *
 578       * @since   1.0
 579       */
 580  	public function getToken()
 581      {
 582          return $this->token;
 583      }
 584  
 585      /**
 586       * Set the oauth token.
 587       *
 588       * @param   array  $token  The access token key and secret.
 589       *
 590       * @return  $this
 591       *
 592       * @since   1.0
 593       */
 594  	public function setToken($token)
 595      {
 596          $this->token = $token;
 597  
 598          return $this;
 599      }
 600  }


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