Skip to main content
Jahia Store
EN

UPA - MFA factors - Login UI

community
Download 0.2.0

Information

Module ID
mfa-factors-login-ui
Group ID
org.jahia.community
Status
community
Category
Authentication
Author
Florent BOURASSE
Developer website
https://github.com/Jahia/mfa-community-parent
Requires Jahia
8.2.3.0
Updated
2026-08-13

The single front-end for the MFA Community factor family, delivered as a Jahia JS-SDK module. It renders the complete step-up flow (username and password, factor chooser, then TOTP, WebAuthn, or email-code verification) and a self-service settings panel where signed-in users manage every factor: enroll or re-enroll TOTP, view and regenerate backup codes, and add, rename, or remove passkeys. It also offers a "lost access to your second factor" path that requests an administrator reset without leaking whether an account exists.

The UI is built to WCAG 2.2 AAA, with a shared accessible OTP input reused across the login and self-service screens. Install it only if you want the bundled login template; deploy via the Jahia provisioning API or the Modules UI (the .tgz is not picked up by the hot-deploy folder).

- Full login flow: password, factor selection, and TOTP / WebAuthn / email-code verification
- Self-service management for TOTP, backup codes, passkeys, and email factor
- Locked-out account recovery request (no account enumeration)
- WCAG 2.2 AAA accessible, keyboard-first, reduced-motion aware
- Internationalized; drop-in Jahia component for any login page

Screenshots

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

Requires Jahia 8.2.3.0Updated 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.

Requires Jahia 8.2.3.0Updated 2026-06-29
Requires Jahia 8.2.3.0Updated 2026-06-28