Skip directly to page content
b13 GmbH

Hauptstätter Str. 59
70178 Stuttgart
Germany
+49 (0) 711 460 589 70 [email protected]

Changelog Module “Single-Sign-On”

Chapters of this Documentation

All notable changes to b13/sso-authentication are documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

2.0.3–2026–11–04

Fixed

  • A failed frontend SSO login no longer triggers a deprecation on TYPO3 v14.3. The sys_log entry takes the visitor's IP address from the request instead of GeneralUtility::getIndpEnv(), which v14.3 deprecates.

Security

  • onelogin/php-saml is required from 4.3.1 on. The constraint was ^4.0, which let a project install anything from 4.0.0 up to 4.2.x. Those versions pull in a robrichards/xmlseclibs release affected by CVE-2025-66475, where a crafted assertion passes signature validation—an authentication bypass in the library this extension verifies assertions with. Which version a site runs is decided by the project, not by this package, so a project that had once resolved to a 4.0.x release kept it through every update of this extension. Run composer update onelogin/php-saml after updating and check that the installed version is at least 4.3.1.

2.0.2 — 2026-10-19

Fixed

  • A frontend SSO login only finds users in userStoragePid. It searched every fe_users folder, so a person with accounts on two sites could be signed in to the other site's account. If you run several sites with frontend SSO, clear tx_sso_tenantid and tx_sso_objectidentifier on records outside userStoragePid that received them since 2.0.0.
  • Tenant plus object identifier wins over a username or email match. Other matches are ordered by uid, so the same record wins on every login.

Documentation

  • The frontend and backend login flows are diagrams now. "How It Works" drew both as ASCII art. Graphics now show the same steps, from the login page through the identity provider to the logged-in request, each with a full text description as alt text.

2.0.1 — 2026-10-03

Changed

  • tx_sso_tenantid and tx_sso_objectidentifier are no longer part of the claim mapping. Both were always filled from the raw tenantid and objectidentifier claims anyway, so the forced mapping entries only duplicated that. A newly federated user now gets both columns set explicitly, and a BeforeUserCreationEvent listener sees them in getUserData() as before—the object identifier now with its name identifier fallback. The two Entra ID URIs are ordinary attribute names now and can be mapped to any other column. The matching claimsMapping entries are gone from the example configurations and the docs; existing configurations that still carry them keep working.
  • The BackendBaseUrl label says what the setting does. It promised to prefix all URLs in the service provider metadata. In practice the assertion consumer service and single logout URLs are already absolute when it is applied, so the only value it can affect is a relative entityId — and it applies to the frontend as well, despite the name.

Fixed

  • A missing noGroupsPage no longer redirects a visitor to page 0. A logged-in frontend user whose only groups are the two pseudo-groups was sent to whatever noGroupsPage said, including when the site did not set it — plus a PHP warning for the missing key, and a type error on a request without routing. Without the page configured there is now no redirect, and the visitor stays where they are.
  • A missing loginStatusPage falls back to the site's root page. Same missing key, same warning, and a logout that ended on page 0. The fallback now matches what the assertion consumer service already did.
  • The single logout no longer leaves a used session index on the user. After an identity-provider-initiated logout, tx_sso_sessionindex stayed on the record, so the next logout offered the identity provider an index for a session it had already closed.
  • A rejected assertion now reaches sys_log. The entry the response from the identity provider was rejected—an invalid signature, an expired or replayed assertion, a Destination mismatch behind a reverse proxy—was never written, because TYPO3 drops a login request without a valid request token before it counts as a failed login. Only the no TYPO3 user entry made it into the Log module. Both are recorded now, as Logging describes.

Security

  • The request token for the SSO return is only provided for a validated assertion. It used to be enough that the submitted password equalled the internal SSO marker, so a forged login form could sign a visitor in to an account whose password had been set to that value.

Documentation

  • The documentation has images. Seven of them, each next to the passage it illustrates: the SSO entry on the backend login screen, the extension settings, a frontend login template with the SSO link, the tx_sso_* columns on a backend user, a rejected login in the Log module, the Install Tool as the way back in, and the KeyCloak client side by side with the service provider metadata TYPO3 publishes. All of them were recorded against the bundled KeyCloak demo realm, so none shows data from a real identity provider.
  • Backend paths match TYPO3 v14. The Log module is named with its v14 menu path, Administration > Log, next to v13's System > Log. The filter hint points at the Channel filter the module actually has, and the extension settings are referred to by the form's real name, Extension Configuration.

2.0.0 — 2026-09-10

