primo commit
This commit is contained in:
393
libraries/vendor/joomla/oauth2/src/Client.php
vendored
Normal file
393
libraries/vendor/joomla/oauth2/src/Client.php
vendored
Normal file
@ -0,0 +1,393 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user