Skip to content

fix(core): add CSRF token to HordePopup.popup at click time#171

Merged
ralflang merged 2 commits into
FRAMEWORK_6_0from
fix/popup-csrf-token
Jun 24, 2026
Merged

fix(core): add CSRF token to HordePopup.popup at click time#171
ralflang merged 2 commits into
FRAMEWORK_6_0from
fix/popup-csrf-token

Conversation

@TDannhauer

@TDannhauer TDannhauer commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add only the CSRF token to every HordePopup.popup() URL at click time via new HordeCore.addCsrfToken() (no legacy SID query parameter).
  • Ensure token_secret_key exists before read-only sessions are closed, so download/view scripts can validate HMAC tokens.
  • Fix ViewModeConfigurator to expose a modern HMAC HordeCore.conf.TOKEN instead of the legacy empty session slot.
  • Register TokenServiceFactory explicitly in DefaultInjectorBindings and use use imports in Registry to avoid doubled namespace resolution.

Motivation

After Horde 6 switched to HMAC CSRF tokens, IMP links that open MIME parts in a popup (e.g. “View HTML data in new window”) failed with “Invalid token!” and showed the portal instead of the message. Horde::popupJs() uses HordePopup.popup(), which never appended a token parameter, unlike HordeCore.popupWindow().

Session identity must stay in cookies/headers, not URL query parameters (review feedback).

Changes

  • js/hordecore.js: add HordeCore.addCsrfToken() (token only).
  • js/popup.js: call HordeCore.addCsrfToken() before window.open().
  • lib/Horde/Registry.php: seed per-session CSRF secret before SESSION_READONLY close.
  • src/DefaultInjectorBindings.php: explicit Token::class => TokenServiceFactory::class binding.
  • src/PageOutput/ViewModeConfigurator.php (+ factory, tests): use Horde\Token\Token for TOKEN.

Test plan

  • Open an HTML message in IMP dynamic view; click “View HTML data in new window”; popup shows rendered HTML.
  • No “Invalid token!” growler messages in the parent window.
  • Other Horde::popupJs() popups (help, prefs import, etc.) still open and authenticate correctly.
  • vendor/bin/phpunit --bootstrap vendor/autoload.php -c vendor/horde/core/phpunit.xml.dist vendor/horde/core/test/Unit/PageOutput/ViewModeConfiguratorTest.php vendor/horde/core/test/Unit/PageOutput/ViewModeConfiguratorDiscovererTest.php vendor/horde/core/test/Unit/Factory/TokenServiceFactoryTest.php

HordePopup.popup() did not merge session ID and CSRF token into popup
URLs, unlike HordeCore.popupWindow(). Append them at open time via
HordeCore.addRequestParams() when available.

Seed per-session token_secret_key before closing read-only sessions so
view/download endpoints can validate HMAC tokens.

ViewModeConfigurator: emit modern HMAC TOKEN for HordeCore.conf instead
of the legacy empty horde.token session slot.
@TDannhauer TDannhauer requested a review from ralflang June 22, 2026 15:34

@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.

I don't like adding session ID to ajax URLs like its 1998. These belong into a header (cookie or other).

@TDannhauer

Copy link
Copy Markdown
Contributor Author

Feel free to adapt 🙂

Session and tokens is your Expertise

Use HordeCore.addCsrfToken for popup navigation instead of
addRequestParams so only the CSRF token is appended; session identity
relies on cookies per review feedback.

Register TokenServiceFactory explicitly in DefaultInjectorBindings and
use TokenServiceFactory import in Registry to avoid doubled namespace
resolution inside Horde\Core.
@TDannhauer

Copy link
Copy Markdown
Contributor Author

@ralflang Addressed in fc1e3d5: popups now use new HordeCore.addCsrfToken() which appends only the CSRF token at click time — no SID in the URL. Session auth stays on cookies.

Also fixed the TokenServiceFactory DI binding / Registry imports so bootstrap no longer resolves a doubled Horde\Core\Horde\Core\... class name.

@TDannhauer TDannhauer requested a review from ralflang June 23, 2026 10:06
@ralflang

Copy link
Copy Markdown
Member

The TOKEN field is now generated on every page render rather than read from a session slot. That means each dynamic-view page render mints a new token. We used to reuse from session. Anyway we are going to migrate off Horde_Registry in the longer run.

@ralflang ralflang merged commit 6353481 into FRAMEWORK_6_0 Jun 24, 2026
0 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants