fix duo 2fa failing to add #2432

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Mar 11, 2025 at 19:24 UTC 1f83b7927a01614ce1cc56854f187c1d2f71d949
1 file changed +67 -74
webserver.js
+67 -74
@@ -1433,6 +1433,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1433 delete req.session.temail;
1434 delete req.session.tsms;
1435 delete req.session.tmsg;
1436 + delete req.session.tduo;
1437 delete req.session.tpush;
1438 delete req.session.messageid;
1439 delete req.session.passhint;
@@ -7008,104 +7009,96 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7009 res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page
7010 return;
7011 } else {
7011 - // User credentials are stored in session, just check again and get userid
7012 - obj.authenticate(sec.tuser, sec.tpass, domain, function (err, userid, passhint, loginOptions) {
7013 - if ((userid != null) && (err == null)) {
7014 - // Login data correct, now exchange authorization code for 2FA
7015 - const duo = require('@duosecurity/duo_universal');
7016 - const client = new duo.Client({
7017 - clientId: domain.duo2factor.integrationkey,
7018 - clientSecret: domain.duo2factor.secretkey,
7019 - apiHost: domain.duo2factor.apihostname,
7020 - redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('?key=' + domain.loginkey) : '')
7021 - });
7022 - client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) {
7023 - const sec = parent.decryptSessionData(req.session.e);
7024 - if ((sec != null) && (sec.duoconfig == 1)) {
7025 - // Duo 2FA exchange success
7026 - parent.debug('web', 'handleRootRequest: Duo 2FA configuration success.');
7027 -
7028 - // Enable Duo for this user
7029 - var user = obj.users[userid];
7030 - if (user.otpduo == null) {
7031 - user.otpduo = {};
7032 - db.SetUser(user);
7033 -
7034 - // Notify change
7035 - var targets = ['*', 'server-users', user._id];
7036 - if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
7037 - var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msgid: 160, msg: "Enabled duo two-factor authentication.", domain: domain.id };
7038 - if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
7039 - parent.DispatchEvent(targets, obj, event);
7040 - }
7041 -
7042 - // Clear the Duo state
7043 - delete sec.duostate;
7044 - delete sec.duoconfig;
7045 - req.session.e = parent.encryptSessionData(sec);
7046 -
7047 - var url = req.session.duorurl;
7048 - delete req.session.duorurl;
7049 - res.redirect(url ? url : domain.url); // Redirect back to the user's original page
7050 - } else {
7012 + const duo = require('@duosecurity/duo_universal');
7013 + const client = new duo.Client({
7014 + clientId: domain.duo2factor.integrationkey,
7015 + clientSecret: domain.duo2factor.secretkey,
7016 + apiHost: domain.duo2factor.apihostname,
7017 + redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('?key=' + domain.loginkey) : '')
7018 + });
7019 + if (sec.duoconfig == 1) {
7020 + // Login data correct, now exchange authorization code for 2FA
7021 + var userid = req.session.userid;
7022 + client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) {
7023 + // Duo 2FA exchange success
7024 + parent.debug('web', 'handleRootRequest: Duo 2FA configuration success.');
7025 + // Enable Duo for this user
7026 + var user = obj.users[userid];
7027 + if (user.otpduo == null) {
7028 + user.otpduo = {};
7029 + db.SetUser(user);
7030 + // Notify change
7031 + var targets = ['*', 'server-users', user._id];
7032 + if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
7033 + var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msgid: 160, msg: "Enabled duo two-factor authentication.", domain: domain.id };
7034 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
7035 + parent.DispatchEvent(targets, obj, event);
7036 + }
7037 + // Clear the Duo state
7038 + delete sec.duostate;
7039 + delete sec.duoconfig;
7040 + req.session.e = parent.encryptSessionData(sec);
7041 + var url = req.session.duorurl;
7042 + delete req.session.duorurl;
7043 + res.redirect(url ? url : domain.url); // Redirect back to the user's original page
7044 + }).catch(function (err) {
7045 + const sec = parent.decryptSessionData(req.session.e);
7046 + // Duo 2FA exchange success
7047 + parent.debug('web', 'handleRootRequest: Duo 2FA configuration failed.');
7048 + // Clear the Duo state
7049 + delete sec.duostate;
7050 + delete sec.duoconfig;
7051 + req.session.e = parent.encryptSessionData(sec);
7052 + var url = req.session.duorurl;
7053 + delete req.session.duorurl;
7054 + res.redirect(url ? url : domain.url); // Redirect back to the user's original page
7055 + });
7056 + } else {
7057 + // User credentials are stored in session, just check again and get userid
7058 + obj.authenticate(sec.tuser, sec.tpass, domain, function (err, userid, passhint, loginOptions) {
7059 + if ((userid != null) && (err == null)) {
7060 + // Login data correct, now exchange authorization code for 2FA
7061 + client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) {
7062 + const sec = parent.decryptSessionData(req.session.e);
7063 // Duo 2FA exchange success
7064 parent.debug('web', 'handleRootRequest: Duo 2FA authorization success.');
7065 req.session.userid = userid;
7066 delete req.session.currentNode;
7067 req.session.ip = req.clientIp; // Bind this session to the IP address of the request
7068 setSessionRandom(req);
7057 -
7058 - // Clear the Duo state
7069 + // Clear the Duo state and user/pass
7070 delete sec.duostate;
7071 + delete sec.tuser;
7072 + delete sec.tpass;
7073 req.session.e = parent.encryptSessionData(sec);
7061 -
7074 obj.parent.authLog('https', 'Accepted Duo authentication for ' + userid + ' from ' + req.clientIp + ':' + req.connection.remotePort, { useragent: req.headers['user-agent'], sessionid: req.session.x });
7075 res.redirect(domain.url + getQueryPortion(req));
7064 - }
7065 - }).catch(function (err) {
7066 - console.log('err', err);
7067 - const sec = parent.decryptSessionData(req.session.e);
7068 - if ((sec != null) && (sec.duoconfig == 1)) {
7069 - // Duo 2FA exchange success
7070 - parent.debug('web', 'handleRootRequest: Duo 2FA configuration failed.');
7071 -
7072 - // Clear the Duo state
7073 - delete sec.duostate;
7074 - delete sec.duoconfig;
7075 - req.session.e = parent.encryptSessionData(sec);
7076 -
7077 - var url = req.session.duorurl;
7078 - delete req.session.duorurl;
7079 - res.redirect(url ? url : domain.url); // Redirect back to the user's original page
7080 - } else {
7076 + }).catch(function (err) {
7077 + const sec = parent.decryptSessionData(req.session.e);
7078 // Duo 2FA exchange failed
7079 parent.debug('web', 'handleRootRequest: Duo 2FA authorization failed.');
7083 -
7080 // Clear the Duo state
7081 delete sec.duostate;
7082 req.session.e = parent.encryptSessionData(sec);
7087 -
7083 req.session.loginmode = 1;
7084 req.session.messageid = 117; // Invalid security check
7085 res.redirect(domain.url + getQueryPortion(req));
7091 - }
7092 - });
7093 - } else {
7094 - // Login failed
7095 - parent.debug('web', 'handleRootRequest: login authorization failed when returning from Duo 2FA.');
7096 - req.session.loginmode = 1;
7097 - res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page
7098 - return;
7099 - }
7100 - });
7086 + });
7087 + } else {
7088 + // Login failed
7089 + parent.debug('web', 'handleRootRequest: login authorization failed when returning from Duo 2FA.');
7090 + req.session.loginmode = 1;
7091 + res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page
7092 + return;
7093 + }
7094 + });
7095 + }
7096 }
7097 });
7098
7099 // Configure Duo handler
7100 obj.app.get(url + 'add-duo', function (req, res) {
7101 var domain = getDomain(req);
7107 - const sec = parent.decryptSessionData(req.session.e);
7108 -
7102 if (req.session.userid == null) {
7103 res.sendStatus(404);
7104 } else {