You are here

LdapSsoBootSubscriber.php in LDAP Single Sign On 8

Same filename and directory in other branches
  1. 8.4 src/LdapSsoBootSubscriber.php

Namespace

Drupal\ldap_sso

File

src/LdapSsoBootSubscriber.php
View source
<?php

namespace Drupal\ldap_sso;

use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Routing\RedirectDestinationInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Url;
use Drupal\Core\Session\AccountInterface;
use Drupal\ldap_servers\Logger\LdapDetailLog;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;

/**
 * Provides the automated single sign-on provider.
 */
class LdapSsoBootSubscriber implements EventSubscriberInterface {
  private $config;
  private $logger;
  private $frontpage;
  private $currentPath;
  private $detailLog;

  /**
   * The current user account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $account;

  /**
   * The redirect destination service.
   *
   * @var \Drupal\Core\Routing\RedirectDestinationInterface
   */
  protected $redirectDestination;

  /**
   * Fetches debugging level and logging interface.
   *
   * @param \Psr\Log\LoggerInterface $logger
   *   The logging interface.
   * @param \Drupal\Core\Config\ConfigFactory $configFactory
   *   Factory for configuration for LDAP and logging level.
   * @param \Drupal\Core\Path\CurrentPathStack $currentPath
   *   Adds the current path.
   * @param \Drupal\ldap_servers\Logger\LdapDetailLog $detailLog
   *   LDAP detail log.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user account.
   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
   *   Redirect destination.
   */
  public function __construct(LoggerInterface $logger, ConfigFactory $configFactory, CurrentPathStack $currentPath, LdapDetailLog $detailLog, AccountInterface $account, RedirectDestinationInterface $redirect_destination) {
    $this->logger = $logger;
    $this->config = $configFactory
      ->get('ldap_sso.settings');
    $this->frontpage = $configFactory
      ->get('system.site')
      ->get('frontpage');
    $this->currentPath = $currentPath;
    $this->detailLog = $detailLog;
    $this->account = $account;
    $this->redirectDestination = $redirect_destination;
  }

  /**
   * Determine if we should attempt SSO.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
   *   Event to act upon.
   */
  public function checkSsoLoad(GetResponseEvent $event) {
    if (PHP_SAPI === 'cli' || $this->account
      ->isAnonymous() == FALSE) {
      $this->detailLog
        ->log('CLI or logged in user, no SSO.', [], 'ldap_sso');
      return;
    }
    elseif (!$this->config
      ->get('seamlessLogin')) {
      $this->detailLog
        ->log('Automated SSO not active.', [], 'ldap_sso');
      return;
    }
    elseif ($this
      ->checkExcludePath()) {
      $this->detailLog
        ->log('Excluded path', [], 'ldap_sso');
      return;
    }
    elseif (isset($_COOKIE['sso_login_running'])) {
      $this->detailLog
        ->log('SSO login running cookie present, aborting.', [], 'ldap_sso');
      exit(0);
    }
    elseif (isset($_COOKIE['sso_stop'])) {
      $this->detailLog
        ->log('Anonymous user with cookie to not continue SSO login', [], 'ldap_sso');
      return;
    }
    else {
      $this->detailLog
        ->log('Transferring to login controller', [], 'ldap_sso');
      $this
        ->transferSsoLoginController();
      exit(0);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = [
      'checkSsoLoad',
      20,
    ];
    return $events;
  }

  /**
   * Continue booting assuming we are doing SSO.
   */
  private function transferSsoLoginController() {

    // This is set to destination() since the request uri is usually
    // system/40x already.
    $original_path = $this->redirectDestination
      ->get();
    $pathWithDestination = Url::fromRoute('ldap_sso.login_controller')
      ->toString() . '?destination=' . $original_path;
    $cookies[] = new Cookie('sso_login_running', 'true', 0, base_path());
    $response = new RedirectResponseWithCookie($pathWithDestination, 302, $cookies);
    $response
      ->send();
  }

  /**
   * Exclude default excluded paths.
   */
  private function defaultPathsToExclude() {
    return [
      '/admin/config/search/clean-urls/check',
      '/user/login/sso',
      '/user/login',
      '/user/logout',
      '/user',
    ];
  }

  /**
   * Check to exclude paths from SSO.
   *
   * @param bool|string $path
   *   Path to check for exclusion.
   *
   * @return bool
   *   Path excluded or not.
   */
  private function checkExcludePath($path = FALSE) {
    $result = FALSE;
    if ($path) {

      // don't derive.
    }
    elseif ($_SERVER['PHP_SELF'] == '/index.php') {
      $path = $this->currentPath
        ->getPath();
    }
    else {

      // cron.php, etc.
      $path = ltrim($_SERVER['PHP_SELF'], '/');
    }
    if (in_array($path, $this
      ->defaultPathsToExclude())) {
      return TRUE;
    }
    if (is_array($this->config
      ->get('ssoExcludedHosts'))) {
      $host = $_SERVER['SERVER_NAME'];
      foreach ($this->config
        ->get('ssoExcludedHosts') as $host_to_check) {
        if ($host_to_check == $host) {
          return TRUE;
        }
      }
    }
    if ($this->config
      ->get('ssoExcludedPaths')) {
      $patterns = implode("\r\n", $this->config
        ->get('ssoExcludedPaths'));
      if ($patterns) {
        if (function_exists('drupal_get_path_alias')) {
          $path = drupal_get_path_alias($path);
        }
        $path = mb_strtolower($path);

        // Replacements for newlines, asterisks, and the <front> placeholder.
        $to_replace = [
          '/(\\r\\n?|\\n)/',
          '/\\\\\\*/',
          '/(^|\\|)\\\\<front\\\\>($|\\|)/',
        ];
        $replacements = [
          '|',
          '.*',
          '\\1' . preg_quote($this->frontpage, '/') . '\\2',
        ];
        $patterns_quoted = preg_quote($patterns, '/');
        $regex = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
        $result = (bool) preg_match($regex, $path);
      }
    }
    return $result;
  }

}

Classes

Namesort descending Description
LdapSsoBootSubscriber Provides the automated single sign-on provider.