oidc-1.0.0-alpha2/src/Controller/OpenidConnectController.php

src/Controller/OpenidConnectController.php
<?php

namespace Drupal\oidc\Controller;

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Session\SessionManagerInterface;
use Drupal\Core\Url;
use Drupal\externalauth\ExternalAuthInterface;
use Drupal\oidc\ExistingAccountValidator;
use Drupal\oidc\Event\LinkExistingAccountEvent;
use Drupal\oidc\OpenidConnectLoginException;
use Drupal\oidc\OpenidConnectSessionInterface;
use Drupal\oidc\Plugin\OpenidConnectRealm\GenericOpenidConnectRealm;
use Drupal\oidc\Routing\ImmutableTrustedRedirectResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
 * Controller for the OpenID Connect requests.
 */
class OpenidConnectController extends ControllerBase {

  /**
   * The session manager.
   *
   * @var \Drupal\Core\Session\SessionManagerInterface
   */
  protected $sessionManager;

  /**
   * The OpenID Connect session service.
   *
   * @var \Drupal\oidc\OpenidConnectSessionInterface
   */
  protected $session;

  /**
   * The external authentication service.
   *
   * @var \Drupal\externalauth\ExternalAuthInterface
   */
  protected $externalauth;

  /**
   * The existing account validator.
   *
   * @var \Drupal\oidc\ExistingAccountValidator
   */
  protected $existingAccountValidator;

  /**
   * The UUID service.
   *
   * @var \Drupal\Component\Uuid\UuidInterface
   */
  protected $uuid;

  /**
   * The user storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $userStorage;

  /**
   * The event dispatcher.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected $eventDispatcher;

  /**
   * Class constructor.
   *
   * @param \Drupal\Core\Session\SessionManagerInterface $session_manager
   *   The session manager.
   * @param \Drupal\oidc\OpenidConnectSessionInterface $session
   *   The OpenID Connect session service.
   * @param \Drupal\externalauth\ExternalAuthInterface $externalauth
   *   The external authentication service.
   * @param \Drupal\oidc\ExistingAccountValidator $existing_account_validator
   *   The existing account validator service.
   * @param \Drupal\Component\Uuid\UuidInterface $uuid
   *   The UUID service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
   *   The event dispatcher.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function __construct(SessionManagerInterface $session_manager, OpenidConnectSessionInterface $session, ExternalAuthInterface $externalauth, ExistingAccountValidator $existing_account_validator, UuidInterface $uuid, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $event_dispatcher) {
    $this->sessionManager = $session_manager;
    $this->session = $session;
    $this->externalauth = $externalauth;
    $this->existingAccountValidator = $existing_account_validator;
    $this->uuid = $uuid;
    $this->userStorage = $entity_type_manager->getStorage('user');
    $this->eventDispatcher = $event_dispatcher;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('session_manager'),
      $container->get('oidc.openid_connect_session'),
      $container->get('externalauth.externalauth'),
      $container->get('oidc.existing_account_validator'),
      $container->get('uuid'),
      $container->get('entity_type.manager'),
      $container->get('event_dispatcher')
    );
  }

  /**
   * Start the OpenID Connect authentication.
   *
   * @param string $realm
   *   The realm plugin ID.
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request.
   *
   * @return \Drupal\oidc\Routing\ImmutableTrustedRedirectResponse
   *   Redirect to the login URL.
   */
  public function login($realm, Request $request) {
    // Initialize the realm.
    try {
      $this->session->initRealm($realm);
      $plugin = $this->session->getRealmPlugin();
    }
    catch (PluginNotFoundException $ex) {
      $this->session->destroy();
      throw new NotFoundHttpException();
    }

    // Ensure it's enabled.
    if (!$plugin->isEnabled()) {
      $this->session->destroy();
      throw new NotFoundHttpException();
    }

    // Initialize the state.
    $destination = $request->query->get('destination');
    $state = $this->session->initState($destination);

    // Get and redirect to the login URL.
    $redirect_url = Url::fromRoute('oidc.openid_connect.login_redirect');
    $url = $plugin->getLoginUrl($state, $redirect_url)
      ->setAbsolute();

    return new ImmutableTrustedRedirectResponse($url);
  }

  /**
   * Redirect callback triggered after an OpenID Connect login.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   Redirect to the front page.
   */
  public function loginRedirect(Request $request) {
    $query = $request->query;
    $plugin_id = $this->session->getRealmPluginId();

    if ($query->has('error') && $query->get('error_description')) {
      // An error occurred.
      $this->getLogger('oidc')->critical('@error error occurred on @realm realm: %description', [
        '@error' => $query->get('error'),
        '@realm' => $plugin_id,
        '%description' => $query->get('error_description'),
      ]);
    }
    elseif (!$query->has('code')) {
      // No code specified.
      $this->getLogger('oidc')->error('Code missing in redirect from @realm realm.', [
        '@realm' => $plugin_id,
      ]);
    }
    else {
      // Get the realm plugin.
      $plugin = $this->session->getRealmPlugin();

      try {
        // Get the tokens.
        $tokens = $plugin->getJsonWebTokensForLogin($this->session->getState(), $query->get('code'));
        $this->session->setJsonWebTokens($tokens);

        // Check if there's a mapped user.
        $authname = $tokens->getId();
        $provider = 'oidc:' . $plugin_id;
        $account = $this->externalauth->load($authname, $provider);

        // No user found, try to link to an existing user.
        if (!$account) {
          $event = new LinkExistingAccountEvent($provider, $tokens);
          $this->eventDispatcher->dispatch($event);

          $account = $event->getAccount();
          if ($account && $this->existingAccountValidator->isValid($account)) {
            $this->externalauth->linkExistingAccount($authname, $provider, $account);
            $account->setPassword(NULL)->save();
          }
        }

        // Stil no user, create a new one.
        if (!$account) {
          do {
            $name = $this->uuid->generate();
            $count = $this->userStorage->getQuery()
              ->count()
              ->condition('name', $name)
              ->accessCheck(FALSE)
              ->execute();
          } while ($count);

          $account = $this->externalauth->register($authname, $provider, [
            'name' => $name,
          ]);
        }

        // Login.
        $this->externalauth->userLoginFinalize($account, $authname, $provider);

        // Clear the state and restore the destination.
        if (($destination = $this->session->clearState()) !== NULL) {
          $request->query->set('destination', $destination);
        }

        // Destroy the session if the realm is only to be used for authentication.
        if ($plugin instanceof GenericOpenidConnectRealm && $plugin->isOnlyForAuthentication()) {
          $this->session->destroy();
        }
      }
      catch (OpenidConnectLoginException $ex) {
        if ($this->currentUser()->isAnonymous()) {
          // Redirect to the destination.
          $redirect = new ImmutableTrustedRedirectResponse($ex->getDestination());
          $this->session->destroy();
        }
        else {
          // Logout before redirecting to the destination.
          $request->query->set('destination', $ex->getDestination()->getInternalPath());
          $redirect = $this->logout($request);
        }

        // Set the exception message as error.
        if (($message = $ex->getMessage()) !== '') {
          $this->messenger()->addError($message);
        }

        return $redirect;
      }
      catch (\Exception $ex) {
        $this->getLogger('oidc')->error('Error on authentication via @realm realm: %error', [
          '@realm' => $plugin_id,
          '%error' => $ex->getMessage(),
        ]);
      }
    }

    // Destroy the session and set an error message if authentication failed.
    if ($this->currentUser()->isAnonymous()) {
      $this->session->destroy();
      $this->messenger()->addError($this->t('Authentication failed, please try again later.'));
    }

    return $this->redirect('<front>');
  }

  /**
   * Start the OpenID Connect logout.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request.
   *
   * @return \Drupal\oidc\Routing\ImmutableTrustedRedirectResponse
   *   Redirect to the logout URL.
   */
  public function logout(Request $request) {
    // Get the realm plugin.
    $plugin = $this->session->getRealmPlugin();
    $plugin_id = $plugin->getPluginId();

    // Get the tokens.
    $tokens = $this->session->getJsonWebTokens();

    // Log out of Drupal. This code is copied from user_logout() because that function
    // also destroys the PHP session, which breaks the OpenID Connect session.
    $user = $this->currentUser();
    $this->getLogger('user')->notice('Session closed for %name.', ['%name' => $user->getAccountName()]);
    $this->moduleHandler()->invokeAll('user_logout', [$user]);
    $user->setAccount(new AnonymousUserSession());

    // Clear the session and restore the realm.
    $this->sessionManager->clear();
    $this->session->initRealm($plugin_id);

    // Initialize the state.
    $destination = $request->query->get('destination');
    $state = $this->session->initState($destination);

    // Get and redirect to the logout URL.
    $redirect_url = Url::fromRoute('oidc.openid_connect.logout_redirect');
    $url = $plugin->getLogoutUrl($tokens->getIdToken(), $state, $redirect_url)
      ->setAbsolute();

    return new ImmutableTrustedRedirectResponse($url);
  }

  /**
   * Redirect callback triggered after an OpenID Connect logout.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   Redirect to the front page.
   */
  public function logoutRedirect(Request $request) {
    // Set a message if there are no error messages.
    if (!$this->messenger()->messagesByType(MessengerInterface::TYPE_ERROR)) {
      $this->messenger()->addStatus($this->t('You have been logged out successfully.'));
    }

    // Clear the state and restore the destination.
    if (($destination = $this->session->clearState()) !== NULL) {
      $request->query->set('destination', $destination);
    }

    $this->session->destroy();

    return $this->redirect('<front>');
  }

}

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

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