Skip to content

Remember MFA verification for users who choose "Keep me signed in" - #13

Open
tombokombo wants to merge 1 commit into
jenkinsci:masterfrom
tombokombo:feature/remember-mfa-cookie
Open

tombokombo wants to merge 1 commit into
jenkinsci:masterfrom
tombokombo:feature/remember-mfa-cookie

Conversation

@tombokombo

@tombokombo tombokombo commented Sep 30, 2026 •

Copy link
Copy Markdown

Adds a "remember MFA" capability so users who check Jenkins' Keep me signed
in
at login are not challenged for a TOTP code on every new HTTP session.

What changed:

  • After a successful MFA verification, users authenticated with the Jenkins
    remember-me cookie receive a long-lived openmfa-remember cookie
    (stateless, HMAC-SHA256-signed). While it is valid, MFAFilter marks the
    new session as verified instead of redirecting to the MFA challenge.
  • The token is bound to the username, an absolute expiry, and a hash of the
    user's current TOTP secret — re-enrolling or disabling MFA invalidates all
    previously issued cookies. Logout clears the cookie.
  • New global configuration: Remember MFA for "Keep me signed in" (hours)
    (default 24, 0 disables) and an optional rememberMfaKey signing key.
    The key is auto-generated and persisted on first use; it can be provided
    explicitly via JCasC (any secret source) so cookies survive restarts on
    ephemeral-JENKINS_HOME deployments (e.g. jenkins-operator).
  • JCasC: exemptUsers/exemptRoles are now list-valued, matching the shape
    the README already documented (the string-only binding used to fail with
    ConfiguratorException on the documented example). The UI textarea still
    edits one entry per line.
  • Jenkins baseline bumped to 2.568 (BOM bom-2.568.x:7093.v37de7b_4a_8a_4f)
  • README documents the new behavior and ephemeral-home deployment guidance.

Upgrade note: previously persisted string-form exemptions in an existing
JENKINS_HOME are dropped on upgrade (field type change) — re-save the
global configuration once, or let JCasC re-apply it. Per-user data
(MFAUserProperty) is unchanged, so existing enrollments are unaffected.

Testing done

  • Automated: 134 tests pass (mvn verify, SpotBugs clean, 0 findings).
    New coverage added in this PR:
    • RememberMFAServiceTest (9 tests): token validation — expiry, tampered
      signature, tampered expiry, wrong user, changed TOTP secret, malformed
      values, separator characters in usernames, enable/disable via
      configured hours.
    • RememberMFAWebTest (8 tests, JenkinsRule + HtmlUnit): cookie issued
      only when remember-me is used, filter accepts a valid cookie in a fresh
      session, rejects tampered/absent cookies, feature disabled via 0
      hours, logout clears the cookie.
    • MFAGlobalConfigurationCasCTest: binds the documented JCasC yaml
      (list-valued exemptions, rememberMfaHours, rememberMfaKey).
    • MFAGlobalConfigurationTest: list persistence, UI text form, default
      hours.
  • Manual, local (mvn hpi:run, Jenkins 2.568.3): full curl-driven E2E —
    login with remember_me, TOTP verify issues the cookie (HttpOnly, correct
    expiry), fresh session with the cookie skips MFA, control session without
    it is challenged, tampered signature/expiry rejected, logout clears the
    cookie, and the cookie stays valid across a full Jenkins restart with the
    persisted signing key.
  • Manual, staging (jenkins-operator on Kubernetes, custom image, signing key
    supplied from Vault via JCasC): verified the signing key is stable across
    pod restarts (same key hash before/after) and that a valid cookie skips
    the MFA challenge after kubectl delete pod.

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests that demonstrate the feature works or the issue is fixed

@tombokombo
tombokombo requested a review from a team as a code owner September 30, 2026 10:57
@github-actions

Copy link
Copy Markdown

Missing required label for changelog. Requires at least 1 of: bug, chore, dependencies, documentation, enhancement, feature, internal, localization, major-bug, regression-fix, security, skip-changelog. Found: .

You can add the required label by adding a comment with the following text: /label <category>

@tombokombo

Copy link
Copy Markdown
Author

/label feature

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant