social_auth_vipps-8.x-2.1/src/Controller/VippsAuthController.php

src/Controller/VippsAuthController.php
<?php

namespace Drupal\social_auth_vipps\Controller;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\social_api\Plugin\NetworkManager;
use Drupal\social_auth\Controller\OAuth2ControllerBase;
use Drupal\social_auth\SocialAuthDataHandler;
use Drupal\social_auth\User\UserAuthenticator;
use Drupal\social_auth_vipps\VippsAuthManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Returns responses for Social Auth Vipps routes.
 */
class VippsAuthController extends OAuth2ControllerBase {

  const OAUTH2_STATES_DRUPAL_STATE_KEY = 'social_auth_vipps.oauth2_states';
  const OAUTH2_STATE_IS_VALID_IN_DRUPAL_STATE_THRESHOLD = 60 * 2;

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

  /**
   * VippsAuthController constructor.
   *
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   * @param \Drupal\social_api\Plugin\NetworkManager $network_manager
   *   Used to get an instance of social_auth_vipps network plugin.
   * @param \Drupal\social_auth\User\UserAuthenticator $user_authenticator
   *   Manages user login/registration.
   * @param \Drupal\social_auth_vipps\VippsAuthManager $vipps_manager
   *   Used to manage authentication methods.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request
   *   Used to access GET parameters.
   * @param \Drupal\social_auth\SocialAuthDataHandler $data_handler
   *   The Social Auth data handler.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   Used to handle metadata for redirection to authentication URL.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time service.
   */
  public function __construct(
    MessengerInterface $messenger,
    NetworkManager $network_manager,
    UserAuthenticator $user_authenticator,
    VippsAuthManager $vipps_manager,
    RequestStack $request,
    SocialAuthDataHandler $data_handler,
    RendererInterface $renderer,
    TimeInterface $time
  ) {
    parent::__construct(
      'Social Auth Vipps',
      'social_auth_vipps',
      $messenger,
      $network_manager,
      $user_authenticator,
      $vipps_manager,
      $request,
      $data_handler,
      $renderer
    );
    $this->time = $time;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('messenger'),
      $container->get('plugin.network.manager'),
      $container->get('social_auth.user_authenticator'),
      $container->get('social_auth_vipps.manager'),
      $container->get('request_stack'),
      $container->get('social_auth.data_handler'),
      $container->get('renderer'),
      $container->get('datetime.time')
    );
  }

  /**
   * Response for path 'user/login/vipps/callback'.
   *
   * Vipps returns the user here after user has authenticated.
   */
  public function callback() {
    /** @var \Drupal\social_auth_vipps\Provider\VippsResourceOwner|null $profile */
    $profile = $this->processCallback();

    // If authentication was successful.
    if ($profile !== NULL) {
      $profile->verificationGuard();

      // Gets (or not) extra initial data.
      $data = $this->userAuthenticator->checkProviderIsAssociated($profile->getId()) ? NULL : $this->providerManager->getExtraDetails();

      // If user information could be retrieved.
      return $this->userAuthenticator->authenticateUser(
        $profile->getNickName(),
        $profile->getEmail(),
        $profile->getId(),
        $this->providerManager->getAccessToken(),
        $profile->getAvatarUrl(),
        $data
      );
    }

    return $this->redirect('user.login');
  }

  /**
   * {@inheritdoc}
   */
  public function processCallback() {
    $retrieved_state = $this->request->getCurrentRequest()->query->get('state');
    $stored_oauth2_states = $this->state()->get(self::OAUTH2_STATES_DRUPAL_STATE_KEY);
    $result = parent::processCallback();
    if ($result !== NULL) {
      // Process passed successfully.
      // Flush state value from the Drupal states, so it cannot be re-used.
      if (isset($stored_oauth2_states[$retrieved_state])) {
        unset($stored_oauth2_states[$retrieved_state]);
        $this->state()->set(self::OAUTH2_STATES_DRUPAL_STATE_KEY, $stored_oauth2_states);
      }
      return $result;
    }

    // Check for "Login failed. Invalid OAuth2 state." error message.
    // This might be inaccurate now, but starting from "social_auth" v.4.1.2,
    // there was process callback errors handling introduced.
    // Let's keep this like this for now.
    $status_messages = $this->messenger()->all();
    $invalid_state_error = FALSE;
    foreach ($status_messages as $message_type => $messages) {
      if ($message_type !== MessengerInterface::TYPE_ERROR) {
        continue;
      }
      foreach ($messages as $message) {
        $message = (string) $message;
        if (strpos($message, 'Invalid OAuth2 state') !== FALSE) {
          $invalid_state_error = TRUE;
          break;
        }
      }
      if ($invalid_state_error) {
        break;
      }
    }

    // Sorry, not our stuff.
    if (!$invalid_state_error) {
      return NULL;
    }

    // Run our OAuth2 state check.
    if (isset($stored_oauth2_states[$retrieved_state])) {
      // Great, we have a match.
      // Now, let's check whether value is still valid.
      $created = $stored_oauth2_states[$retrieved_state];
      $allowed_until = $created + self::OAUTH2_STATE_IS_VALID_IN_DRUPAL_STATE_THRESHOLD;
      if ($this->time->getRequestTime() < $allowed_until) {
        // This will set needed session key, and processCallback() should pass
        // successfully this time.
        $this->dataHandler->set('oauth2state', $retrieved_state);
      }

      // Flush value from the Drupal states.
      unset($stored_oauth2_states[$retrieved_state]);
      $this->state()->set(self::OAUTH2_STATES_DRUPAL_STATE_KEY, $stored_oauth2_states);

      // Clear status messages to prevent showing already existing error.
      $this->messenger()->deleteByType(MessengerInterface::TYPE_ERROR);

      // Now, run same process again.
      return parent::processCallback();
    }

    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function redirectToProvider() {
    $method_call = parent::redirectToProvider();

    // Get the value that was set in user's session during parent method call.
    $session_oauth2_state = $this->dataHandler->get('oauth2state');
    // Store such auth state in Drupal states for possible additional check.
    if ($session_oauth2_state) {
      $stored_oauth2_states = $this->state()->get(self::OAUTH2_STATES_DRUPAL_STATE_KEY);
      $stored_oauth2_states[$session_oauth2_state] = $this->time->getRequestTime();
      $this->state()->set(self::OAUTH2_STATES_DRUPAL_STATE_KEY, $stored_oauth2_states);
    }

    return $method_call;
  }

}

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

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