Aller au contenu principal
Jahia Store
FR

UPA - MFA factors - shared extensions

community
Télécharger 0.2.0

Informations

Identifiant du module
mfa-factors-extensions
Identifiant de groupe
org.jahia.community
Statut
community
Catégorie
Authentication
Auteur
Florent BOURASSE
Site web du développeur
http://www.jahia.com
Nécessite Jahia
8.2.3.0
Mis à jour
2026-08-13
Source
scm:git:git@github.com:Jahia/jahia-private.git/jahia-modules/mfa-factors-extensions

The factor-agnostic foundation of the MFA Community family. This bundle has no UI of its own; it provides the plumbing the TOTP and WebAuthn factors plug into: the /cms/login gate with IP allow-listing, the login/logout URL provider, the backup-code generator, per-site and global enforcement policy, an audit log, and the MfaSiteProvider SPI that lets each factor contribute its own enforcement state and per-site routing.

Install this first. Both factor modules declare it as a hard dependency (jahia-depends), so it starts ahead of them. Server administrators configure it under Administration → Server → Configuration → MFA Community.

  • Factor-agnostic /cms/login gate with IPv4/IPv6 and CIDR allow-listing
  • Global and per-site login/logout URL routing (file-backed OSGi configuration, one file per site)
  • One-shot backup-code generation shared across factors
  • Session-level GraphQL API, including the locked-out "request reset" flow (no account enumeration)
  • Consolidated audit and enrollment reporting surface for all installed factors

Captures d'écran

Versions

Security

Three vulnerabilities affecting 0.1.0 / 0.1.1, found by an adversarial review and each confirmed by reproduction against a live Jahia 8.2 before and after the fix (#100).

All three shared one root cause: a client-supplied site value was trusted to narrow or suppress an access-control decision.

  • The site request parameter defeated the /cms/login gate. MfaLoginGateDecision.isGated() resolved the site from request.getParameter("site"), validated only against [A-Za-z0-9_-]+, and used it to replace the "is any site enforcing?" answer. Naming a site where the factor was not enabled turned gating off — a password-only POST authenticated as root with no second factor while enforcement was active. The site context now only ever widens the decision.
  • The site argument to mfaInitiate suppressed a globally enforced factor. Per-site applicability was evaluated before enforcement, so a caller holding only a password could name a site with the factor disabled, receive a "skipped" preparation, and have verify() accept an empty code. Global enforcement is now evaluated first, and a per-site switch can never skip a user who owns the factor.
  • Any single-site administrator could strip MFA from any account, including root. resetUserMfa / resetUserWebauthn authorized on siteKey alone, then acted on an unconstrained userId. The subject is now resolved once and authorized in its own right; a reset targeting a global user requires server-administrator rights.

Also: enrollmentReport no longer hands any site administrator the MFA status of every account platform-wide, and unknown usernames are reported instead of returning a green confirmation for a user that was never touched.

New — loginGate.gateBasicAuth

The /cms/login gate can now also refuse a password presented in an Authorization: Basic header, closing the same bypass on the machine-facing surface. Default false, and deliberately opt-in: that credential shape is not confined to one endpoint, so arming it refuses the provisioning API, GraphQL, the tools and WebDAV platform-wide the moment one site enforces a factor.

Read the README section before enabling it — in particular, whitelist your automation hosts, not just an admin VPN range, and verify a whitelisted client actually gets through first, because behind a reverse proxy the IP whitelist fails closed (GHSA-4v3g-mcmj-83fp).

Fixed

  • The /cms/login gate wrote the response twice (valve + filter), surfacing as HTTP 500 instead of a redirect whenever a distinct loginUrl was configured.
  • The gate matched on the mere presence of username + password request parameters while running at pipeline position 0, so it refused unrelated endpoints that happened to use those field names. It now mirrors LoginEngineAuthValveImpl#isLoginRequested.
  • The admin screens could wipe your configuration. useQuery was read without error, so a failed load left constructor defaults in the form and Save wrote them back — silently clearing enforcedFactors, the IP whitelist and the login URL.
  • The admin UI stated that trusting X-Forwarded-For was ON by default and defaulted the checkbox to true. It is OFF, because trusting the header makes the IP whitelist spoofable (SEC-135).
  • The self-service disable/regenerate dialog offered backup codes the server does not accept there — each rejected attempt burned a rate-limit strike, walking a user who had lost their authenticator into locking themselves out of their own recovery.
  • The destructive "reset a user's MFA" action never showed its in-flight state: a React 18 batching bug unmounted the confirmation box in the same render that was meant to display it. Affected both the TOTP and WebAuthn copies.

Known limitation (documented, unchanged behaviour)

The /cms/login gate is scoped to global enforcement: with enforcedFactors empty it is inert, and loginGate.enabled does not override that. A per-site opt-in deployment still challenges enrolled users through the MFA login UI, but /cms/login remains a password-only door. See The /cms/login gate → Known limitation in the README for the two supported mitigations.

Quality

The module previously had no CI, no lint gate, no coverage measurement, and no tests for its React admin apps. This release adds all four: a build workflow, yarn lint and yarn test wired into the Maven build, JaCoCo coverage, and 115 component tests — plus 22 dependency updates, ESLint 9, and Node 22.23.2.

352 Java tests + 115 React tests + 26 Cypress specs, all green.

Compatibility

Jahia 8.2.3+, user-password-authentication 0.2.0, graphql-dxm-provider 3.4+, Java 11+.

Operators who use per-site group scoping should note that a globally enforced factor now overrides it (an out-of-scope user is challenged rather than skipped, and the override is logged) — see the README's Global enforcement section.

Full Changelog: 0_1_0...0_2_0

Nécessite Jahia 8.2.3.0Mis à jour 2026-08-13

Fixes

  • Admin UI: restored the vertical scrollbar on the MFA extensions global settings page (/jahia/administration/mfa-extensions-settings). The form was clipped with no scrollbar when it grew past the viewport.

Contents

0.1.0 plus the single fix above. No API or dependency changes.

Requirements

  • Jahia 8.2.3.0
  • user-password-authentication 0.2.0 (modules import org.jahia.modules.upa.mfa at [0.2,1))

Install

Deploy the three .jar bundles via the module manager / hot-deploy folder; install mfa-factors-login-ui-0.1.1.tgz via the provisioning API.

Nécessite Jahia 8.2.3.0Mis à jour 2026-06-29
Nécessite Jahia 8.2.3.0Mis à jour 2026-06-28