From b7569ac4ff5c78127bc09aaaea983a663d4b6abe Mon Sep 17 00:00:00 2001 From: Coskun Aydinoglu Date: Fri, 19 Jun 2026 09:24:04 +0000 Subject: [PATCH] fix(two-factor-auth): gate 2FA enforcement on global setting (SER-2911) When global 2FA was enabled, every user who logged in was force-enrolled and got two_factor_auth.enabled + secret_token persisted on their member record. After an admin turned global 2FA off, those persisted flags remained, so previously created users were still challenged for 2FA at login (and password reset), while newly created users were not. Make the global setting the single source of truth: login and password reset only enforce 2FA while two-factor-auth.globally_enabled is true. Disabling it now applies to all users regardless of stale per-user flags. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01V4HJ5qrPiDme1u8XqcjxqF --- plugins/two-factor-auth/frontend/app.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/two-factor-auth/frontend/app.js b/plugins/two-factor-auth/frontend/app.js index 1127c3d0ae9..0a4062c8378 100755 --- a/plugins/two-factor-auth/frontend/app.js +++ b/plugins/two-factor-auth/frontend/app.js @@ -34,7 +34,8 @@ const { generateQRCode } = require('../lib.js'); // member is found countlyDb.collection('members').findOne({_id: passwordReset.user_id}, {}, function(memberErr, member) { - if (member && member.two_factor_auth && member.two_factor_auth.enabled && member.two_factor_auth.secret_token) { + // Only enforce 2FA during reset while it is globally enabled (SER-2911) + if (plugins.getConfig("two-factor-auth").globally_enabled && member && member.two_factor_auth && member.two_factor_auth.enabled && member.two_factor_auth.secret_token) { if (!req.query.auth_code) { // user has not passed the 2fa res.render("../../../plugins/two-factor-auth/frontend/public/templates/enter2fa_reset", { @@ -91,7 +92,8 @@ const { generateQRCode } = require('../lib.js'); } countlyDb.collection('members').findOne({_id: passwordReset.user_id}, {}, function(memberErr, member) { - if (member && member.two_factor_auth && member.two_factor_auth.enabled && member.two_factor_auth.secret_token) { + // Only enforce 2FA during reset while it is globally enabled (SER-2911) + if (plugins.getConfig("two-factor-auth").globally_enabled && member && member.two_factor_auth && member.two_factor_auth.enabled && member.two_factor_auth.secret_token) { if (passwordReset.two_factor_auth_passed) { next(); } @@ -113,8 +115,11 @@ const { generateQRCode } = require('../lib.js'); // modify login flow app.post(countlyConfig.path + '/login', function(req, res, next) { members.verifyCredentials(req.body.username, req.body.password, async function(member) { - // if member exists and 2fa is enabled globally or for the user - if (member && (member.two_factor_auth && member.two_factor_auth.enabled || plugins.getConfig("two-factor-auth").globally_enabled)) { + // 2FA is governed solely by the global setting. When it is + // disabled no user is prompted for 2FA, even if their member + // record still carries two_factor_auth.enabled from a time when + // 2FA was globally enabled (SER-2911). + if (member && plugins.getConfig("two-factor-auth").globally_enabled) { // if 2fa is not set up for the user if ((member.two_factor_auth === undefined || member.two_factor_auth.secret_token === undefined) && (req.body.auth_code === undefined || req.body.secret_token === undefined)) {