Added

  • TYPO3 v14 support. One code base now serves TYPO3 v13.4 LTS and v14.3. The backend login provider implements modifyView(), which both supported lines prefer over the removed render(), and the authentication service tolerates v14 dropping the $passwordTransmissionStrategy parameter from processLoginData().
  • A listener can refuse to create a user. BeforeUserCreationEvent now implements StoppableEventInterface, so a listener can call preventCreation() and the login is treated exactly like federation being switched off. Until now, every authenticated SAML identity received a TYPO3 account when federation.enabled was set, with no way to restrict that by claim — a real gap whenever the same identity provider also serves other applications, for example a company-wide Entra ID tenant where only one department should reach this TYPO3 instance.
  • Contact information in the generated service provider metadata is configurable. Set contactPerson in the same configuration file as everything else; it is omitted entirely when unset. If you set a type (technical, support, administrative, billing or other), both givenName and emailAddress are required — otherwise the SAML toolkit rejects the whole configuration rather than just that block.

Changed

  • [!!!] Your own login template renders the frontend SSO button. ModifyFrontendLoginView no longer merges a partial root path into the view. It assigns additionalAuthenticationProviders, ssoAcsRedirectUrl and enforceSSO, and rendering is up to the site's own Login.html. A site that rendered the shipped AzureAdLogin partial by name gets a broken login page until its template is updated — the new contract, including the redirect_url parameter, is documented in Documentation/FrontendLogin.md.
  • The release archive contains only what an installation needs. The test suite, the KeyCloak development fixtures, the DDEV environment, and the Playwright toolchain are excluded from the package. Documentation/ is shipped deliberately, because that is what the marketplace reads.
  • [!!!] TYPO3 v12 is no longer supported. This release requires TYPO3 ^13.4 || ^14.3 and PHP ^8.3. Dropping v12 also collapsed the backend login provider onto a single implementation, because v13 and v14 both prefer modifyView() over render().

Removed

  • [!!!] The sso:migrateDatabaseNamespace command. It migrated column names from a pre-1.0 layout and has no purpose on a supported version.
  • [!!!] The shipped backend login layouts and the SsoLogin template. They existed to style the provider switch per core version and are unnecessary now that one provider implementation covers both supported lines. Nothing in a normal installation references them; a site that copied or overrode them should remove those overrides.

Fixed

  • Existing users are matched reliably, so logins stop creating duplicates. The lookup only matched on the TYPO3 username or a handful of raw claim names (name, login_name, emailaddress, email). Neither Entra ID's namespaced claim URIs nor a typical OID-based KeyCloak client ever sends those, so as soon as a user's TYPO3 username differed from what the identity provider sent, every login fell through to federation and created another account. The lookup now also uses the claimsMapping-resolved email, and tenant plus object identifier is a genuine alternative match instead of an additional condition that could only ever narrow an existing one.
  • The WS-Federation name claim no longer overwrites the SSO checkbox. The default field mapping pointed the raw name claim — which ADFS and Entra ID commonly send — at tx_sso_enabled, a boolean field. The claim string landed in that column on every login and silently replaced whatever an editor had set there.
  • A listener can change the data of an existing user again. BeforeUserDataUpdatedEvent::setUpdateData() had no effect at all: the update re-read the original user record after dispatching the event and wrote that instead. Removing a single field in a listener is now the way to keep SSO from overwriting a manually corrected value such as realName.
  • Finishing a password reset no longer bounces back to the identity provider. When a stale be_lastLoginProvider cookie still pointed at SSO while the password form was rendered, the reset link and the form action were both built from that cookie. Submitting the password form also rewrote the cookie back to SSO on every login instead of correcting itself.

Security

  • The package no longer ships private keys. Up to and including 1.3.4 the release archive carried a KeyCloak realm export with two RSA private keys in cleartext—the realm’s signing and encryption keys—alongside a certificate issued for an internal hostname, plus a service provider configuration file containing tenant identifiers, contact addresses, and a federation certificate. Neither Resources/ nor Configuration/ was excluded from the archive, so every 1.x installation received those files on disk. The keys are stripped, the example realm is neutralized, the KeyCloak fixtures are kept out of the package, and the tenant configuration file is deleted. If you ever imported the shipped example realm into a KeyCloak you still operate, rotate that realm’s keys.
  • A disabled backend user could get back in through SSO. A disabled be_users row was invisible to the existing-user lookup, so federation created a second, active row with the same username and the rejected user logged in again instead of staying locked out. If you run with federation.enabled: true, check be_users for duplicate usernames after updating.

