feat: OIDC/OAuth2 authentication integration for Horde base - #110
jcdelepine wants to merge 2 commits into
Conversation
jcdelepine
commented
Jun 15, 2026
|
As anticipated in #109 - This is somewhat more complicated to handle than the previous PRs on the Oauth library itself. Different architecturesYour model of integrating OIDC works a bit different than what we started to implement. I understand yours already works correctly for your install and delivers OAUTH (for UI login) and XOAUTH (for backend login) and a seamless integration. That makes it a bit hard for me to defend wanting to do things a bit different. Fundamentally, the upstream model makes OAuth 2.0 / OIDC an alternative to an Auth driver. Your model makes it an auth driver. In our model, OIDC capabilities (beyond "login to horde") can be added to apps and services individually and independent of login method. I.e. we can drive service login to Twitter, Github, Mastodon, Google Calendar ... independent of how to login to Horde. At the moment many of the necessary changes in horde are not yet implemented, i.e. activesync and caldav/carddav backends with OAuth 2.0 support. Gaps when OIDC is the auth backend
Cherry PickingI would like to take a lot of your PRs' supporting code because it does mostly what we need to do across both models. UsernameAs an opt-in mechanism creating/matching an auth backend username to an attribute provided by the IdP would also work in the upstream concept. Compromise on OAuth Login driverI see there's room for the OAuth Login driver as the primary/only login mechanism for some installations. Horde's login.php will forward to the IdP screen transparently. This will however hide mode selection and language selection as well as the secondfactor UI. TimelineI already stretched the Horde 6.0 Stable Release timeline for some last minute fixes to the cache and activesync codebase. I would rather not stretch much further. @TDannhauer How do you see this? This could easily be an addition for an early horde/base 6.1 as it's a major feature. |
|
To be honest, I prefer a soon release of Horde. Reading the techn question being a Auth driver or beeing an Alternative to an with driver: what is the technical difference? Is adding another "Module Type" worth it? |
|
@ralflang @TDannhauer Thank you for the detailed feedback. I understand the architectural Looking at what actually blocked me: when logging in via OAuth with a The root cause is that IMP_Auth::_canAutoLogin() only attempts XOAUTH2 This would allow the hook infrastructure (OidcHookHelper, Does this direction make sense to you? |
|
Yes, this direction makes sense to me. Allow me some time to look into how we can best integrate what your hooks do with the federated approach. @TDannhauer There is quite some difference. With OIDC as the "auth driver" it will be responsible for all aspects of user handling and everything OIDC naturally cannot do will be unaccessible. With the model we designed for, we can have both "real users of this platform" and "collaborators/privileged guests". We can also allow social login from different platforms (github, google, university internal OIDC) while still having one specific account. The main problem is we historically used a concept of "application auth" (which delegates nicely to horde auth most of the time) which defined both if the user can use the application and how to login to backends (smtp, imap, sieve, ldap to some degree, gollem samba backends, ...) and increasingly this is model doesn't fit very well. These days many services and resources horde needs to access live in cloud platforms which don't want username/password style logins. They want Oauth2.0/OIDC (everything google calendar/tasks/adressbook, social media, billing platforms) or XOauth (Imap, SMTP, ... ) which is OAuth but funneled into a traditional protocol's password field. |
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.
Wires OIDC/OAuth2 support into the Horde base application, independent of the Horde auth driver (LDAP, SQL, application, etc. all supported): - OAuthLoginController: accept GET in addition to POST to support direct links/buttons to the IdP. - LoginServiceFactory: register OidcPreLogoutHandler whenever OAuth/OIDC providers are configured — a user authenticating via LDAP/SQL/etc. may still hold OAuth tokens (e.g. for XOAUTH2 IMAP access) that need revocation/SLO on logout. No dependency on auth.driver. - LoginService::performLogout(): aggregate redirect URLs from pre-logout handlers; handler redirect takes priority over redirect_on_logout config. - OAuthAccountController: resolve a human-readable Horde username from OIDC userinfo claims (preferred_username, uid, login, email); store tokens for XOAUTH2 hooks; filter login.php as post-login redirect destination. - OAuthTokenRepositoryFactory: SQL-backed token repository. - Admin UI: OIDC-specific provider fields (logout strategy, SLO endpoints, XOAUTH2 domain). - conf.xml: OAuth/OIDC token storage tab under Authentication. - Migration 3: add OIDC-specific columns to horde_oauth_providers. - hooks.php.dist: smtp_credentials and backchannel logout route. An earlier revision of this branch also auto-redirected to the IdP when auth.driver was set to a dedicated 'oidc' value. That driver no longer exists — this integration works alongside any existing auth driver. An admin wanting to skip the login page entirely can already do so via the pre-existing generic alternate_login config. Depends on: - horde/Core: OIDC integration (PR horde#160) - horde/base refactor/login-logout-delegate-to-service (PR horde#109)
ab6cc13 to
635c51c
Compare
|
Hi Ralf, Sorry for the long silence on this — following up now that things have settled. I've reworked this branch (and the related ones in Core/imp/ingo) to drop the dedicated
Updated PRs, all rebased onto current FRAMEWORK_6_0:
Along the way I also found two unrelated Core/base bugs while working through the DI container and the login form — filed as separate PRs since they don't depend on any of the above:
And for the record: #190 is resolved and merged. #218 has a working fix in #227 — I know you'd rather land a cleaner long-term approach there, so no rush on my end regardless of when that follow-up lands. Let me know if the current shape still misses something from the Two Actor model, happy to keep iterating. Jean Charles |
|
Hi JCDelepine, thank you for updating this. This is much closer to what I intend and for application auth it matches well. |