Files
kevinveenbirkenbachandClaude Opus 5.5 dd955a71a6 style(markdown): pin list markers to dash and convert every list
The 16.0.0 entry pkgmgr wrote on top of CHANGELOG.md uses "-" bullets
while every older entry uses "*". MD004's default "consistent" style takes
the marker of the first list in a file, so lint-markdown reported 400
MD004 findings in CHANGELOG.md and the pre-push gate refused the release
push.

MD004 is now pinned to "dash", the marker pkgmgr and the changelog skill
write, and make autoformat (markdownlint-cli2 --fix) converted the lists
of the 72 files that still used "*". Only list markers changed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 23:04:02 +02:00

4.7 KiB

Joomla 6 Keycloak OIDC SSO plugin (plg_system_keycloak)

Native OIDC SSO against Keycloak for Joomla 6, with RBAC group mapping and an env-toggleable local-form fallback at /administrator?fallback=local (Modus 3 per requirement 013).

Build

The plugin's PHP dependencies (jumbojett/openid-connect-php) are vendored at deploy time inside the Joomla container. Composer is baked into the role's custom image by roles/web-app-joomla/files/Dockerfile. The role-side tasks/08_oidc_plugin.yml copies the plugin source into the container, runs composer install --no-dev, and installs the plugin via the Joomla CLI:

php cli/joomla.php extension:install --path=/tmp/plg_system_keycloak

The repository working tree stays clean (no vendor/ checked in) and the host MUST NOT need a PHP or Composer installation.

Configuration (env)

The plugin reads its runtime config from the Joomla container's environment, so the same plugin code works against any Keycloak realm without manual reconfiguration through the Joomla admin UI.

Variable Purpose Default
JOOMLA_OIDC_ISSUER_URL Keycloak realm issuer URL. (required)
JOOMLA_OIDC_CLIENT_ID OIDC client ID in the realm. (required)
JOOMLA_OIDC_CLIENT_SECRET OIDC client secret. (required)
JOOMLA_OIDC_REDIRECT_URI Callback URL https://<joomla>/index.php?option=keycloak&task=callback. (required)
JOOMLA_OIDC_FALLBACK_ENABLED If false, the local-form fallback at /administrator?fallback=local is disabled (Modus 1 in effect). true
JOOMLA_OIDC_GROUP_ADMIN Keycloak group path that maps onto Joomla's Super Users (id 8). /roles/web-app-joomla/administrator
JOOMLA_OIDC_GROUP_EDITOR Keycloak group path that maps onto Joomla's Editor (id 4). /roles/web-app-joomla/editor
JOOMLA_OIDC_GROUP_USER Keycloak group path that maps onto Joomla's Registered (id 2). /roles/web-app-joomla
JOOMLA_OIDC_END_SESSION_URL RP-initiated logout endpoint at Keycloak. <issuer>/protocol/openid-connect/logout

A user whose Keycloak groups claim matches none of the three mapped paths is refused. This is the documented RBAC gate per requirement 013. The Joomla account is created on first login if it does not already exist. Subsequent logins re-sync the group memberships from Keycloak.

Routes the plugin claims

URL Purpose
/index.php?option=keycloak&task=login Start the OIDC authorization-code flow.
/index.php?option=keycloak&task=callback OIDC callback endpoint.
/index.php?option=keycloak&task=logout RP-initiated logout against Keycloak.
/index.php?fallback=local Local Joomla form-login (Modus 3 hatch).

Watch points

  • The plugin trusts the Keycloak-issued ID token. The jumbojett/openid-connect-php library validates the JWT signature against the realm's JWKS, so the issuer URL MUST be reachable from the Joomla container at the time the user authenticates.
  • The plugin lives in the system plugin group so it can intercept every request via onAfterInitialise. It MUST run BEFORE the Joomla local form-login plugin in the system event chain so the redirect short-circuits any local-account authentication attempt. System plugins are ordered alphabetically. keycloak ranks before users, which is the typical local-form gate.
  • The local-form fallback at ?fallback=local is documented as an emergency hatch. For high-security deployments, set JOOMLA_OIDC_FALLBACK_ENABLED=false to disable it (Modus 1 effective).