|
|
|
|
@ -15,8 +15,14 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
|
|
|
/** |
|
|
|
|
* Subscribes to kernel request events to redirect users based on permissions. |
|
|
|
|
* |
|
|
|
|
* If a user has the 'access protected domain' permission and is not already |
|
|
|
|
* accessing the site via the protected domain, they will be redirected there. |
|
|
|
|
* - Authenticated users with 'access protected domain' permission are |
|
|
|
|
* redirected to the protected domain when accessing admin paths. |
|
|
|
|
* - Anonymous users logging in from the public domain log in normally, but if |
|
|
|
|
* they gain access permission, they're redirected to the protected domain to |
|
|
|
|
* log in again. |
|
|
|
|
* - A message is shown on the protected domain when redirected, and query |
|
|
|
|
* strings are cleaned. |
|
|
|
|
* - A logout finalizer allows users to fully log out across both domains. |
|
|
|
|
*/ |
|
|
|
|
class RedirectSubscriber implements EventSubscriberInterface { |
|
|
|
|
|
|
|
|
|
@ -37,19 +43,19 @@ class RedirectSubscriber implements EventSubscriberInterface {
|
|
|
|
|
/** |
|
|
|
|
* The Messenger service. |
|
|
|
|
* |
|
|
|
|
* @var \Drupal\Core\Messenger\ |
|
|
|
|
* @var \Drupal\Core\Messenger\MessengerInterface |
|
|
|
|
*/ |
|
|
|
|
protected $messenger; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Constructs a new RedirectSubscriber. |
|
|
|
|
* Constructs a new RedirectSubscriber object. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Session\AccountProxyInterface $current_user |
|
|
|
|
* The current user. |
|
|
|
|
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory |
|
|
|
|
* The config factory. |
|
|
|
|
* @param Drupal\Core\Messenger\MessengerInterface $messenger |
|
|
|
|
* The messenger. |
|
|
|
|
* The configuration factory. |
|
|
|
|
* @param \Drupal\Core\Messenger\MessengerInterface $messenger |
|
|
|
|
* The messenger service. |
|
|
|
|
*/ |
|
|
|
|
public function __construct(AccountProxyInterface $current_user, ConfigFactoryInterface $config_factory, MessengerInterface $messenger) { |
|
|
|
|
$this->currentUser = $current_user; |
|
|
|
|
@ -58,41 +64,44 @@ class RedirectSubscriber implements EventSubscriberInterface {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* {@inheritdoc} |
|
|
|
|
* Handles kernel request events. |
|
|
|
|
* |
|
|
|
|
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event |
|
|
|
|
* The event to process. |
|
|
|
|
*/ |
|
|
|
|
public function onRequest(RequestEvent $event) { |
|
|
|
|
$request = $event->getRequest(); |
|
|
|
|
$host = $request->getHost(); |
|
|
|
|
$uri = $request->getRequestUri(); |
|
|
|
|
$config = $this->configFactory->get('url_permission_redirect.settings'); |
|
|
|
|
$protectedDomain = $config->get('protected_domain') ?? FALSE; |
|
|
|
|
$protectedDomain = $this->sanitizeDomain($config->get('protected_domain') ?? ''); |
|
|
|
|
|
|
|
|
|
// Redirect logged-in users with access permission to protected domain. |
|
|
|
|
// Redirect logged-in users with access permission to protected domain for admin routes only. |
|
|
|
|
if ($protectedDomain && $this->currentUser->isAuthenticated() && |
|
|
|
|
$this->currentUser->hasPermission('access protected domain')) { |
|
|
|
|
if ($host !== $protectedDomain) { |
|
|
|
|
if ($host !== $protectedDomain && str_starts_with($uri, '/admin')) { |
|
|
|
|
$redirect_url = 'https://' . $protectedDomain . $uri; |
|
|
|
|
$event->setResponse(new TrustedRedirectResponse($redirect_url, 302)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Redirect anonymous users attempting to log in from public domain. |
|
|
|
|
if ($host !== $protectedDomain && $uri === '/user/login' && $this->currentUser->isAnonymous()) { |
|
|
|
|
$destination = $request->query->get('destination'); |
|
|
|
|
$redirect_url = 'https://' . $protectedDomain . '/user?redirect_message=1'; |
|
|
|
|
|
|
|
|
|
if ($destination) { |
|
|
|
|
$redirect_url .= '&destination=' . urlencode($destination); |
|
|
|
|
} |
|
|
|
|
// Let anonymous users log in normally. |
|
|
|
|
if ($uri === '/user/login' && $this->currentUser->isAnonymous()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Redirect users who now have permission and are still on public site. |
|
|
|
|
if ($host !== $protectedDomain && $uri === '/user' && $this->currentUser->isAuthenticated() && |
|
|
|
|
$this->currentUser->hasPermission('access protected domain')) { |
|
|
|
|
$redirect_url = 'https://' . $protectedDomain . '/user?redirect_message=1'; |
|
|
|
|
$event->setResponse(new TrustedRedirectResponse($redirect_url, 302)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Show redirect message on target domain if query parameter is present. |
|
|
|
|
if ($host === $protectedDomain && $request->query->get('redirect_message') === '1') { |
|
|
|
|
$this->messenger->addStatus('You were redirected here to log in securely.'); |
|
|
|
|
$this->messenger->addStatus('You were redirected here to log in securely. If already logged in, no action is needed.'); |
|
|
|
|
|
|
|
|
|
// Clean the query string by removing redirect_message and reloading. |
|
|
|
|
$query = $request->query->all(); |
|
|
|
|
@ -102,6 +111,28 @@ class RedirectSubscriber implements EventSubscriberInterface {
|
|
|
|
|
$clean_url = Url::fromUri('internal:' . $current_path, ['query' => $query])->toString(); |
|
|
|
|
$event->setResponse(new RedirectResponse($clean_url, 302)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Final logout handling: if coming from the protected domain, force logout here too. |
|
|
|
|
if ($uri === '/user/logout' && $request->query->get('final') === '1') { |
|
|
|
|
if ($this->currentUser->isAuthenticated()) { |
|
|
|
|
user_logout(); |
|
|
|
|
} |
|
|
|
|
$url = Url::fromRoute('user.login')->toString(); |
|
|
|
|
$event->setResponse(new RedirectResponse($url)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Strips protocol and trailing slashes from a domain. |
|
|
|
|
* |
|
|
|
|
* @param string $domain |
|
|
|
|
* The domain string to sanitize. |
|
|
|
|
* |
|
|
|
|
* @return string |
|
|
|
|
* The sanitized domain. |
|
|
|
|
*/ |
|
|
|
|
protected function sanitizeDomain(string $domain): string { |
|
|
|
|
return preg_replace('#^https?://#', '', rtrim($domain, '/')); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|