Skip to content

Architecture

Path-based SSO

Production setups usually protect only /user/login/sso on the web server.

sequenceDiagram
  participant Browser
  participant WebServer
  participant Login as LoginController
  participant Lookup as ServerVariableLookup
  participant Validator as LoginValidatorSso

  Browser->>WebServer: GET /user/login/sso
  WebServer->>Login: Request with REMOTE_USER
  Login->>Lookup: getAuthenticationNameFromServer
  Lookup-->>Login: authname
  Note over Login: Optional realm split / domain strip
  Login->>Validator: setAuthname + processLogin
  Validator-->>Login: Drupal user or failure
  alt Success
    Login-->>Browser: user_login_finalize + redirect
  else Failure or missing REMOTE_USER
    Login-->>Browser: sso_stop cookie + redirect to login
  end

Access is anonymous-only (LoginController::access). Authenticated users get 403. The route is ldap_sso.login_controller, no_cache: TRUE.

Processing steps in LoginController::login:

  1. Read ssoVariable via ldap_sso.server_variable.
  2. If ssoSplitUserRealm, split user@realm.
  3. If ssoRemoteUserStripDomainName, strip @ or \ domain forms.
  4. Call ldap_authentication.login_validator_sso (LoginValidatorSso::processLogin()).
  5. On success: user_login_finalize(), optional status message, redirect to ?destination or <front>.
  6. On failure: set sso_stop, show an error, redirect toward login.
  7. Always clear sso_login_running.

Seamless SSO

When seamlessLogin is TRUE, LdapSsoBootSubscriber runs early on KernelEvents::REQUEST (priority 30).

sequenceDiagram
  participant Browser
  participant Boot as LdapSsoBootSubscriber
  participant Login as LoginController

  Browser->>Boot: Anonymous GET /some/path
  alt CLI, logged in, seamless off, excluded, or sso_stop
    Boot-->>Browser: Continue normal request
  else Should SSO
    Boot-->>Browser: 302 /user/login/sso?destination=... + sso_login_running
    Browser->>Login: GET /user/login/sso
    Note over Login: Same path-based flow
    Login-->>Browser: Session + redirect to destination
  end

Skips when:

  • PHP_SAPI === 'cli'
  • User already authenticated
  • seamlessLogin is false
  • Path or host is excluded (defaults + config)
  • Cookie sso_stop is present
  • Cookie sso_login_running is present (abort to avoid loops)

Hardcoded excluded paths:

  • /admin/config/search/clean-urls/check
  • /user/login/sso
  • /user/login
  • /user/logout
  • /user

Logout

ldap_sso_user_logout() in ldap_sso.module:

  1. If seamless login is on, set sso_stop (lifetime from cookieExpire).
  2. If redirectOnLogout, send a RedirectResponse to logoutRedirectPath.

Key classes

Class Path
Drupal\ldap_sso\Controller\LoginController src/Controller/LoginController.php
Drupal\ldap_sso\LdapSsoBootSubscriber src/LdapSsoBootSubscriber.php
Drupal\ldap_sso\ServerVariableLookup src/ServerVariableLookup.php
Drupal\ldap_sso\RedirectResponseWithCookie src/RedirectResponseWithCookie.php
Drupal\ldap_sso\Form\LdapSsoAdminForm src/Form/LdapSsoAdminForm.php
Drupal\ldap_authentication\Controller\LoginValidatorSso (ldap_authentication)

Services

Defined in ldap_sso.services.yml:

Service ID Class
logger.channel.ldap_sso Logger channel
ldap_sso.boot LdapSsoBootSubscriber (event subscriber)
ldap_sso.server_variable ServerVariableLookup

External dependency used by the controller: ldap_authentication.login_validator_sso.