joomla_test/libraries/joomla/oauth2/client.php
2020-01-02 22:20:31 +07:00

377 lines
8.9 KiB
PHP

<?php
/**
* @package Joomla.Platform
* @subpackage Oauth
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
jimport('joomla.environment.response');
/**
* Joomla Platform class for interacting with an OAuth 2.0 server.
*
* @package Joomla.Platform
* @subpackage Oauth
* @since 12.3
*/
class JOAuth2Client
{
/**
* @var JRegistry Options for the JOAuth2Client object.
* @since 12.3
*/
protected $options;
/**
* @var JHttp The HTTP client object to use in sending HTTP requests.
* @since 12.3
*/
protected $http;
/**
* @var JInput The input object to use in retrieving GET/POST data.
* @since 12.3
*/
protected $input;
/**
* @var JApplicationWeb The application object to send HTTP headers for redirects.
* @since 12.3
*/
protected $application;
/**
* Constructor.
*
* @param JRegistry $options JOAuth2Client options object
* @param JHttp $http The HTTP client object
* @param JInput $input The input object
* @param JApplicationWeb $application The application object
*
* @since 12.3
*/
public function __construct(JRegistry $options = null, JHttp $http = null, JInput $input = null, JApplicationWeb $application = null)
{
$this->options = isset($options) ? $options : new JRegistry;
$this->http = isset($http) ? $http : new JHttp($this->options);
$this->input = isset($input) ? $input : JFactory::getApplication()->input;
$this->application = isset($application) ? $application : new JApplicationWeb;
}
/**
* Get the access token or redict to the authentication URL.
*
* @return string The access token
*
* @since 12.3
*/
public function authenticate()
{
if ($data['code'] = $this->input->get('code', false, 'raw'))
{
$data['grant_type'] = 'authorization_code';
$data['redirect_uri'] = $this->getOption('redirecturi');
$data['client_id'] = $this->getOption('clientid');
$data['client_secret'] = $this->getOption('clientsecret');
$response = $this->http->post($this->getOption('tokenurl'), $data);
if ($response->code >= 200 && $response->code < 400)
{
if ($response->headers['Content-Type'] == 'application/json')
{
$token = array_merge(json_decode($response->body, true), array('created' => time()));
}
else
{
parse_str($response->body, $token);
$token = array_merge($token, array('created' => time()));
}
$this->setToken($token);
return $token;
}
else
{
throw new RuntimeException('Error code ' . $response->code . ' received requesting access token: ' . $response->body . '.');
}
}
if ($this->getOption('sendheaders'))
{
$this->application->redirect($this->createUrl());
}
return false;
}
/**
* Verify if the client has been authenticated
*
* @return boolean Is authenticated
*
* @since 12.3
*/
public function isAuthenticated()
{
$token = $this->getToken();
if (!$token || !array_key_exists('access_token', $token))
{
return false;
}
elseif (array_key_exists('expires_in', $token) && $token['created'] + $token['expires_in'] < time() + 20)
{
return false;
}
else
{
return true;
}
}
/**
* Create the URL for authentication.
*
* @return JHttpResponse The HTTP response
*
* @since 12.3
*/
public function createUrl()
{
if (!$this->getOption('authurl') || !$this->getOption('clientid'))
{
throw new InvalidArgumentException('Authorization URL and client_id are required');
}
$url = $this->getOption('authurl');
if (strpos($url, '?'))
{
$url .= '&';
}
else
{
$url .= '?';
}
$url .= 'response_type=code';
$url .= '&client_id=' . urlencode($this->getOption('clientid'));
if ($this->getOption('redirecturi'))
{
$url .= '&redirect_uri=' . urlencode($this->getOption('redirecturi'));
}
if ($this->getOption('scope'))
{
$scope = is_array($this->getOption('scope')) ? implode(' ', $this->getOption('scope')) : $this->getOption('scope');
$url .= '&scope=' . urlencode($scope);
}
if ($this->getOption('state'))
{
$url .= '&state=' . urlencode($this->getOption('state'));
}
if (is_array($this->getOption('requestparams')))
{
foreach ($this->getOption('requestparams') as $key => $value)
{
$url .= '&' . $key . '=' . urlencode($value);
}
}
return $url;
}
/**
* Send a signed Oauth request.
*
* @param string $url The URL forf the request.
* @param mixed $data The data to include in the request
* @param array $headers The headers to send with the request
* @param string $method The method with which to send the request
* @param int $timeout The timeout for the request
*
* @return string The URL.
*
* @since 12.3
*/
public function query($url, $data = null, $headers = array(), $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']);
}
if (!$this->getOption('authmethod') || $this->getOption('authmethod') == 'bearer')
{
$headers['Authorization'] = 'Bearer ' . $token['access_token'];
}
elseif ($this->getOption('authmethod') == 'get')
{
if (strpos($url, '?'))
{
$url .= '&';
}
else
{
$url .= '?';
}
$url .= $this->getOption('getparam') ? $this->getOption('getparam') : 'access_token';
$url .= '=' . $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 RuntimeException('Error code ' . $response->code . ' received requesting data: ' . $response->body . '.');
}
return $response;
}
/**
* Get an option from the JOAuth2Client instance.
*
* @param string $key The name of the option to get
*
* @return mixed The option value
*
* @since 12.3
*/
public function getOption($key)
{
return $this->options->get($key);
}
/**
* Set an option for the JOAuth2Client instance.
*
* @param string $key The name of the option to set
* @param mixed $value The option value to set
*
* @return JOAuth2Client This object for method chaining
*
* @since 12.3
*/
public function setOption($key, $value)
{
$this->options->set($key, $value);
return $this;
}
/**
* Get the access token from the JOAuth2Client instance.
*
* @return array The access token
*
* @since 12.3
*/
public function getToken()
{
return $this->getOption('accesstoken');
}
/**
* Set an option for the JOAuth2Client instance.
*
* @param array $value The access token
*
* @return JOAuth2Client This object for method chaining
*
* @since 12.3
*/
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 12.3
*/
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';
$data['refresh_token'] = $token;
$data['client_id'] = $this->getOption('clientid');
$data['client_secret'] = $this->getOption('clientsecret');
$response = $this->http->post($this->getOption('tokenurl'), $data);
if ($response->code >= 200 || $response->code < 400)
{
if ($response->headers['Content-Type'] == 'application/json')
{
$token = array_merge(json_decode($response->body, true), array('created' => time()));
}
else
{
parse_str($response->body, $token);
$token = array_merge($token, array('created' => time()));
}
$this->setToken($token);
return $token;
}
else
{
throw new Exception('Error code ' . $response->code . ' received refreshing token: ' . $response->body . '.');
}
}
}