fix duo 2fa failing to add #2432

Signed-off-by: si458 <simonsmith5521@gmail.com>
This commit is contained in:
si458 2025-03-11 19:24:57 +00:00
parent 88a765bb13
commit 1f83b7927a

View File

@ -1433,6 +1433,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
delete req.session.temail; delete req.session.temail;
delete req.session.tsms; delete req.session.tsms;
delete req.session.tmsg; delete req.session.tmsg;
delete req.session.tduo;
delete req.session.tpush; delete req.session.tpush;
delete req.session.messageid; delete req.session.messageid;
delete req.session.passhint; delete req.session.passhint;
@ -7008,104 +7009,96 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page
return; return;
} else { } else {
// User credentials are stored in session, just check again and get userid const duo = require('@duosecurity/duo_universal');
obj.authenticate(sec.tuser, sec.tpass, domain, function (err, userid, passhint, loginOptions) { const client = new duo.Client({
if ((userid != null) && (err == null)) { clientId: domain.duo2factor.integrationkey,
// Login data correct, now exchange authorization code for 2FA clientSecret: domain.duo2factor.secretkey,
const duo = require('@duosecurity/duo_universal'); apiHost: domain.duo2factor.apihostname,
const client = new duo.Client({ redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('?key=' + domain.loginkey) : '')
clientId: domain.duo2factor.integrationkey, });
clientSecret: domain.duo2factor.secretkey, if (sec.duoconfig == 1) {
apiHost: domain.duo2factor.apihostname, // Login data correct, now exchange authorization code for 2FA
redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('?key=' + domain.loginkey) : '') var userid = req.session.userid;
}); client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) {
client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) { // Duo 2FA exchange success
const sec = parent.decryptSessionData(req.session.e); parent.debug('web', 'handleRootRequest: Duo 2FA configuration success.');
if ((sec != null) && (sec.duoconfig == 1)) { // Enable Duo for this user
// Duo 2FA exchange success var user = obj.users[userid];
parent.debug('web', 'handleRootRequest: Duo 2FA configuration success.'); if (user.otpduo == null) {
user.otpduo = {};
// Enable Duo for this user db.SetUser(user);
var user = obj.users[userid]; // Notify change
if (user.otpduo == null) { var targets = ['*', 'server-users', user._id];
user.otpduo = {}; if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
db.SetUser(user); 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 };
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.
// Notify change parent.DispatchEvent(targets, obj, event);
var targets = ['*', 'server-users', user._id]; }
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } } // Clear the Duo state
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 }; delete sec.duostate;
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. delete sec.duoconfig;
parent.DispatchEvent(targets, obj, event); req.session.e = parent.encryptSessionData(sec);
} var url = req.session.duorurl;
delete req.session.duorurl;
// Clear the Duo state res.redirect(url ? url : domain.url); // Redirect back to the user's original page
delete sec.duostate; }).catch(function (err) {
delete sec.duoconfig; const sec = parent.decryptSessionData(req.session.e);
req.session.e = parent.encryptSessionData(sec); // Duo 2FA exchange success
parent.debug('web', 'handleRootRequest: Duo 2FA configuration failed.');
var url = req.session.duorurl; // Clear the Duo state
delete req.session.duorurl; delete sec.duostate;
res.redirect(url ? url : domain.url); // Redirect back to the user's original page delete sec.duoconfig;
} else { req.session.e = parent.encryptSessionData(sec);
var url = req.session.duorurl;
delete req.session.duorurl;
res.redirect(url ? url : domain.url); // Redirect back to the user's original page
});
} else {
// User credentials are stored in session, just check again and get userid
obj.authenticate(sec.tuser, sec.tpass, domain, function (err, userid, passhint, loginOptions) {
if ((userid != null) && (err == null)) {
// Login data correct, now exchange authorization code for 2FA
client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) {
const sec = parent.decryptSessionData(req.session.e);
// Duo 2FA exchange success // Duo 2FA exchange success
parent.debug('web', 'handleRootRequest: Duo 2FA authorization success.'); parent.debug('web', 'handleRootRequest: Duo 2FA authorization success.');
req.session.userid = userid; req.session.userid = userid;
delete req.session.currentNode; delete req.session.currentNode;
req.session.ip = req.clientIp; // Bind this session to the IP address of the request req.session.ip = req.clientIp; // Bind this session to the IP address of the request
setSessionRandom(req); setSessionRandom(req);
// Clear the Duo state and user/pass
// Clear the Duo state
delete sec.duostate; delete sec.duostate;
delete sec.tuser;
delete sec.tpass;
req.session.e = parent.encryptSessionData(sec); req.session.e = parent.encryptSessionData(sec);
obj.parent.authLog('https', 'Accepted Duo authentication for ' + userid + ' from ' + req.clientIp + ':' + req.connection.remotePort, { useragent: req.headers['user-agent'], sessionid: req.session.x }); obj.parent.authLog('https', 'Accepted Duo authentication for ' + userid + ' from ' + req.clientIp + ':' + req.connection.remotePort, { useragent: req.headers['user-agent'], sessionid: req.session.x });
res.redirect(domain.url + getQueryPortion(req)); res.redirect(domain.url + getQueryPortion(req));
} }).catch(function (err) {
}).catch(function (err) { const sec = parent.decryptSessionData(req.session.e);
console.log('err', err);
const sec = parent.decryptSessionData(req.session.e);
if ((sec != null) && (sec.duoconfig == 1)) {
// Duo 2FA exchange success
parent.debug('web', 'handleRootRequest: Duo 2FA configuration failed.');
// Clear the Duo state
delete sec.duostate;
delete sec.duoconfig;
req.session.e = parent.encryptSessionData(sec);
var url = req.session.duorurl;
delete req.session.duorurl;
res.redirect(url ? url : domain.url); // Redirect back to the user's original page
} else {
// Duo 2FA exchange failed // Duo 2FA exchange failed
parent.debug('web', 'handleRootRequest: Duo 2FA authorization failed.'); parent.debug('web', 'handleRootRequest: Duo 2FA authorization failed.');
// Clear the Duo state // Clear the Duo state
delete sec.duostate; delete sec.duostate;
req.session.e = parent.encryptSessionData(sec); req.session.e = parent.encryptSessionData(sec);
req.session.loginmode = 1; req.session.loginmode = 1;
req.session.messageid = 117; // Invalid security check req.session.messageid = 117; // Invalid security check
res.redirect(domain.url + getQueryPortion(req)); res.redirect(domain.url + getQueryPortion(req));
} });
}); } else {
} else { // Login failed
// Login failed parent.debug('web', 'handleRootRequest: login authorization failed when returning from Duo 2FA.');
parent.debug('web', 'handleRootRequest: login authorization failed when returning from Duo 2FA.'); req.session.loginmode = 1;
req.session.loginmode = 1; res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page
res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page return;
return; }
} });
}); }
} }
}); });
// Configure Duo handler // Configure Duo handler
obj.app.get(url + 'add-duo', function (req, res) { obj.app.get(url + 'add-duo', function (req, res) {
var domain = getDomain(req); var domain = getDomain(req);
const sec = parent.decryptSessionData(req.session.e);
if (req.session.userid == null) { if (req.session.userid == null) {
res.sendStatus(404); res.sendStatus(404);
} else { } else {