You are here

public function OpenIDConnect::completeAuthorization in OpenID Connect / OAuth client 2.x

Same name and namespace in other branches
  1. 8 src/OpenIDConnect.php \Drupal\openid_connect\OpenIDConnect::completeAuthorization()

Complete the authorization after tokens have been retrieved.

Parameters

\Drupal\openid_connect\OpenIDConnectClientEntityInterface $client: The client.

array $tokens: The tokens as returned by OpenIDConnectClientInterface::retrieveTokens().

Return value

bool TRUE on success, FALSE on failure.

Throws

\Exception

File

src/OpenIDConnect.php, line 326

Class

OpenIDConnect
Main service of the OpenID Connect module.

Namespace

Drupal\openid_connect

Code

public function completeAuthorization(OpenIDConnectClientEntityInterface $client, array $tokens) : bool {
  if ($this->currentUser
    ->isAuthenticated()) {
    throw new \RuntimeException('User already logged in');
  }
  $context = $this
    ->buildContext($client, $tokens);
  if ($context === FALSE) {
    return FALSE;
  }
  $account = $context['account'];
  if ($account instanceof UserInterface) {

    // An existing account was found. Save user claims.
    if ($this->configFactory
      ->get('openid_connect.settings')
      ->get('always_save_userinfo')) {
      $this
        ->saveUserinfo($account, $context + [
        'is_new' => FALSE,
      ]);
    }
  }
  else {

    // Check whether the e-mail address is valid.
    $email = $context['userinfo']['email'] ?? '';
    if (!$this->emailValidator
      ->isValid($email)) {
      $this->messenger
        ->addError($this
        ->t('The e-mail address is not valid: @email', [
        '@email' => $email,
      ]));
      return FALSE;
    }

    // Check whether there is an e-mail address conflict.
    $accounts = $this->userStorage
      ->loadByProperties([
      'mail' => $email,
    ]);
    if ($accounts) {

      /** @var \Drupal\user\UserInterface|bool $account */
      $account = reset($accounts);
      $connect_existing_users = $this->configFactory
        ->get('openid_connect.settings')
        ->get('connect_existing_users');
      if ($connect_existing_users) {

        // Connect existing user account with this sub.
        $this->externalAuth
          ->linkExistingAccount($context['sub'], 'openid_connect.' . $client
          ->id(), $account);
      }
      else {
        $this->messenger
          ->addError($this
          ->t('The e-mail address is already taken: @email', [
          '@email' => $email,
        ]));
        return FALSE;
      }
    }

    // Check Drupal user register settings before saving.
    $register = $this->configFactory
      ->get('user.settings')
      ->get('register');

    // Respect possible override from OpenID-Connect settings.
    $register_override = $this->configFactory
      ->get('openid_connect.settings')
      ->get('override_registration_settings');
    if ($register === UserInterface::REGISTER_ADMINISTRATORS_ONLY && $register_override) {
      $register = UserInterface::REGISTER_VISITORS;
    }
    if (empty($account)) {
      switch ($register) {
        case UserInterface::REGISTER_ADMINISTRATORS_ONLY:

          // Deny user registration.
          $this->messenger
            ->addError($this
            ->t('Only administrators can register new accounts.'));
          return FALSE;
        case UserInterface::REGISTER_VISITORS:

          // Create a new account if register settings is set to visitors or
          // override is active.
          $account = $this
            ->createUser($context['sub'], $context['userinfo'], $client
            ->id());
          break;
        case UserInterface::REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL:

          // Create a new account and inform the user of the pending approval.
          $account = $this
            ->createUser($context['sub'], $context['userinfo'], $client
            ->id(), 0);
          $this->messenger
            ->addMessage($this
            ->t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'));
          break;
      }
    }

    // Store the newly created account.
    $this
      ->saveUserinfo($account, $context + [
      'is_new' => TRUE,
    ]);
  }

  // Whether the user should not be logged in due to pending administrator
  // approval.
  if ($account
    ->isBlocked()) {
    if (empty($context['is_new'])) {
      $this->messenger
        ->addError($this
        ->t('The username %name has not been activated or is blocked.', [
        '%name' => $account
          ->getAccountName(),
      ]));
    }
    return FALSE;
  }
  $this->externalAuth
    ->userLoginFinalize($account, $context['sub'], 'openid_connect.' . $client
    ->id());
  if (isset($tokens['id_token'])) {
    $this->session
      ->saveIdToken($tokens['id_token']);
  }
  if (isset($tokens['access_token'])) {
    $this->session
      ->saveAccessToken($tokens['access_token']);
  }
  $this->moduleHandler
    ->invokeAll('openid_connect_post_authorize', [
    $account,
    $context,
  ]);
  return TRUE;
}