Skip to content

Conversation

@Jan-Schuppik
Copy link
Contributor

@Jan-Schuppik Jan-Schuppik commented Aug 4, 2025

This PR introduces basic two-factor authentication (2FA) using Time-based One-Time Passwords (TOTP) support for Icinga Web 2. The implementation is functional and provides an additional security layer, but it’s an initial version.

TOTP is an algorithm that generates a time-limited numeric code based on a shared secret and the current time, ensuring that each code is valid only for a short window. After enabling 2FA, users authenticate with their usual Icinga Web credentials and are then prompted to provide a valid TOTP code from their authenticator app (e.g., Google Authenticator, Authy).

current authentication process

Currently, Icinga Web authentication follows this workflow:

  1. First, it checks whether the current request is already authenticated via session.

  2. If not, it checks whether the request is authenticated via external authentication.

  3. If both checks fail, and if the request is an API request with the header X-REQUESTED-WITH not set to XMLHttpRequest, authentication falls back to HTTP Basic Auth. In this case, credentials are verified directly and external user backends are skipped.

  4. If authentication still fails, the user is redirected to the login page (icingaweb2/authentication/login). The login form requires a username and password and stores a successful authentication in session.

about the implementation

  • Login flow & session gating

    After a successful username/password login, we set a session flag must_challenge_2fa_token. The login action then renders a dedicated Challenge2FAForm to collect the TOTP code. On success we flip twoFactorSuccessful in session and complete the login. There’s also a Cancel button to return to the password form. 
    If 2FA is enabled for a user, this user isn't able to use the HTTP-authentication (API request)

  • 2FA runtime checks

    Auth::setupUser() initializes twoFactorEnabled from user preferences and twoFactorSuccessful from session. Auth::isAuthenticated() now denies access if 2FA is enabled but the TOTP challenge hasn’t succeeded yet. Audit logging is moved to the point where both factors have passed. 

  • User preferences & permissions

    New privilege user/two-factor-authentication controls who may configure 2FA in Account → Preferences. When allowed, we render a new TotpForm above the existing preferences that lets users enable/disable 2FA and manage their TOTP secret.
    (It would make more sense to be able to enforce 2FA instead of requiring permission to use it)

  • TOTP management UI (TotpForm)

    Allows Generate, Renew, Delete secret and Save changes. Pending secrets are kept in session until the user confirms; submitting persists to preferences and writes/deletes the secret in the DB as needed. Labels, temporary state handling, and error-proofing (when enabled_2fa isn’t set) are included. 

  • Backend: TOTP generation/verification

    New Icinga\Authentication\Totp service encapsulates secret lifecycle and code verification using a PSR clock. It stores per-user secrets in table icingaweb_totp with columns username, secret, ctime, mtime. Methods include generateSecret(), renewSecret(), deleteSecret(), verify(), makeStatePersistent() and helpers for QR provisioning. A lightweight PsrClock is added. 

  • QR provisioning

    When creating/renewing a secret, we display an otpauth:// QR code in the form so users can enroll with an authenticator app (Google Authenticator, Authy, etc.). Styling tweaks are included. 

  • Schema & setup

    • MySQL schema is extended for the icingaweb_totp table; the setup wizard is adjusted accordingly.

require:

@Jan-Schuppik Jan-Schuppik requested a review from lippserd August 4, 2025 08:10
@Jan-Schuppik Jan-Schuppik self-assigned this Aug 4, 2025
@cla-bot cla-bot bot added the cla/signed label Aug 4, 2025
@jrauh01 jrauh01 self-requested a review September 12, 2025 09:15
Copy link
Contributor

@jrauh01 jrauh01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add to the description:

  • Short section about the functionality of 2FA with TOTP
  • How does the authentication currently work in Icinga Web
  • Information about your implementation
  • Reference to the required icinga-php-thirdparty PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants