o365-2.0.3/modules/o365_sso/src/Controller/UserLoginController.php

modules/o365_sso/src/Controller/UserLoginController.php
<?php

namespace Drupal\o365_sso\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Url;
use Drupal\externalauth\ExternalAuth;
use Drupal\o365\AuthenticationService;
use Drupal\o365\GraphService;
use Drupal\o365\O365ConnectorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * UserLoginController. Used when returned from the callback.
 *
 * This creates/updates the user and logs in the Drupal user.
 */
class UserLoginController extends ControllerBase {

  /**
   * Drupal\o365\GraphService definition.
   *
   * @var \Drupal\o365\GraphService
   */
  protected GraphService $graphService;

  /**
   * Drupal\o365\AuthenticationService definition.
   *
   * @var \Drupal\o365\AuthenticationService
   */
  protected AuthenticationService $authenticationService;

  /**
   * The external auth service.
   *
   * @var \Drupal\externalauth\ExternalAuth
   */
  protected ExternalAuth $externalAuth;

  /**
   * Constructs a new UserLoginController object.
   *
   * @param \Drupal\o365\GraphService $o365_graph
   *   The GraphService definition.
   * @param \Drupal\o365\AuthenticationService $authenticationService
   *   The AuthenticationService definition.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The EntityTypeManager definition.
   * @param \Drupal\externalauth\ExternalAuth $externalAuth
   *   The ExternalAuth definition.
   */
  public function __construct(GraphService $o365_graph, AuthenticationService $authenticationService, EntityTypeManagerInterface $entity_type_manager, ExternalAuth $externalAuth) {
    $this->graphService = $o365_graph;
    $this->authenticationService = $authenticationService;
    $this->entityTypeManager = $entity_type_manager;
    $this->externalAuth = $externalAuth;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // @phpstan-ignore-next-line
    return new static($container->get('o365.graph'), $container->get('o365.authentication'), $container->get('entity_type.manager'), $container->get('externalauth.externalauth'));
  }

  /**
   * Login a user.
   *
   * @param \Drupal\o365\O365ConnectorInterface $o365_connector
   *   The o365 connector interface.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   The redirect to the set URL in config.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\TempStore\TempStoreException
   * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException|\Drupal\externalauth\Exception\ExternalAuthRegisterException|\GuzzleHttp\Exception\GuzzleException
   * @throws \Drupal\Core\Entity\EntityStorageException|\Microsoft\Graph\Exception\GraphException
   */
  public function login(O365ConnectorInterface $o365_connector): RedirectResponse {
    // Get config objects.
    $ssoConfig = $this->config('o365_sso.settings');

    // Get the mail property.
    $mailProperty = $ssoConfig->get('email_property') ?? 'userPrincipalName';
    if ($mailProperty === 'other') {
      $mailProperty = $ssoConfig->get('email_property_other');
    }

    // Determine the fields we want to get for a user.
    $select = $this->getFieldsForUser($mailProperty, TRUE);

    // Get user data.
    $userData = $this->graphService->getGraphData('/me?$select=' . $select);

    // Get set config.
    $useRedirectDestination = $ssoConfig->get('redirect_login_destination');
    $onlyExistingUsers = $ssoConfig->get('only_existing_users');
    $nameAttribute = $ssoConfig->get('username_attribute') ?? 'displayName';
    $updateUsername = $ssoConfig->get('update_username') ?? FALSE;

    // Get redirect url after login.
    $redirectUrl = $o365_connector->getRedirectLogin();

    // Check if we want to use the redirect destination.
    if ($useRedirectDestination) {
      $savedDestination = $this->authenticationService->getDataFromTempStore('destination');

      $savedDestination = $savedDestination ?? '';
      $firstChar = $savedDestination[0] ?? '';
      $mandatoryChars = ['/', '?', '#'];
      if (!empty($savedDestination) && in_array($firstChar, $mandatoryChars, TRUE)) {
        $url = Url::fromUserInput($savedDestination, ['absolute' => TRUE]);
        $redirectUrl = $url->toString();
      }
    }

    // Get user unique identifier.
    $o365_id = $userData['id'];
    $account = $this->externalAuth->load($o365_id, 'o365_sso');
    $email = strtolower($userData[$mailProperty]);

    // Check for email match.
    if (!$account) {
      $account = $this->entityTypeManager->getStorage('user')
        ->loadByProperties(['mail' => $email]);
      $account = !empty($account) ? reset($account) : FALSE;
    }

    if ($account) {
      $this->externalAuth->linkExistingAccount($o365_id, 'o365_sso', $account);
    }

    // If we haven't found an account to link, create one from the data.
    if (!$account && empty($onlyExistingUsers)) {
      $accountData = [
        'name' => $this->sanitizeUsername($userData[$nameAttribute]),
        'mail' => $email,
      ];
      $account = $this->externalAuth->register($o365_id, 'o365_sso', $accountData);
    }
    elseif (!$account && !empty($onlyExistingUsers)) {
      $this->messenger()->addError($this->t('You do not have an account on this site. Please contact a administrator.'));

      if (empty($ssoConfig->get('auto_redirect'))) {
        return $this->redirect('user.login');
      }
      else {
        return $this->redirect('<front>');
      }
    }
    elseif ($account->isBlocked()) {
      $this->messenger()->addError($this->t('The requested account is blocked'));
      return $this->redirect('user.login');
    }

    // Log the user in.
    $this->externalAuth->userLoginFinalize($account, $o365_id, 'o365_sso');

    // Update the username if requested.
    $newUsername = $this->sanitizeUsername($userData[$nameAttribute]);
    if (!empty($updateUsername) && $account->getAccountName() != $newUsername) {
      $account->setUsername($newUsername);
      $account->save();
    }

    // Save the data from the url.
    $this->authenticationService->saveAuthDataFromUrl();

    // Return the redirect.
    return new RedirectResponse($redirectUrl);
  }

  /**
   * Sanitize username.
   *
   * @param string $username
   *   The username coming from o365.
   *
   * @return string
   *   The sanitized username.
   */
  public function sanitizeUsername($username): string {
    // Strip illegal characters.
    return preg_replace('/[^\\x{80}-\\x{F7} a-zA-Z0-9@_.\'-]/', '', $username);
  }

  /**
   * Get a list of the fields we need to retrieve during login for a user.
   *
   * @param string $mailProperty
   *   The mail property name.
   * @param bool $implode
   *   If we want to implode the array.
   *
   * @return string[]|string
   *   The list of fields as an array or string.
   */
  private function getFieldsForUser(string $mailProperty, bool $implode = TRUE): array|string {
    $fields = [
      'businessPhones',
      'displayName',
      'givenName',
      'jobTitle',
      'mail',
      'mobilePhone',
      'officeLocation',
      'preferredLanguage',
      'userPrincipalName',
      'id',
    ];

    if (!in_array($mailProperty, $fields)) {
      $fields[] = $mailProperty;
    }

    if ($implode) {
      return implode(',', $fields);
    }

    return $fields;
  }

}

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

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