Current File : /home/pacjaorg/public_html/kmm/libraries/vendor/joomla/oauth2/src/Client.php |
<?php
/**
* Part of the Joomla Framework OAuth2 Package
*
* @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
namespace Joomla\OAuth2;
use Joomla\Application\WebApplicationInterface;
use Joomla\Http\Exception\UnexpectedResponseException;
use Joomla\Http\Http;
use Joomla\Http\HttpFactory;
use Joomla\Input\Input;
use Joomla\Uri\Uri;
/**
* Joomla Framework class for interacting with an OAuth 2.0 server.
*
* @since 1.0
*/
class Client
{
/**
* Options for the Client object.
*
* @var array|\ArrayAccess
* @since 1.0
*/
protected $options;
/**
* The HTTP client object to use in sending HTTP requests.
*
* @var Http
* @since 1.0
*/
protected $http;
/**
* The input object to use in retrieving GET/POST data.
*
* @var Input
* @since 1.0
*/
protected $input;
/**
* The application object to send HTTP headers for redirects.
*
* @var WebApplicationInterface
* @since 1.0
*/
protected $application;
/**
* Constructor.
*
* @param array|\ArrayAccess $options OAuth2 Client options object
* @param Http $http The HTTP client object
* @param Input $input The input object
* @param WebApplicationInterface $application The application object
*
* @since 1.0
*/
public function __construct($options = [], Http $http = null, Input $input = null, WebApplicationInterface $application = null)
{
if (!\is_array($options) && !($options instanceof \ArrayAccess))
{
throw new \InvalidArgumentException(
'The options param must be an array or implement the ArrayAccess interface.'
);
}
$this->options = $options;
$this->http = $http ?: (new HttpFactory)->getHttp($this->options);
$this->input = $input ?: ($application ? $application->getInput() : new Input);
$this->application = $application;
}
/**
* Get the access token or redirect to the authentication URL.
*
* @return array|boolean The access token or false on failure
*
* @since 1.0
* @throws UnexpectedResponseException
* @throws \RuntimeException
*/
public function authenticate()
{
if ($data['code'] = $this->input->get('code', false, 'raw'))
{
$data = [
'grant_type' => 'authorization_code',
'redirect_uri' => $this->getOption('redirecturi'),
'client_id' => $this->getOption('clientid'),
'client_secret' => $this->getOption('clientsecret'),
];
$response = $this->http->post($this->getOption('tokenurl'), $data);
if (!($response->code >= 200 && $response->code < 400))
{
throw new UnexpectedResponseException(
$response,
sprintf(
'Error code %s received requesting access token: %s.',
$response->code,
$response->body
)
);
}
if (strpos($response->headers['Content-Type'], 'application/json') !== false)
{
$token = array_merge(json_decode($response->body, true), ['created' => time()]);
}
else
{
parse_str($response->body, $token);
$token = array_merge($token, ['created' => time()]);
}
$this->setToken($token);
return $token;
}
if ($this->getOption('sendheaders'))
{
if (!($this->application instanceof WebApplicationInterface))
{
throw new \RuntimeException(
\sprintf('A "%s" implementation is required to process authentication.', WebApplicationInterface::class)
);
}
$this->application->redirect($this->createUrl());
}
return false;
}
/**
* Verify if the client has been authenticated
*
* @return boolean Is authenticated
*
* @since 1.0
*/
public function isAuthenticated()
{
$token = $this->getToken();
if (!$token || !array_key_exists('access_token', $token))
{
return false;
}
if (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20)
{
return false;
}
return true;
}
/**
* Create the URL for authentication.
*
* @return string
*
* @since 1.0
* @throws \InvalidArgumentException
*/
public function createUrl()
{
if (!$this->getOption('authurl') || !$this->getOption('clientid'))
{
throw new \InvalidArgumentException('Authorization URL and client_id are required');
}
$url = new Uri($this->getOption('authurl'));
$url->setVar('response_type', 'code');
$url->setVar('client_id', urlencode($this->getOption('clientid')));
if ($redirect = $this->getOption('redirecturi'))
{
$url->setVar('redirect_uri', urlencode($redirect));
}
if ($scope = $this->getOption('scope'))
{
$scope = \is_array($scope) ? implode(' ', $scope) : $scope;
$url->setVar('scope', urlencode($scope));
}
if ($state = $this->getOption('state'))
{
$url->setVar('state', urlencode($state));
}
if (\is_array($this->getOption('requestparams')))
{
foreach ($this->getOption('requestparams') as $key => $value)
{
$url->setVar($key, urlencode($value));
}
}
return (string) $url;
}
/**
* Send a signed OAuth request.
*
* @param string $url The URL for the request
* @param mixed $data Either an associative array or a string to be sent with the request
* @param array $headers The headers to send with the request
* @param string $method The method with which to send the request
* @param integer $timeout The timeout for the request
*
* @return \Joomla\Http\Response
*
* @since 1.0
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function query($url, $data = null, $headers = [], $method = 'get', $timeout = null)
{
$token = $this->getToken();
if (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20)
{
if (!$this->getOption('userefresh'))
{
return false;
}
$token = $this->refreshToken($token['refresh_token']);
}
$url = new Uri($url);
if (!$this->getOption('authmethod') || $this->getOption('authmethod') == 'bearer')
{
$headers['Authorization'] = 'Bearer ' . $token['access_token'];
}
elseif ($this->getOption('authmethod') == 'get')
{
$url->setVar($this->getOption('getparam', 'access_token'), $token['access_token']);
}
switch ($method)
{
case 'head':
case 'get':
case 'delete':
case 'trace':
$response = $this->http->$method($url, $headers, $timeout);
break;
case 'post':
case 'put':
case 'patch':
$response = $this->http->$method($url, $data, $headers, $timeout);
break;
default:
throw new \InvalidArgumentException('Unknown HTTP request method: ' . $method . '.');
}
if ($response->code < 200 || $response->code >= 400)
{
throw new UnexpectedResponseException(
$response,
sprintf(
'Error code %s received requesting data: %s.',
$response->code,
$response->body
)
);
}
return $response;
}
/**
* Get an option from the OAuth2 Client instance.
*
* @param string $key The name of the option to get
* @param mixed $default Optional default value, returned if the requested option does not exist.
*
* @return mixed The option value
*
* @since 1.0
*/
public function getOption($key, $default = null)
{
return $this->options[$key] ?? $default;
}
/**
* Set an option for the OAuth2 Client instance.
*
* @param string $key The name of the option to set
* @param mixed $value The option value to set
*
* @return Client This object for method chaining
*
* @since 1.0
*/
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $this;
}
/**
* Get the access token from the Client instance.
*
* @return array The access token
*
* @since 1.0
*/
public function getToken()
{
return $this->getOption('accesstoken');
}
/**
* Set an option for the Client instance.
*
* @param array $value The access token
*
* @return Client This object for method chaining
*
* @since 1.0
*/
public function setToken($value)
{
if (\is_array($value) && !array_key_exists('expires_in', $value) && array_key_exists('expires', $value))
{
$value['expires_in'] = $value['expires'];
unset($value['expires']);
}
$this->setOption('accesstoken', $value);
return $this;
}
/**
* Refresh the access token instance.
*
* @param string $token The refresh token
*
* @return array The new access token
*
* @since 1.0
* @throws UnexpectedResponseException
* @throws \RuntimeException
*/
public function refreshToken($token = null)
{
if (!$this->getOption('userefresh'))
{
throw new \RuntimeException('Refresh token is not supported for this OAuth instance.');
}
if (!$token)
{
$token = $this->getToken();
if (!array_key_exists('refresh_token', $token))
{
throw new \RuntimeException('No refresh token is available.');
}
$token = $token['refresh_token'];
}
$data = [
'grant_type' => 'refresh_token',
'refresh_token' => $token,
'client_id' => $this->getOption('clientid'),
'client_secret' => $this->getOption('clientsecret'),
];
$response = $this->http->post($this->getOption('tokenurl'), $data);
if (!($response->code >= 200 || $response->code < 400))
{
throw new UnexpectedResponseException(
$response,
sprintf(
'Error code %s received refreshing token: %s.',
$response->code,
$response->body
)
);
}
if (strpos($response->headers['Content-Type'], 'application/json') !== false)
{
$token = array_merge(json_decode($response->body, true), ['created' => time()]);
}
else
{
parse_str($response->body, $token);
$token = array_merge($token, ['created' => time()]);
}
$this->setToken($token);
return $token;
}
}