Documentation

  • Documentation/ is now the source of truth and the README covers only what you need in order to decide and to install. Start at Documentation/Index.md.
  • The dead sp: block is gone from the backend example. The example and two README snippets showed a nested sp: block with entityId, assertionConsumerService and singleLogoutService. Those values are assembled from the backend entry point plus the top-level entityId and acsUrl and were overwritten regardless of what the file said, so the block never had any effect. The example now shows the two top-level keys that are genuinely read.
  • enabled and strict no longer appear in the backend example. enabled is never read for the backend service provider file — only the enableBE extension setting governs backend SSO, and the frontend's per-site enabled is a different key — so showing it implied a switch that never existed. strict is read, but by the SAML toolkit rather than by this extension, and it already matches the toolkit's default, so it is documented instead.
  • allowEmailAsUsername is documented.

Tests

  • Add a functional test suite, one test per branch of the existing-user lookup plus federation enabled and disabled, built on a mocked SAML response so the user details are constructed by production code.
  • Add unit tests for SamlSettings, including a regression guard that nothing maps to tx_sso_enabled by default again.
  • Add an end-to-end suite that drives the real login flow. Playwright walks a browser through frontend SSO, single logout, and the service provider metadata endpoint against a KeyCloak identity provider, with a demo site package and a committed DDEV environment providing the fixture site.
  • Static analysis runs against both supported TYPO3 lines.

1.3.4 — 2026-08-13

Fixed

  • TYPO3 compatibility metadata in ext_emconf.php. constraints.depends.typo3 was * and now states 12.4.0-13.4.99, matching the Composer requirement ^12.4 || ^13.4. Composer installs were already constrained correctly; this fixes the compatibility information shown for non-Composer (TER) installs.

Changed

  • Package version moved to extra.typo3/cms.version. The top-level version field was removed from composer.json to follow b13's release convention — composer validate --strict rejects a top-level version. No effect on installation.

1.3.3 — 2026-08-13

Documentation

  • Add this changelog and link it from the README.

1.3.2 — 2026-07-29

Fixed

  • Unit test suite on TYPO3 v12. The v12 job asserted an X-Forwarded-Proto behaviour that only TYPO3 v13 provides — v12 does not evaluate that header, so the expectation is now skipped on v12, letting the pipeline pass on both core lines.

1.3.1 — 2026-07-29

Fixed

  • SSO behind a TLS-terminating reverse proxy. The SAML toolkit now follows TYPO3's own view of the current URL instead of reconstructing it from $_SERVER. Previously the Destination in the assertion did not match the internal http URL the proxy forwarded, so logins failed silently and fell back to the login form. The usual reverseProxyIP / reverseProxySSL configuration is now all that is required (on TYPO3 v12 reverseProxySSL is mandatory). See Documentation/ReverseProxy.md.

1.3.0 — 2026-07-28

Added

  • Logging for failed SSO logins. A rejected login now records why it failed: rejected assertions are written to sys_log (visible in System > Log, distinguishing a rejected IdP response from a missing TYPO3 user), and full technical detail goes to the PSR-3 logger under the B13.SSOAuthentication component. See Documentation/Logging.md for the log levels and a file-writer example.

1.2.0 — 2026-07-28

Added

  • enforceSSO option for dual or SSO-only login. Off by default, so SSO and username/password are offered side by side. When enabled it makes SSO the only accepted login (password logins are rejected during authentication, not just hidden). Configured per scope: a top-level key in the backend YAML config file, and per site under settings.sso_authentication for the frontend.

Fixed

  • Resolve the backend entry point instead of hard-coding /typo3/, so a custom backend path or a subdirectory installation derives the correct SAML endpoints on both v12 and v13.
  • Backend-specific default for the ACS endpoint, which follows a custom backend entry point automatically.
  • Ship the backend login layout per core version (v12 / v13).
  • Accept a group id in valueMapping without requiring it to be wrapped in an array.
  • Make the unit test pipeline actually run the tests.

1.1.0 — 2026-05-07

Added

  • BeforeUserDataUpdatedEvent — a PSR-14 event fired when an existing user is updated from a SAML response, alongside the existing user-creation event.
  • CI pipeline and the initial unit-test infrastructure.
  • Backend login template updated for TYPO3 v13.

Fixed

  • Weak open-redirect protection in sanitizeRelayState. (security)
  • Malformed query strings in SSO redirect URLs.
  • ModifyBackendLoginView no longer uses frontend settings.

1.0.x and earlier

The 1.0 line established the extension: SAML authentication for the TYPO3 backend and frontend, user federation with claims mapping, and Single Logout. Later 1.0.x releases lowered the requirement to PHP 8.2, removed PHP 8.3-only syntax, fixed a range of claims-handling issues (including using the email as nameId), added exception logging, and cleaned up PHP warnings. See the tags 1.0.0–1.0.5 for details.