bankid_oidc-1.x-dev/src/Controller/LoginController.php

src/Controller/LoginController.php
<?php

namespace Drupal\bankid_oidc\Controller;

use BankID\OAuth2\Client\Provider\BankIdProvider;
use Drupal\bankid_oidc\BankIdAuthInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Url;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Class LoginController.
 */
class LoginController extends ControllerBase {

  protected const SESSION_OAUTH_STATE_NAME = 'bankid_oidc_state';

  /**
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $moduleConfig;

  /**
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * @var \Drupal\externalauth\ExternalAuthInterface
   */
  protected $userAuth;

  /**
   * @var \BankID\OAuth2\Client\Provider\BankIdProvider
   */
  protected $oauthClient;

  protected function userAuth(): BankIdAuthInterface {
    if (!$this->userAuth) {
      $this->userAuth = \Drupal::service('bankid_oidc.user_auth');
    }
    return $this->userAuth;
  }

  protected function logger(): LoggerInterface {
    if (!$this->logger) {
      $this->logger = $this->getLogger('bankid_oidc');
    }

    return $this->logger;
  }

  protected function oauthClient(): BankIdProvider {
    if (!$this->oauthClient) {
      $this->oauthClient = $this->userAuth()->oauthClient();
    }

    return $this->oauthClient;
  }


  /**
   * Returns one configuration item or the whole config for this module.
   *
   * @param string|null $name
   *  Optional: Return only 1 config item.
   *
   * @return \Drupal\Core\Config\ImmutableConfig|mixed
   */
  protected function getConfig(string $name = NULL) {
    if (!$this->moduleConfig) {
      $this->moduleConfig = $this->config('bankid_oidc.config');
    }

    return ($name) ? $this->moduleConfig->get($name) : $this->moduleConfig;
  }

  public function login(Request $request) {
    if (\Drupal::currentUser()->isAuthenticated()) {
      throw new AccessDeniedHttpException('User already authenticated.');
    }

    $authorizationUrl = $this->oauthClient()->getAuthorizationUrl();
    $this->setSessionState($request, $this->oauthClient()->getState());

    $destination = $request->query->get('destination');
    if ($request->query->has('destination')) {
      $request->getSession()->remove('destination');
      $request->getSession()->set('destination', $destination);
      $request->query->remove('destination');
    }
    $response = new TrustedRedirectResponse($authorizationUrl);
    // 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.
    \Drupal::service('page_cache_kill_switch')->trigger();
    return $response
      ->setPrivate()
      ->setMaxAge(0);
  }

  public function authenticate(Request $request) {
    if (!$this->isValidState($request)) {
      throw new AccessDeniedHttpException('Invalid oauth state');
    }

    $query = $request->query;
    $code = $query->get('code');
    $session = $request->getSession();
    if ($session && $session->has('destination')) {
      $destination_uri = $session->get('destination');
      $session->remove('destination');
      $destination = Url::fromUserInput($destination_uri)
        ->toString(TRUE);
    }
    else {
      $destination = Url::fromRoute('user.page')
        ->toString(TRUE);
    }

    $response = new TrustedRedirectResponse($destination->getGeneratedUrl());
    $response->addCacheableDependency($destination);
    try {
      $grant_options = ['code' => $code];
      /** @var \BankID\OAuth2\Client\Token\AccessToken $accessToken */
      $accessToken = $this->oauthClient()
        ->getAccessToken('authorization_code', $grant_options);
    }
    catch (IdentityProviderException $e) {
      watchdog_exception('bankid_oidc', $e);
      $message = $this->getConfig('auth_error');
      if (!$message) {
        $url = Url::fromRoute('bankid_oidc.login')->toString(TRUE);
        $response->addCacheableDependency($url);
        $message = $this->t(
          'There was an error during the authentication, please wait a few seconds and <a href="@url">click here to try again</a>.',
          ['@url' => $url->getGeneratedUrl()]
        );
      }

      $this->messenger()->addError($message);
      return $response;
    }

    $auth = $this->userAuth();
    \Drupal::service('renderer')
      ->executeInRenderContext(
        new RenderContext(),
        static function() use ($auth, $accessToken) {
          return $auth->authenticate($accessToken);
        }
      );
    // 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.
    \Drupal::service('page_cache_kill_switch')->trigger();
    return $response;
  }

  /**
   * Ensures that the 'state' matches in both session and request query.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request to validate.
   *
   * @return bool
   */
  protected function isValidState(Request $request): bool {
    // We need a valid session!
    if (!$request->hasSession()) {
      return FALSE;
    }
    /** @noinspection NullPointerExceptionInspection */
    $session__state = $request->getSession()->get(self::SESSION_OAUTH_STATE_NAME);
    $request__state = $request->query->get('state');
    // Both 'states' need to have a value.
    if ($session__state === NULL || $request__state === NULL) {
      return FALSE;
    }

    return $session__state === $request__state;
  }

  /**
   * Sets the 'state' code for a given session (will start a new one if required).
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request for the session.
   * @param string $state_code
   *   The 'state' to save in the session.
   */
  protected function setSessionState(Request $request, string $state_code): void {
    $session = $request->getSession();
    if (!$session) {
      /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
      $session = \Drupal::service('session');
      $request->setSession($session);
      $session->start();
    }

    $session->set(self::SESSION_OAUTH_STATE_NAME, $state_code);
  }


}

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

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