View source
<?php
declare (strict_types=1);
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 Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
class LdapSsoBootSubscriber implements EventSubscriberInterface {
protected $config;
protected $frontpage;
protected $currentPath;
protected $detailLog;
protected $account;
protected $redirectDestination;
protected $currentRequest;
protected const DEFAULT_EXCLUDE_PATHS = [
'/admin/config/search/clean-urls/check',
'/user/login/sso',
'/user/login',
'/user/logout',
'/user',
];
public function __construct(ConfigFactory $configFactory, RequestStack $request_stack, CurrentPathStack $currentPath, LdapDetailLog $detailLog, AccountInterface $account, RedirectDestinationInterface $redirect_destination) {
$this->config = $configFactory
->get('ldap_sso.settings');
$this->frontpage = $configFactory
->get('system.site')
->get('frontpage');
$this->currentRequest = $request_stack
->getCurrentRequest();
$this->currentPath = $currentPath;
$this->detailLog = $detailLog;
$this->account = $account;
$this->redirectDestination = $redirect_destination;
}
public function checkSsoLoad(GetResponseEvent $event) : void {
if (PHP_SAPI === 'cli' || $this->account
->isAuthenticated()) {
$this->detailLog
->log('CLI or logged in user, no SSO.', [], 'ldap_sso');
return;
}
if (!$this->config
->get('seamlessLogin')) {
$this->detailLog
->log('Automated SSO not active.', [], 'ldap_sso');
return;
}
if ($this
->checkExcludePath()) {
$this->detailLog
->log('Excluded path', [], 'ldap_sso');
return;
}
if ($this->currentRequest->cookies
->get('sso_login_running', FALSE)) {
$this->detailLog
->log('SSO login running cookie present, aborting.', [], 'ldap_sso');
exit(0);
}
if ($this->currentRequest->cookies
->get('sso_stop', FALSE)) {
$this->detailLog
->log('Anonymous user with cookie to not continue SSO login', [], 'ldap_sso');
return;
}
$this->detailLog
->log('Transferring to login controller', [], 'ldap_sso');
$this
->transferSsoLoginController();
exit(0);
}
public static function getSubscribedEvents() : array {
return [
KernelEvents::REQUEST => [
'checkSsoLoad',
20,
],
];
}
protected function transferSsoLoginController() : void {
$original_path = $this->redirectDestination
->get();
$pathWithDestination = Url::fromRoute('ldap_sso.login_controller')
->toString() . '?destination=' . $original_path;
if (method_exists(Cookie::class, 'create')) {
$cookie = Cookie::create('sso_login_running', 'true', 0, base_path());
}
else {
$cookie = new Cookie('sso_login_running', 'true', 0, base_path());
}
$response = new RedirectResponseWithCookie($pathWithDestination, 302, [
$cookie,
]);
$response
->send();
}
protected function checkExcludePath() : bool {
if ($_SERVER['PHP_SELF'] === $this->currentRequest
->getBasePath() . '/index.php') {
$path = str_replace($this->currentRequest
->getBasePath(), '', $this->currentPath
->getPath());
}
else {
$path = ltrim($_SERVER['PHP_SELF'], '/');
}
if (\in_array($path, self::DEFAULT_EXCLUDE_PATHS, TRUE)) {
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;
}
}
}
foreach ($this->config
->get('ssoExcludedPaths') as $path_to_exclude) {
if (mb_strtolower($path) === mb_strtolower($path_to_exclude) || $path_to_exclude === '<front>' && mb_strtolower($this->frontpage) === mb_strtolower($path)) {
return TRUE;
}
}
return FALSE;
}
}