Small context: the OIDC code that surfaces this is an upcoming revision, not published yet — so this isn't blocking anything currently live, just flagging it while it's fresh.
Found something related in spirit to #190 (legacy/modern coexistence) but a distinct root cause — opening separately rather than piling onto that thread since the mechanism is different.
Symptom: on the Rampage stack, hitting a route whose middleware constructs Horde_Registry (e.g. AuthHordeSession, which depends on it) after an OIDC backchannel logout has revoked the user's IMP token — services/ajax.php/imp/poll is what surfaces it — produces:
PHP Warning: session_set_cookie_params(): Session cookie parameters cannot be changed when a session is active
PHP Warning: session_cache_limiter(): ...
PHP Warning: session_name(): ...
PHP Warning: session_set_save_handler(): ...
and, when the failing check is IMP's own transparent-auth validation, an unwanted forced logout.
Root cause, traced with logging on SessionLifecycle::setup()/SessionLifecycleFactory::create(): within a single Rampage request, SessionLifecycle gets constructed multiple times with different object identities — confirmed the modern container itself caches correctly (added the missing SessionLifecycle::class => SessionLifecycleFactory::class binding to DefaultInjectorBindings, which didn't change the symptom). Tracing the call sites down to Horde_Registry.php:
// line 525
$GLOBALS['injector'] = $injector = new Horde_Injector(new Horde_Injector_TopLevel());
Horde_Registry's own bootstrap builds a fresh legacy Horde_Injector and overwrites $GLOBALS['injector'] with it, every time it's constructed — including when a Horde_Registry instance is built as a middleware dependency mid-request on the modern Rampage stack, which already has its own Horde\Injector\Injector container. From that point on, Horde_Session.php:294 and Registry.php:2321 (both call sites in clearAuth()) resolve SessionLifecycle/HordeSession through this fresh legacy container instead of the Rampage one — so anything already cached in the Rampage container (session already configured via session_set_cookie_params() etc.) gets a second, independent SessionLifecycle instance that redoes setup() on a PHP session that's already active.
Tried pre-seeding $GLOBALS['injector'] with the Rampage container at the top of RampageBootstrap::run() — no effect, since Horde_Registry overwrites it again on construction regardless.
Not something I want to guess a fix for — this is really "two DI containers with different lifetimes coexist in one request whenever legacy Horde_Registry gets constructed on the modern stack," which seems like it needs a decision on your end (should Horde_Registry accept/reuse an injector rather than always minting its own?) rather than a local patch.
Small context: the OIDC code that surfaces this is an upcoming revision, not published yet — so this isn't blocking anything currently live, just flagging it while it's fresh.
Found something related in spirit to #190 (legacy/modern coexistence) but a distinct root cause — opening separately rather than piling onto that thread since the mechanism is different.
Symptom: on the Rampage stack, hitting a route whose middleware constructs
Horde_Registry(e.g.AuthHordeSession, which depends on it) after an OIDC backchannel logout has revoked the user's IMP token —services/ajax.php/imp/pollis what surfaces it — produces:and, when the failing check is IMP's own transparent-auth validation, an unwanted forced logout.
Root cause, traced with logging on
SessionLifecycle::setup()/SessionLifecycleFactory::create(): within a single Rampage request,SessionLifecyclegets constructed multiple times with different object identities — confirmed the modern container itself caches correctly (added the missingSessionLifecycle::class => SessionLifecycleFactory::classbinding toDefaultInjectorBindings, which didn't change the symptom). Tracing the call sites down toHorde_Registry.php:Horde_Registry's own bootstrap builds a fresh legacyHorde_Injectorand overwrites$GLOBALS['injector']with it, every time it's constructed — including when aHorde_Registryinstance is built as a middleware dependency mid-request on the modern Rampage stack, which already has its ownHorde\Injector\Injectorcontainer. From that point on,Horde_Session.php:294andRegistry.php:2321(both call sites inclearAuth()) resolveSessionLifecycle/HordeSessionthrough this fresh legacy container instead of the Rampage one — so anything already cached in the Rampage container (session already configured viasession_set_cookie_params()etc.) gets a second, independentSessionLifecycleinstance that redoessetup()on a PHP session that's already active.Tried pre-seeding
$GLOBALS['injector']with the Rampage container at the top ofRampageBootstrap::run()— no effect, sinceHorde_Registryoverwrites it again on construction regardless.Not something I want to guess a fix for — this is really "two DI containers with different lifetimes coexist in one request whenever legacy
Horde_Registrygets constructed on the modern stack," which seems like it needs a decision on your end (shouldHorde_Registryaccept/reuse an injector rather than always minting its own?) rather than a local patch.