abstract class OpenIDConnectClientBase in OpenID Connect / OAuth client 2.x
Same name and namespace in other branches
- 8 src/Plugin/OpenIDConnectClientBase.php \Drupal\openid_connect\Plugin\OpenIDConnectClientBase
Base class for OpenID Connect client plugins.
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\openid_connect\Plugin\OpenIDConnectClientBase implements ContainerFactoryPluginInterface, OpenIDConnectClientInterface uses PluginWithFormsTrait, StringTranslationTrait
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of OpenIDConnectClientBase
6 files declare their use of OpenIDConnectClientBase
- OpenIDConnectFacebookClient.php in src/
Plugin/ OpenIDConnectClient/ OpenIDConnectFacebookClient.php - OpenIDConnectGenericClient.php in src/
Plugin/ OpenIDConnectClient/ OpenIDConnectGenericClient.php - OpenIDConnectGithubClient.php in src/
Plugin/ OpenIDConnectClient/ OpenIDConnectGithubClient.php - OpenIDConnectGoogleClient.php in src/
Plugin/ OpenIDConnectClient/ OpenIDConnectGoogleClient.php - OpenIDConnectLinkedinClient.php in src/
Plugin/ OpenIDConnectClient/ OpenIDConnectLinkedinClient.php
File
- src/
Plugin/ OpenIDConnectClientBase.php, line 30
Namespace
Drupal\openid_connect\PluginView source
abstract class OpenIDConnectClientBase extends PluginBase implements OpenIDConnectClientInterface, ContainerFactoryPluginInterface {
use StringTranslationTrait;
use PluginWithFormsTrait;
/**
* The request stack used to access request globals.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The HTTP client to fetch the feed data with.
*
* @var \GuzzleHttp\ClientInterface
*/
protected $httpClient;
/**
* The logger factory used for logging.
*
* @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
*/
protected $loggerFactory;
/**
* The datetime.time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $dateTime;
/**
* Page cache kill switch.
*
* @var \Drupal\Core\PageCache\ResponsePolicy\KillSwitch
*/
protected $pageCacheKillSwitch;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The OpenID state token service.
*
* @var \Drupal\openid_connect\OpenIDConnectStateTokenInterface
*/
protected $stateToken;
/**
* The OpenID well-known discovery service.
*
* @var \Drupal\openid_connect\OpenIDConnectAutoDiscover
*/
protected $autoDiscover;
/**
* The parent entity identifier.
*
* @var string
*/
protected $parentEntityId;
/**
* The constructor.
*
* @param array $configuration
* The plugin configuration.
* @param string $plugin_id
* The plugin identifier.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \GuzzleHttp\ClientInterface $http_client
* The http client.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
* The logger factory.
* @param \Drupal\Component\Datetime\TimeInterface $datetime_time
* The datetime.time service.
* @param \Drupal\Core\PageCache\ResponsePolicy\KillSwitch $page_cache_kill_switch
* Policy evaluating to static::DENY when the kill switch was triggered.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\openid_connect\OpenIDConnectStateTokenInterface $state_token
* The OpenID state token service.
* @param \Drupal\openid_connect\OpenIDConnectAutoDiscover $auto_discover
* The OpenID well-known discovery service.
*/
public function __construct(array $configuration, string $plugin_id, $plugin_definition, RequestStack $request_stack, ClientInterface $http_client, LoggerChannelFactoryInterface $logger_factory, TimeInterface $datetime_time, KillSwitch $page_cache_kill_switch, LanguageManagerInterface $language_manager, OpenIDConnectStateTokenInterface $state_token, OpenIDConnectAutoDiscover $auto_discover) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->requestStack = $request_stack;
$this->httpClient = $http_client;
$this->loggerFactory = $logger_factory;
$this->dateTime = $datetime_time;
$this->pageCacheKillSwitch = $page_cache_kill_switch;
$this->languageManager = $language_manager;
$this->stateToken = $state_token;
$this->autoDiscover = $auto_discover;
$this->parentEntityId = '';
$this
->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('request_stack'), $container
->get('http_client'), $container
->get('logger.factory'), $container
->get('datetime.time'), $container
->get('page_cache_kill_switch'), $container
->get('language_manager'), $container
->get('openid_connect.state_token'), $container
->get('openid_connect.autodiscover'));
}
/**
* {@inheritdoc}
*/
public function getLabel() : string {
return $this->pluginDefinition['label'];
}
/**
* {@inheritdoc}
*/
public function getConfiguration() : array {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$current_configuration = $this->configuration ?: $this
->defaultConfiguration();
$this->configuration = array_merge($current_configuration, $configuration);
}
/**
* Unsets some elements of the configuration.
*
* @param array $keys
* Array of keys to unset.
*/
protected function unsetConfigurationKeys(array $keys) {
foreach ($keys as $key) {
if (isset($this->configuration[$key])) {
unset($this->configuration[$key]);
}
}
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() : array {
return [
'client_id' => '',
'client_secret' => '',
];
}
/**
* {@inheritdoc}
*/
public function setParentEntityId(string $entity_id) {
$this->parentEntityId = $entity_id;
}
/**
* {@inheritdoc}
*/
public function getParentEntityId() : string {
return $this->parentEntityId;
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() : array {
return [];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) : array {
$form['client_id'] = [
'#title' => $this
->t('Client ID'),
'#type' => 'textfield',
'#default_value' => $this->configuration['client_id'],
'#required' => TRUE,
];
$form['client_secret'] = [
'#title' => $this
->t('Client secret'),
'#type' => 'textarea',
'#default_value' => $this->configuration['client_secret'],
'#required' => TRUE,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function getClientScopes() : ?array {
return [
'openid',
'email',
];
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
// Empty function. Can be overridden by derived classes if required.
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
// Empty function. Can be overridden by derived classes if required.
}
/**
* {@inheritdoc}
*/
public function authorize(string $scope = 'openid email') : Response {
$redirect_uri = $this
->getRedirectUrl()
->toString(TRUE);
$url_options = $this
->getUrlOptions($scope, $redirect_uri);
$endpoints = $this
->getEndpoints();
// Clear _GET['destination'] because we need to override it.
$this->requestStack
->getCurrentRequest()->query
->remove('destination');
$authorization_endpoint = Url::fromUri($endpoints['authorization'], $url_options)
->toString(TRUE);
$this->loggerFactory
->get('openid_connect_' . $this->pluginId)
->debug('Send authorize request to @url', [
'@url' => $authorization_endpoint
->getGeneratedUrl(),
]);
$response = new TrustedRedirectResponse($authorization_endpoint
->getGeneratedUrl());
// We can't cache the response, since this will prevent the state to be
// added to the session. The kill switch will prevent the page getting
// cached for anonymous users when page cache is active.
$this->pageCacheKillSwitch
->trigger();
return $response;
}
/**
* Helper function for URL options.
*
* @param string $scope
* A string of scopes.
* @param \Drupal\Core\GeneratedUrl $redirect_uri
* URI to redirect for authorization.
*
* @return array
* Array with URL options.
*/
protected function getUrlOptions(string $scope, GeneratedUrl $redirect_uri) : array {
return [
'query' => [
'client_id' => $this->configuration['client_id'],
'response_type' => 'code',
'scope' => $scope,
'redirect_uri' => $redirect_uri
->getGeneratedUrl(),
'state' => $this->stateToken
->generateToken(),
],
];
}
/**
* Helper function for request options.
*
* @param string $authorization_code
* Authorization code received as a result of the the authorization request.
* @param string $redirect_uri
* URI to redirect for authorization.
*
* @return array
* Array with request options.
*/
protected function getRequestOptions(string $authorization_code, string $redirect_uri) : array {
return [
'form_params' => [
'code' => $authorization_code,
'client_id' => $this->configuration['client_id'],
'client_secret' => $this->configuration['client_secret'],
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code',
],
'headers' => [
'Accept' => 'application/json',
],
];
}
/**
* {@inheritdoc}
*/
public function retrieveTokens(string $authorization_code) : ?array {
// Exchange `code` for access token and ID token.
$redirect_uri = $this
->getRedirectUrl()
->toString();
$endpoints = $this
->getEndpoints();
$request_options = $this
->getRequestOptions($authorization_code, $redirect_uri);
$client = $this->httpClient;
try {
$response = $client
->post($endpoints['token'], $request_options);
$response_data = Json::decode((string) $response
->getBody());
// Expected result.
if (is_array($response_data)) {
$tokens = [];
if (isset($response_data['id_token'])) {
$tokens['id_token'] = $response_data['id_token'];
}
if (isset($response_data['access_token'])) {
$tokens['access_token'] = $response_data['access_token'];
}
if (array_key_exists('expires_in', $response_data)) {
$tokens['expire'] = $this->dateTime
->getRequestTime() + $response_data['expires_in'];
}
if (array_key_exists('refresh_token', $response_data)) {
$tokens['refresh_token'] = $response_data['refresh_token'];
}
return $tokens;
}
} catch (\Exception $e) {
$error_message = $e
->getMessage();
if ($e instanceof RequestException && $e
->hasResponse()) {
$error_message .= ' Response: ' . $e
->getResponse()
->getBody()
->getContents();
}
$this->loggerFactory
->get('openid_connect_' . $this->pluginId)
->error('Could not retrieve tokens. Details: @error_message', [
'@error_message' => $error_message,
]);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function retrieveUserInfo(string $access_token) : ?array {
$request_options = [
'headers' => [
'Authorization' => 'Bearer ' . $access_token,
'Accept' => 'application/json',
],
];
$endpoints = $this
->getEndpoints();
try {
$response = $this->httpClient
->get($endpoints['userinfo'], $request_options);
$userinfo = Json::decode((string) $response
->getBody());
$this->loggerFactory
->get('openid_connect_' . $this->pluginId)
->debug('Response from userinfo endpoint: @userinfo', [
'@userinfo' => print_r($userinfo, TRUE),
]);
return is_array($userinfo) ? $userinfo : NULL;
} catch (\Exception $e) {
$error = $e
->getMessage();
if ($e instanceof RequestException && $e
->hasResponse()) {
$response_body = $e
->getResponse()
->getBody()
->getContents();
$error .= ' Response: ' . $response_body;
}
$this->loggerFactory
->get('openid_connect_' . $this->pluginId)
->error('Could not retrieve user profile information. Details: @error_message', [
'@error_message' => $error,
]);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function usesUserInfo() : bool {
return !empty($this
->getEndpoints()['userinfo']);
}
/**
* Returns the redirect URL.
*
* @param array $route_parameters
* See \Drupal\Core\Url::fromRoute() for details.
* @param array $options
* See \Drupal\Core\Url::fromRoute() for details.
*
* @return \Drupal\Core\Url
* A new Url object for a routed (internal to Drupal) URL.
*
* @see \Drupal\Core\Url::fromRoute()
*/
protected function getRedirectUrl(array $route_parameters = [], array $options = []) : Url {
$route_parameters += [
'openid_connect_client' => $this->parentEntityId,
];
$options += [
'absolute' => TRUE,
'language' => $this->languageManager
->getLanguage(LanguageInterface::LANGCODE_NOT_APPLICABLE),
];
return Url::fromRoute('openid_connect.redirect_controller_redirect', $route_parameters, $options);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
OpenIDConnectClientBase:: |
protected | property | The OpenID well-known discovery service. | |
OpenIDConnectClientBase:: |
protected | property | The datetime.time service. | |
OpenIDConnectClientBase:: |
protected | property | The HTTP client to fetch the feed data with. | |
OpenIDConnectClientBase:: |
protected | property | The language manager. | |
OpenIDConnectClientBase:: |
protected | property | The logger factory used for logging. | |
OpenIDConnectClientBase:: |
protected | property | Page cache kill switch. | |
OpenIDConnectClientBase:: |
protected | property | The parent entity identifier. | |
OpenIDConnectClientBase:: |
protected | property | The request stack used to access request globals. | |
OpenIDConnectClientBase:: |
protected | property | The OpenID state token service. | |
OpenIDConnectClientBase:: |
public | function |
Redirects the user to the authorization endpoint. Overrides OpenIDConnectClientInterface:: |
3 |
OpenIDConnectClientBase:: |
public | function |
Form constructor. Overrides PluginFormInterface:: |
6 |
OpenIDConnectClientBase:: |
public | function |
Calculates dependencies for the configured plugin. Overrides DependentPluginInterface:: |
|
OpenIDConnectClientBase:: |
public static | function |
Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Gets default configuration for this plugin. Overrides ConfigurableInterface:: |
3 |
OpenIDConnectClientBase:: |
public | function |
Gets an array of of scopes. Overrides OpenIDConnectClientInterface:: |
2 |
OpenIDConnectClientBase:: |
public | function |
Gets this plugin's configuration. Overrides ConfigurableInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Return the plugin label as defined in the annotation. Overrides OpenIDConnectClientInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Returns the parent entity ID. Overrides OpenIDConnectClientInterface:: |
|
OpenIDConnectClientBase:: |
protected | function | Returns the redirect URL. | |
OpenIDConnectClientBase:: |
protected | function | Helper function for request options. | |
OpenIDConnectClientBase:: |
protected | function | Helper function for URL options. | |
OpenIDConnectClientBase:: |
public | function |
Retrieve access token and ID token. Overrides OpenIDConnectClientInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Retrieves user info: additional user profile data. Overrides OpenIDConnectClientInterface:: |
4 |
OpenIDConnectClientBase:: |
public | function |
Sets the configuration for this plugin instance. Overrides ConfigurableInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Sets the parent entity ID. Overrides OpenIDConnectClientInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Form submission handler. Overrides PluginFormInterface:: |
2 |
OpenIDConnectClientBase:: |
protected | function | Unsets some elements of the configuration. | |
OpenIDConnectClientBase:: |
public | function |
Check if the client uses the userinfo endpoint. Overrides OpenIDConnectClientInterface:: |
|
OpenIDConnectClientBase:: |
public | function |
Form validation handler. Overrides PluginFormInterface:: |
1 |
OpenIDConnectClientBase:: |
public | function |
The constructor. Overrides PluginBase:: |
|
OpenIDConnectClientInterface:: |
public | function | Returns an array of endpoints. | 6 |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
2 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PluginWithFormsTrait:: |
public | function | Implements \Drupal\Core\Plugin\PluginWithFormsInterface::getFormClass(). | |
PluginWithFormsTrait:: |
public | function | Implements \Drupal\Core\Plugin\PluginWithFormsInterface::hasFormClass(). | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |