salesforce-8.x-4.x-dev/modules/salesforce_jwt/src/Plugin/SalesforceAuthProvider/SalesforceJWTPlugin.php

modules/salesforce_jwt/src/Plugin/SalesforceAuthProvider/SalesforceJWTPlugin.php
<?php

namespace Drupal\salesforce_jwt\Plugin\SalesforceAuthProvider;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\key\KeyRepositoryInterface;
use Drupal\salesforce\SalesforceAuthProviderPluginBase;
use Drupal\salesforce\Storage\SalesforceAuthTokenStorageInterface;
use Firebase\JWT\JWT;
use OAuth\Common\Http\Client\ClientInterface;
use OAuth\Common\Http\Uri\Uri;
use OAuth\Common\Token\TokenInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * JWT Oauth plugin.
 *
 * @Plugin(
 *   id = "jwt",
 *   label = @Translation("Salesforce JWT OAuth"),
 *   credentials_class = "\Drupal\salesforce_jwt\Consumer\JWTCredentials"
 * )
 */
class SalesforceJWTPlugin extends SalesforceAuthProviderPluginBase {

  /**
   * The credentials for this auth plugin.
   *
   * @var \Drupal\salesforce_jwt\Consumer\JWTCredentials
   */
  protected $credentials;

  /**
   * Key repository service.
   *
   * @var \Drupal\key\KeyRepositoryInterface
   */
  protected $keyRepository;

  /**
   * Time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, ClientInterface $httpClient, SalesforceAuthTokenStorageInterface $storage, ConfigFactoryInterface $configFactory, KeyRepositoryInterface $keyRepository, TimeInterface $time) {
    $this->keyRepository = $keyRepository;
    $this->time = $time;
    parent::__construct($configuration, $plugin_id, $plugin_definition, $httpClient, $storage, $configFactory);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $configuration = array_merge(self::defaultConfiguration(), $configuration);
    return new static($configuration, $plugin_id, $plugin_definition, $container->get('salesforce.http_client_wrapper'), $container->get('salesforce.auth_token_storage'), $container->get('config.factory'), $container->get('key.repository'), $container->get('datetime.time'));
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultConfiguration() {
    $defaults = parent::defaultConfiguration();
    return array_merge($defaults, [
      'login_user' => '',
      'encrypt_key' => '',
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function getLoginUrl() {
    return $this->getCredentials()->getLoginUrl();
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    if (!$this->keyRepository->getKeyNamesAsOptions(['type' => 'authentication'])) {
      $this->messenger()
        ->addError($this->t('Please <a href="@href">add an authentication key</a> before creating a JWT Auth provider.', [
          '@href' => Url::fromRoute('entity.key.add_form')
            ->toString(),
        ]));
      return $form;
    }
    $form['consumer_key'] = [
      '#title' => $this->t('Salesforce consumer key'),
      '#type' => 'textfield',
      '#description' => $this->t('Consumer key of the Salesforce remote application you want to grant access to'),
      '#required' => TRUE,
      '#default_value' => $this->getCredentials()->getConsumerKey(),
    ];

    $form['login_user'] = [
      '#title' => $this->t('Salesforce login user'),
      '#type' => 'textfield',
      '#description' => $this->t('User account to issue token to'),
      '#required' => TRUE,
      '#default_value' => $this->getCredentials()->getLoginUser(),
    ];

    $form['login_url'] = [
      '#title' => $this->t('Login URL'),
      '#type' => 'textfield',
      '#default_value' => $this->getCredentials()->getLoginUrl(),
      '#description' => $this->t('Enter a login URL, either https://login.salesforce.com or https://test.salesforce.com.'),
      '#required' => TRUE,
    ];

    // Can't use key-select input type here because its #process method doesn't
    // fire on ajax, so the list is empty. DERP.
    $form['encrypt_key'] = [
      '#title' => 'Private Key',
      '#type' => 'select',
      '#empty_option' => $this->t('- Select -'),
      '#options' => $this->keyRepository->getKeyNamesAsOptions(['type' => 'authentication']),
      '#required' => TRUE,
      '#default_value' => $this->getCredentials()->getKeyId(),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
    parent::validateConfigurationForm($form, $form_state);
    if (empty($form_state->getValue('provider_settings')) && $form_state->getValue('provider_settings') == self::defaultConfiguration()) {
      $form_state->setError($form, $this->t('Please fill in JWT provider settings.'));
      return;
    }
    $this->setConfiguration($form_state->getValue('provider_settings'));
    // Force new credentials from form input, rather than storage.
    unset($this->credentials);
    try {
      // Bootstrap here by setting ID to provide a key to token storage.
      $this->id = $form_state->getValue('id');
      $this->requestAccessToken($this->generateAssertion());
    }
    catch (\Exception $e) {
      $form_state->setError($form, $e->getMessage());
    }
  }

  /**
   * Overrides AbstractService::requestAccessToken for jwt-bearer flow.
   *
   * @param string $assertion
   *   The JWT assertion.
   * @param string $state
   *   Not used.
   *
   * @return \OAuth\Common\Token\TokenInterface
   *   Access Token.
   *
   * @throws \OAuth\Common\Http\Exception\TokenResponseException
   */
  public function requestAccessToken($assertion, $state = NULL) {
    $data = [
      'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      'assertion' => $assertion,
    ];
    $response = $this->httpClient->retrieveResponse(new Uri($this->getLoginUrl() . static::AUTH_TOKEN_PATH), $data, ['Content-Type' => 'application/x-www-form-urlencoded']);
    $token = $this->parseAccessTokenResponse($response);
    $this->storage->storeAccessToken($this->service(), $token);
    $this->refreshIdentity($token);
    return $token;
  }

  /**
   * {@inheritDoc}
   */
  public function refreshAccessToken(TokenInterface $token) {
    $token = $this->requestAccessToken($this->generateAssertion());
    $this->refreshIdentity($token);
    return $token;
  }

  /**
   * Returns a JWT Assertion to authenticate.
   *
   * @return string
   *   JWT Assertion.
   */
  protected function generateAssertion() {
    $key = $this->keyRepository->getKey($this->getCredentials()->getKeyId()) ?
      $this->keyRepository->getKey($this->getCredentials()->getKeyId())
        ->getKeyValue() : '';
    $token = $this->generateAssertionClaim();
    return JWT::encode($token, $key, 'RS256');
  }

  /**
   * Returns a JSON encoded JWT Claim.
   *
   * @return array
   *   The claim array.
   */
  protected function generateAssertionClaim() {
    $cred = $this->getCredentials();
    return [
      'iss' => $cred->getConsumerKey(),
      'sub' => $cred->getLoginUser(),
      'aud' => $cred->getLoginUrl(),
      'exp' => $this->time->getCurrentTime() + 60,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getPluginDefinition() {
    $definition = parent::getPluginDefinition();
    if ($this->configuration['encrypt_key'] && $key = $this->keyRepository->getKey($this->configuration['encrypt_key'])) {
      $definition['config_dependencies']['config'][] = $key->getConfigDependencyName();
    }
    return $definition;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc