View source
<?php
declare (strict_types=1);
namespace Drupal\entity_share_client\Plugin\ClientAuthorization;
use Drupal\Core\Form\FormStateInterface;
use Drupal\entity_share_client\ClientAuthorization\ClientAuthorizationPluginBase;
use Drupal\entity_share_client\Entity\Remote;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Provider\GenericProvider;
use League\OAuth2\Client\Token\AccessTokenInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Oauth extends ClientAuthorizationPluginBase {
protected $messenger;
protected $logger;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->messenger = $container
->get('messenger');
$instance->logger = $container
->get('logger.channel.entity_share_client');
return $instance;
}
public function checkIfAvailable() {
return TRUE;
}
protected function getAccessToken($url) {
$configuration = $this
->getConfiguration();
$accessToken = $this->keyValueStore
->get($configuration['uuid'] . '-' . $this
->getPluginId());
$credentials = $this->keyService
->getCredentials($this);
if ($accessToken instanceof AccessTokenInterface) {
if ($accessToken
->hasExpired()) {
$oauth_client = $this
->getOauthClient($url, $credentials);
try {
$newAccessToken = $oauth_client
->getAccessToken('refresh_token', [
'refresh_token' => $accessToken
->getRefreshToken(),
]);
} catch (\Throwable $e) {
$this->logger
->critical('Entity Share refresh oauth token request failed with Exception: %exception_type and error: %error.', [
'%exception_type' => get_class($e),
'%error' => $e
->getMessage(),
]);
try {
$newAccessToken = $oauth_client
->getAccessToken('client_credentials');
} catch (\Throwable $e) {
$this->logger
->critical('Entity Share new oauth token request failed with Exception: %exception_type and error: %error.', [
'%exception_type' => get_class($e),
'%error' => $e
->getMessage(),
]);
return '';
}
}
$this->keyValueStore
->set($configuration['uuid'] . '-' . $this
->getPluginId(), $newAccessToken);
return $newAccessToken
->getToken();
}
return $accessToken
->getToken();
}
return '';
}
public function getClient($url) {
$token = $this
->getAccessToken($url);
return $this->httpClientFactory
->fromOptions([
'base_uri' => $url . '/',
'allow_redirects' => TRUE,
'headers' => [
'Authorization' => 'Bearer ' . $token,
],
]);
}
public function getJsonApiClient($url) {
$token = $this
->getAccessToken($url);
return $this->httpClientFactory
->fromOptions([
'base_uri' => $url . '/',
'headers' => [
'Content-type' => 'application/vnd.api+json',
'Authorization' => 'Bearer ' . $token,
],
]);
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['entity_share']['#title'] = $this
->t('Oauth using <em>Resource owner password credentials</em> grant');
$form['entity_share']['#description'] = $this
->t('A token will be requested and saved in State storage when this form is submitted. The username and password entered here are not saved, but are only used to request the token.');
$form['entity_share']['username'] = [
'#type' => 'textfield',
'#title' => $this
->t('Username'),
];
$form['entity_share']['password'] = [
'#type' => 'password',
'#title' => $this
->t('Password'),
];
$credentials = $this->keyService
->getCredentials($this);
$form['entity_share']['client_id'] = [
'#type' => 'textfield',
'#title' => $this
->t('Client ID'),
'#default_value' => $credentials['client_id'] ?? '',
];
$form['entity_share']['client_secret'] = [
'#type' => 'password',
'#title' => $this
->t('Client secret'),
];
$form['entity_share']['authorization_path'] = [
'#type' => 'textfield',
'#title' => $this
->t('Authorization path on the remote website'),
'#default_value' => $credentials['authorization_path'] ?? '/oauth/authorize',
];
$form['entity_share']['token_path'] = [
'#type' => 'textfield',
'#title' => $this
->t('Token path on the remote website'),
'#default_value' => $credentials['token_path'] ?? '/oauth/token',
];
if ($this->keyService
->additionalProviders()) {
$this
->expandedProviderOptions($form);
$form['key']['#description'] = $this
->t('A token will be requested and saved in State storage when this form is submitted. The username and password entered here are not saved, but are only used to request the token.');
$form['key']['username'] = [
'#type' => 'textfield',
'#title' => $this
->t('Username'),
];
$form['key']['password'] = [
'#type' => 'password',
'#title' => $this
->t('Password'),
];
$form['key']['id']['#key_filters'] = [
'type' => 'entity_share_oauth',
];
$form['key']['id']['#description'] = $this
->t('Select the key you have configured to hold the Oauth credentials.');
}
return $form;
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
$configuration = $this
->getConfiguration();
$remote = $form_state
->get('remote');
$resetConfiguration = $configuration;
$provider = $values['credential_provider'];
$credentials = $values[$provider];
array_walk($credentials, function (&$value) {
$value = trim($value);
});
$key = $configuration['uuid'];
if ($provider == 'key') {
$key = $credentials['id'];
}
$configuration['data'] = [
'credential_provider' => $provider,
'storage_key' => $key,
];
$this
->setConfiguration($configuration);
try {
switch ($provider) {
case 'key':
$requestCredentials = $this->keyService
->getCredentials($this);
$requestCredentials['username'] = $credentials['username'];
$requestCredentials['password'] = $credentials['password'];
$accessToken = $this
->initializeToken($remote, $requestCredentials);
$this->keyValueStore
->delete($configuration['uuid']);
break;
default:
$accessToken = $this
->initializeToken($remote, $credentials);
unset($credentials['username']);
unset($credentials['password']);
$this->keyValueStore
->set($configuration['uuid'], $credentials);
}
$this->keyValueStore
->set($configuration['uuid'] . '-' . $this
->getPluginId(), $accessToken);
$this->messenger
->addStatus($this
->t('OAuth token obtained from remote website and stored.'));
} catch (IdentityProviderException $e) {
$this
->setConfiguration($resetConfiguration);
$this->messenger
->addError($this
->t('Unable to obtain an OAuth token. The error message is: @message', [
'@message' => $e
->getMessage(),
]));
}
}
protected function getOauthClient(string $url, array $credentials) {
$oauth_client = new GenericProvider([
'clientId' => $credentials['client_id'],
'clientSecret' => $credentials['client_secret'],
'urlAuthorize' => $url . $credentials['authorization_path'],
'urlAccessToken' => $url . $credentials['token_path'],
'urlResourceOwnerDetails' => '',
], [
'httpClient' => $this->httpClientFactory
->fromOptions(),
]);
return $oauth_client;
}
public function initalizeToken(Remote $remote, array $credentials) {
@trigger_error(__METHOD__ . '() is deprecated in 8.x-3.0-beta4 and will be removed in 4.0.0. use initializeToken() instead.', \E_USER_DEPRECATED);
$this
->initializeToken($remote, $credentials);
}
public function initializeToken(Remote $remote, array $credentials) {
$oauth_client = $this
->getOauthClient($remote
->get('url'), $credentials);
return $oauth_client
->getAccessToken('password', [
'username' => $credentials['username'],
'password' => $credentials['password'],
]);
}
}