docusign_signature-1.0.x-dev/src/DocuSignAuth/Jwt.php

src/DocuSignAuth/Jwt.php
<?php

declare(strict_types=1);

namespace Drupal\docusign_signature\DocuSignAuth;

use DocuSign\eSign\Client\ApiClient;
use DocuSign\eSign\Client\Auth\OAuthToken;
use DocuSign\eSign\Configuration;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\docusign_signature\Auth\DocuSign;
use Drupal\docusign_signature\AuthBase;
use Firebase\JWT\BeforeValidException;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * DocuSign authentication with JSON Web Token (JWT).
 *
 * @package Drupal\docusign_signature\DocuSignAuth
 *
 * @DocuSignAuth(
 *   id = "jwt",
 *   label = @Translation("JSON Web Token (JWT)")
 * )
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Jwt extends AuthBase {

  /**
   * DocuSign OAuth token object.
   *
   * @var \DocuSign\eSign\Client\Auth\OAuthToken
   */
  private static OAuthToken $accessToken;

  /**
   * The DocuSign API Client object.
   *
   * @var \DocuSign\eSign\Client\ApiClient
   */
  private ApiClient $apiClient;

  /**
   * {@inheritdoc}
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    LoggerInterface $logger,
    PrivateTempStoreFactory $temp_store_factory
  ) {
    parent::__construct($config_factory, $logger, $temp_store_factory);

    $config = new Configuration();
    $this->apiClient = new ApiClient($config);
  }

  /**
   * {@inheritdoc}
   *
   * @throws \DocuSign\eSign\Client\ApiException
   * @throws \Drupal\Core\TempStore\TempStoreException
   */
  public function authCallback(string $redirectUrl = NULL): RedirectResponse {
    // Check given state against previously stored one to mitigate CSRF attack.
    if (empty(self::$accessToken)) {
      throw new BeforeValidException('Invalid JWT state.');
    }

    try {
      // We have an access token, which we may use in authenticated
      // requests against the service provider's API.
      $this->tempStore->get('access_token', self::$accessToken->getAccessToken());
      $this->tempStore->get('expiration',
        \Drupal::time()->getCurrentTime() + self::$accessToken->getExpiresIn() * 60
      );

      /** @var \DocuSign\eSign\Client\Auth\UserInfo $user */
      $user = $this->apiClient->getUserInfo(self::$accessToken->getAccessToken())[0];

      /** @var \DocuSign\eSign\Client\Auth\Account $accountInfo */
      $accountInfo = $user->getAccounts();

      $this->tempStore->set('user', $user);
      $this->tempStore->set('account_id', $accountInfo->getAccountId());
      $this->tempStore->set('base_path', $accountInfo->getBaseUri() . self::BASE_URI_SUFFIX);
    }
    catch (IdentityProviderException $e) {
      // Failed to get the access token or user details.
      \Drupal::messenger()->addError($e->getMessage());
    }

    return parent::authCallback($redirectUrl);
  }

  /**
   * Get JWT auth by RSA key.
   *
   * @return void|\DocuSign\eSign\Client\Auth\OAuthToken
   *   A OAuth token object.
   *
   * @throws \Drupal\Core\TempStore\TempStoreException
   */
  private function configureJwtAuthorizationFlowByKey(): ?OAuthToken {
    $this->apiClient->getOAuth()->setOAuthBasePath(self::AUTHORIZATION_URL);
    $privateKey = file_get_contents($this->config->get('private_key_file'), TRUE);
    $scope = (new DocuSign())->getDefaultScopes()[0];

    // Make sure to add the "impersonation" scope when using JWT authorization.
    $jwt_scope = $scope . ' impersonation';
    $this->tempStore->set('jwt_scope', $jwt_scope);

    try {
      $response = $this->apiClient->requestJWTUserToken(
        $this->config->get('client_id'),
        $this->config->get('impersonated_user_id'),
        $privateKey,
        $jwt_scope,
        );

      return reset($response);
    }
    catch (\Throwable $th) {
      // We found consent_required in the response body
      // meaning first time consent is needed.
      if (strpos($th->getMessage(), 'consent_required') !== FALSE) {
        $this->tempStore->set('consent_set', TRUE);
      }
    }

    return NULL;
  }

  /**
   * {@inheritdoc}
   *
   * @throws \DocuSign\eSign\Client\ApiException
   * @throws \Drupal\Core\TempStore\TempStoreException
   */
  public function login(): RedirectResponse {
    self::$accessToken = $this->configureJwtAuthorizationFlowByKey();

    if (
      !self::$accessToken &&
      $this->tempStore->get('consent_set') === TRUE
    ) {
      $authorizationURL = $this->getAutohorizationUrl() . 'oauth/http?' . http_build_query([
        'scope' => $this->tempStore->get('jwt_scope'),
        'redirect_uri' => Url::fromRoute('docusign_signature.callback.oauth', [], ['absolute' => TRUE])->toString(TRUE)->getGeneratedUrl(),
        'client_id' => $this->config->get('client_id'),
        'state' => $this->tempStore->get('oauth2state'),
        'response_type' => 'code',
      ]);

      return new RedirectResponse($authorizationURL);
    }

    return $this->authCallback(
      Url::fromRoute('<current>', [], ['absolute' => TRUE])->toString(TRUE)->getGeneratedUrl()
    );
  }

}

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

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