Skip to content

refactor: delegate logout handling from login.php to LoginService#109

Open
jcdelepine wants to merge 1 commit into
horde:FRAMEWORK_6_0from
jcdelepine:refactor/login-logout-delegate-to-service
Open

refactor: delegate logout handling from login.php to LoginService#109
jcdelepine wants to merge 1 commit into
horde:FRAMEWORK_6_0from
jcdelepine:refactor/login-logout-delegate-to-service

Conversation

@jcdelepine

Copy link
Copy Markdown
Contributor

This PR refactors logout handling in login.php to delegate to LoginService::performLogout(), ensuring consistent behavior across all logout paths (legacy and modern routing).

It removes duplicated logout logic and ensures pre-logout handlers and session lifecycle management are executed uniformly.

@ralflang My OIDC login implementation is ready. This is PR 3 of 3 required to
continue the implementation.

login.php handled logout logic directly (CSRF check, clearAuth,
session setup, redirect). LoginService.performLogout() already
encapsulates all of this. Delegate to it so logout behaviour is
consistent whether the request comes from login.php or from the
modern routing stack (ResponsiveLogoutController).

Pre-logout handlers registered in LoginService now run on all
logout paths, not just those going through the responsive stack.

@ralflang ralflang left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcdelepine Thank you for submitting this. Please don't be worried by the number of comments here. The crucial change is twofold: Where does the preLogoutHandler come from in your setup (probably a hook?)

The other parts are minutiae which don't affect the happy path and which I can work on myself.

Comment thread src/Service/LoginService.php
$this->notification->detach('status');
$this->notification->attach('status');

// Check redirect_on_logout config

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this redirect will make your own redirect code unaccessible?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. This is fixed in the OIDC PR where redirect_on_logout
is evaluated after sessionLifecycle->setup() and after the
pre-logout handlers have run, so handler redirects take priority.
Feel free to fix this directly.

Comment thread login.php
forwardedFor: $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null,
));
$is_auth = null;
} else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to reset the notification handler in this path, too?

try {
$data = $handler->onBeforeLogout($currentUser, $request->reason);
if (!empty($data['redirect']) && $postLogoutRedirect === null) {
$postLogoutRedirect = $data['redirect'];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we have multiple preLogoutHandlers with different redirect attributes? Only the first one will be honored (which is probably what we want OR notice we have contradicting setups and just crash with a useful error message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the first non-null redirect is honoured — subsequent handlers
can still perform their cleanup (token revocation etc.) but their
redirect is ignored. This is intentional: in practice a deployment
will have at most one handler that produces a redirect (the OIDC SLO
handler). If contradicting redirects were a real concern, a more
explicit conflict-detection mechanism would be warranted, but I felt
that was premature for now.

@jcdelepine

Copy link
Copy Markdown
Contributor Author

@jcdelepine Thank you for submitting this. Please don't be worried by the number of comments here. The crucial change is twofold: Where does the preLogoutHandler come from in your setup (probably a hook?)

A preLogoutHandler is an object implementing PreLogoutHandlerInterface
(in horde/Core), which defines a single method:

public function onBeforeLogout(string $userId, int $reason): array;

The concrete implementation in our setup is OidcPreLogoutHandler
(also in horde/Core), which handles token revocation and SLO redirect
preparation before clearAuth(). It is injected at construction time
by LoginServiceFactory — see the OIDC integration PR coming next.
The interface and factory wiring are part of that PR, not this one.
This PR only introduces the mechanism; the first concrete handler
arrives with the OIDC PR.

@ralflang

Copy link
Copy Markdown
Member

@jcdelepine This is roughly what I thought it could be. However, excuse my ignorance, I think I am missing the PR against horde/core. I merged the ones against horde/jwt and horde/Oauth#4 (and I am reviewing your additional horde/Oauth#5 in the mean time).

@jcdelepine

Copy link
Copy Markdown
Contributor Author

@ralflang The missing context is now available in the horde/Core PR which I have
just submitted. It introduces:

  • PreLogoutHandlerInterface: the contract implemented by pre-logout handlers
  • OidcPreLogoutHandler: the concrete OIDC implementation that handles token
    revocation and SLO redirect, injected by LoginServiceFactory when
    auth.driver = oidc
  • Horde_Core_Auth_Oidc: the auth driver itself

The full OIDC integration also covers horde/imp and horde/ingo (XOAUTH2
hooks for IMAP, SMTP and Sieve).

PRs in dependency order:

  1. horde/Jwt: Jwk::toPublicKey() — merged
  2. horde/Oauth: OAuth2Client::revokeToken() — merged
  3. horde/base refactor/login-logout-delegate-to-service — this PR
  4. horde/Core feat/OidcIntegration — just submitted
  5. horde/base feat/OidcIntegration — just submitted
  6. horde/imp feat/OidcIntegration — just submitted
  7. horde/ingo feat/OidcIntegration — just submitted

@ralflang

Copy link
Copy Markdown
Member

I see. The first two points are not controversial and expected.
As for the third point I will look closely in that specific PR. So far I have maintained a boundary between "local users backend" (mysql, ldap, ...) and OIDC which is tied to Identities, not Users. More on that when reviewing the Core PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants