Added 3FA using LoginKey in domain section of config.json, add &key= to URL.
Ylian Saint-Hilaire committed
Nov 21, 2019 at 18:57 UTC
d4af4ec441e88368ea8737383646ca2d143a1903
2 files changed
+45
-46
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.4.4-p",
3
+ "version": "0.4.4-r",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
webserver.js
+44
-45
@@ -496,11 +496,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
496
497
function handleLogoutRequest(req, res) {
498
const domain = checkUserIpAddress(req, res);
499
- if ((domain == null) || (domain.auth == 'sspi')) {
500
- parent.debug('web', 'handleLogoutRequest: failed checks.');
501
- res.sendStatus(404);
502
- return;
503
- }
499
+ if ((domain == null) || (domain.auth == 'sspi')) { parent.debug('web', 'handleLogoutRequest: failed checks.'); res.sendStatus(404); return; }
500
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
501
502
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
503
// Destroy the user's session to log them out will be re-created next request
@@ -509,7 +506,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
506
if (user != null) { obj.parent.DispatchEvent(['*'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id }); }
507
}
508
req.session = null;
512
- res.redirect(domain.url);
509
+ if (req.query.key != null) { res.redirect(domain.url + "?key=" + req.query.key); } else { res.redirect(domain.url); }
510
parent.debug('web', 'handleLogoutRequest: success.');
511
}
512
@@ -638,6 +635,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
635
function handleLoginRequest(req, res, direct) {
636
const domain = checkUserIpAddress(req, res);
637
if (domain == null) { parent.debug('web', 'handleLoginRequest: invalid domain'); res.sendStatus(404); return; }
638
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
639
640
// Check if this is a banned ip address
641
if (obj.checkAllowLogin(req) == false) {
@@ -790,11 +788,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
788
789
function handleCreateAccountRequest(req, res, direct) {
790
const domain = checkUserIpAddress(req, res);
793
- if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
794
- parent.debug('web', 'handleCreateAccountRequest: failed checks.');
795
- res.sendStatus(404);
796
- return;
797
- }
791
+ if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleCreateAccountRequest: failed checks.'); res.sendStatus(404); return; }
792
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
793
794
// Always lowercase the email address
795
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
@@ -905,6 +900,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
900
// Called to process an account password reset
901
function handleResetPasswordRequest(req, res, direct) {
902
const domain = checkUserIpAddress(req, res);
903
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
904
905
// Check everything is ok
906
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
@@ -987,11 +983,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
983
// Called to process an account reset request
984
function handleResetAccountRequest(req, res, direct) {
985
const domain = checkUserIpAddress(req, res);
990
- if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) {
991
- parent.debug('web', 'handleResetAccountRequest: check failed');
992
- res.sendStatus(404);
993
- return;
994
- }
986
+ if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) { parent.debug('web', 'handleResetAccountRequest: check failed'); res.sendStatus(404); return; }
987
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
988
989
// Always lowercase the email address
990
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
@@ -1083,11 +1076,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1076
// Called to process a web based email verification request
1077
function handleCheckMailRequest(req, res) {
1078
const domain = checkUserIpAddress(req, res);
1086
- if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
1087
- parent.debug('web', 'handleCheckMailRequest: failed checks.');
1088
- res.sendStatus(404);
1089
- return;
1090
- }
1079
+ if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleCheckMailRequest: failed checks.'); res.sendStatus(404); return; }
1080
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1081
1082
if (req.query.c != null) {
1083
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
@@ -1188,11 +1178,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1178
// Called to process an agent invite request
1179
function handleAgentInviteRequest(req, res) {
1180
const domain = getDomain(req);
1191
- if ((domain == null) || ((req.query.m == null) && (req.query.c == null))) {
1192
- parent.debug('web', 'handleAgentInviteRequest: failed checks.');
1193
- res.sendStatus(404);
1194
- return;
1195
- }
1181
+ if ((domain == null) || ((req.query.m == null) && (req.query.c == null))) { parent.debug('web', 'handleAgentInviteRequest: failed checks.'); res.sendStatus(404); return; }
1182
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1183
+
1184
if (req.query.c != null) {
1185
// A cookie is specified in the query string, use that
1186
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.invitationLinkEncryptionKey);
@@ -1218,11 +1206,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1206
function handleDeleteAccountRequest(req, res, direct) {
1207
parent.debug('web', 'handleDeleteAccountRequest()');
1208
const domain = checkUserIpAddress(req, res);
1221
- if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
1222
- parent.debug('web', 'handleDeleteAccountRequest: failed checks.');
1223
- res.sendStatus(404);
1224
- return;
1225
- }
1209
+ if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleDeleteAccountRequest: failed checks.'); res.sendStatus(404); return; }
1210
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1211
1212
var user = null;
1213
if (req.body.authcookie) {
@@ -1308,11 +1293,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1293
// Handle password changes
1294
function handlePasswordChangeRequest(req, res, direct) {
1295
const domain = checkUserIpAddress(req, res);
1311
- if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
1312
- parent.debug('web', 'handlePasswordChangeRequest: failed checks (1).');
1313
- res.sendStatus(404);
1314
- return;
1315
- }
1296
+ if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handlePasswordChangeRequest: failed checks (1).'); res.sendStatus(404); return; }
1297
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1298
1299
// Check if the user is logged and we have all required parameters
1300
if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) {
@@ -1353,6 +1335,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1335
function handleRootRequest(req, res, direct) {
1336
const domain = checkUserIpAddress(req, res);
1337
if (domain == null) { parent.debug('web', 'handleRootRequest: invalid domain.'); res.sendStatus(404); return; }
1338
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1339
if (!obj.args) { parent.debug('web', 'handleRootRequest: no obj.args.'); res.sendStatus(500); return; }
1340
1341
if ((domain.sspi != null) && ((req.query.login == null) || (obj.parent.loginCookieEncryptionKey == null))) {
@@ -1539,7 +1522,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1522
const authRelayCookie = obj.parent.encodeCookie({ ruserid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
1523
1524
// Send the master web application
1542
- if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1525
+ var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1526
+ if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1527
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1528
1529
// Clean up the U2F challenge if needed
@@ -1621,7 +1605,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1605
1606
// Handle a post request on the root
1607
function handleRootPostRequest(req, res) {
1608
+ const domain = checkUserIpAddress(req, res);
1609
+ if (domain == null) { parent.debug('web', 'handleTermsRequest: Bad domain'); res.sendStatus(404); return; }
1610
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1611
parent.debug('web', 'handleRootPostRequest, action: ' + req.body.action);
1612
+
1613
switch (req.body.action) {
1614
case 'login': { handleLoginRequest(req, res, true); break; }
1615
case 'tokenlogin': {
@@ -1662,11 +1650,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1650
// Render the terms of service.
1651
function handleTermsRequest(req, res) {
1652
const domain = checkUserIpAddress(req, res);
1665
- if (domain == null) {
1666
- parent.debug('web', 'handleTermsRequest: Bad domain');
1667
- res.sendStatus(404);
1668
- return;
1669
- }
1653
+ if (domain == null) { parent.debug('web', 'handleTermsRequest: Bad domain'); res.sendStatus(404); return; }
1654
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1655
1656
// See if term.txt was loaded from the database
1657
if ((parent.configurationFiles != null) && (parent.configurationFiles['terms.txt'] != null)) {
@@ -1676,7 +1661,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1661
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
1662
var user = obj.users[req.session.userid];
1663
var logoutcontrol = 'Welcome ' + user.name + '.';
1679
- if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1664
+ var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1665
+ if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1666
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()), logoutControl: logoutcontrol });
1667
} else {
1668
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()) });
@@ -1694,7 +1680,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1680
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
1681
var user = obj.users[req.session.userid];
1682
var logoutcontrol = 'Welcome ' + user.name + '.';
1697
- if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1683
+ var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1684
+ if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1685
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data), logoutControl: logoutcontrol });
1686
} else {
1687
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data) });
@@ -1708,7 +1695,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1695
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
1696
var user = obj.users[req.session.userid];
1697
var logoutcontrol = 'Welcome ' + user.name + '.';
1711
- if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1698
+ var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1699
+ if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1700
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, logoutControl: logoutcontrol });
1701
} else {
1702
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url });
@@ -1741,6 +1729,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1729
1730
// Returns the mesh server root certificate
1731
function handleRootCertRequest(req, res) {
1732
+ const domain = getDomain(req);
1733
+ if (domain == null) { parent.debug('web', 'handleRootCertRequest: no domain'); res.sendStatus(404); return; }
1734
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1735
if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { parent.debug('web', 'handleRootCertRequest: invalid ip'); return; } // Check server-wide IP filter only.
1736
parent.debug('web', 'handleRootCertRequest()');
1737
try {
@@ -1835,6 +1826,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1826
1827
// Returns an mescript for Intel AMT configuration
1828
function handleMeScriptRequest(req, res) {
1829
+ const domain = getDomain(req);
1830
+ if (domain == null) { parent.debug('web', 'handleMeScriptRequest: no domain'); res.sendStatus(404); return; }
1831
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1832
+
1833
if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { return; } // Check server-wide IP filter only.
1834
if (req.query.type == 1) {
1835
obj.getCiraConfigurationScript(req.query.meshid, function (script) {
@@ -1862,6 +1857,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1857
function handleDownloadUserFiles(req, res) {
1858
const domain = checkUserIpAddress(req, res);
1859
if (domain == null) { res.sendStatus(404); return; }
1860
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
1861
+
1862
if (obj.common.validateString(req.path, 1, 4096) == false) { res.sendStatus(404); return; }
1863
var domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = '';
1864
if ((spliturl.length < 3) || (obj.common.IsFilenameValid(spliturl[2]) == false) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
@@ -2815,6 +2812,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2812
function handleBackupRequest(req, res) {
2813
const domain = checkUserIpAddress(req, res);
2814
if (domain == null) { res.sendStatus(404); return; }
2815
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
2816
if ((!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
2817
var user = obj.users[req.session.userid];
2818
if ((user == null) || ((user.siteadmin & 1) == 0)) { res.sendStatus(401); return; } // Check if we have server backup rights
@@ -2847,6 +2845,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2845
function handleRestoreRequest(req, res) {
2846
const domain = checkUserIpAddress(req, res);
2847
if (domain == null) { res.sendStatus(404); return; }
2848
+ if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
2849
if (obj.parent.args.noserverbackup == 1) { res.sendStatus(401); return; }
2850
var authUserid = null;
2851
if ((req.session != null) && (typeof req.session.userid == 'string')) { authUserid = req.session.userid; }