You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
4.4 KiB

<?php
namespace authkit2\Oidc;
use authkit2\Authkit2;
/**
* OpenId Connect HTTP Client Library
*/
class Client
{
/**
* Authenticator used to authenticate requests we're making
* @var Authentication\Authentication
*/
protected $auth;
/**
* Http client we've initialized with our authentication middleware in
* place
* @var \GuzzleHttp\Client
*/
protected $client;
/**
* Base url of the OIDC realm
* @var string
*/
static $oidc_url;
/**
* OIDC config fetched from the server or restored from cache
* @var array<string,mixed>
*/
static $oidc_config;
/**
* Create a new OIDC client using the passed authentication provider
*
* @param Authentication\Authentication $auth
*/
public function __construct(Authentication\Authentication $auth)
{
$this->auth = $auth;
}
/**
* Retrieve a HTTP client containing our authentication middleware
*
* Constructed on first use
*
* @return \GuzzleHttp\Client
*/
public function getClient(): \GuzzleHttp\Client
{
if (!isset($this->client))
{
$stack = new \GuzzleHttp\HandlerStack();
$stack->setHandler(new \GuzzleHttp\Handler\CurlHandler());
$stack->push($this->auth->getMiddleware());
$this->client = new \GuzzleHttp\Client(['handler' => $stack]);
}
return $this->client;
}
/**
* Retrieve the configured OpenId Connect realm url; null if never set
*
* @return ?string
*/
public static function getUrl(): ?string
{
return static::$oidc_url;
}
/**
* Configure the library with a OpenId Connect realm url
*
* @param string $url
* @return void
*/
public static function setUrl(string $url): void
{
static::$oidc_url = $url;
}
/**
* Set the OpenId Connect configuration
*
* This is provided to allow external caching rather than having us refetch
* the configuration on every invocation of the project.
*
* @param array $config config as retrieved from getOidcConfig()
* @return void
*/
public static function setOidcConfig(array $config): void
{
static::$oidc_config = $config;
}
/**
* Get the OpenId Connect configuration
*
* If not restored/set via setOidcConfig, this will be fetched from the OIDC
* realm on first use
*
* @return array
*/
public static function getOidcConfig(): array
{
if (!isset(static::$oidc_config))
{
static::$oidc_config = Authkit2::cache('oidc.config', function() {
$response = (new \GuzzleHttp\Client())->get(static::$oidc_url.'/.well-known/openid-configuration');
return json_decode($response->getBody(), true);
});
}
return static::$oidc_config;
}
/**
* Fetch a specific OpenId Connect endpoint from the configuration
*
* @param string $endpoint_name
* @return string
*/
public function getEndpointUrl(string $endpoint_name): string
{
return static::getOidcConfig()[$endpoint_name.'_endpoint'];
}
/**
* Determine the final URL to make a request to given an arbitrarily-defined
* 'endpoint'.
*
* If the passed in value is a valid URI, it will be used directly. Otherwise,
* we will attempt to find a configured endpoint with a name matching the
* passed in value in the OIDC config.
*
* @param string $endpoint url or endpoint name
* @return string url to call
*/
protected function parseEndpoint(string $endpoint): string
{
if (filter_var($endpoint, \FILTER_VALIDATE_URL))
{
return $endpoint;
}
else
{
return $this->getEndpointUrl($endpoint);
}
}
/**
* Make a HTTP get request to a OIDC endpoint or other URL
*
* @param string $endpoint url or endpoint name
* @param array<string,scalar> $params query string parameters
* @return object json decoded response
*/
public function get(string $endpoint, array $params = []): object
{
$response = $this->getClient()->get($this->parseEndpoint($endpoint), [
'query' => $params
]);
return json_decode($response->getBody());
}
/**
* Make a HTTP post request to a OIDC endpoint or other URL
*
* If form parameters are provided the request is sent as
* application/x-www-form-urlencoded
*
* @param string $endpoint url or endpoint name
* @param array<string,scalar> $params form fields
* @return object json decoded response
*/
public function post(string $endpoint, array $params = []): object
{
$response = $this->getClient()->post($this->parseEndpoint($endpoint), [
'form_params' => $params
]);
return json_decode($response->getBody());
}
}