From 1571ce03f0e2cb0e7929e7f1ba9a73a162b8dda4 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Wed, 18 May 2022 18:01:34 -0700 Subject: [PATCH] Added userRequiredHttpHeader support in domain section of the config.json, #4011 --- meshcentral-config-schema.json | 1 + webserver.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index 73800a8e..6ed9dd03 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -561,6 +561,7 @@ } }, "ipBlockedUserRedirect" : { "type": "string", "default": null, "description": "If set, a user from a banned IP address will be redirected to this URL." }, + "userRequiredHttpHeader": { "type": "object", "default": null, "description": "When set, requires that a browser request have set HTTP header to allow user login. Example: \"{ \"Sec-Fetch-Dest\": \"iframe\" }\"" }, "userAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, "userBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, "agentAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, diff --git a/webserver.js b/webserver.js index a3c79bf6..6f606135 100644 --- a/webserver.js +++ b/webserver.js @@ -764,6 +764,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (domain.auth == 'sspi') { parent.debug('web', 'handleLogoutRequest: failed checks.'); res.sendStatus(404); return; } if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key + // If a HTTP header is required, check new UserRequiredHttpHeader + if (domain.userrequiredhttpheader && (typeof domain.userrequiredhttpheader == 'object')) { var ok = false; for (var i in req.headers) { if (domain.userrequiredhttpheader[i.toLowerCase()] == req.headers[i]) { ok = true; } } if (ok == false) { res.sendStatus(404); return; } } + res.set({ 'Cache-Control': 'no-store' }); // Destroy the user's session to log them out will be re-created next request var userid = req.session.userid; @@ -2547,6 +2550,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key if (!obj.args) { parent.debug('web', 'handleRootRequest: no obj.args.'); res.sendStatus(500); return; } + // If a HTTP header is required, check new UserRequiredHttpHeader + if (domain.userrequiredhttpheader && (typeof domain.userrequiredhttpheader == 'object')) { var ok = false; for (var i in req.headers) { if (domain.userrequiredhttpheader[i.toLowerCase()] == req.headers[i]) { ok = true; } } if (ok == false) { res.sendStatus(404); return; } } + // If the session is expired, clear it. if ((req.session != null) && (typeof req.session.expire == 'number') && ((req.session.expire - Date.now()) <= 0)) { for (var i in req.session) { delete req.session[i]; } } @@ -3074,6 +3080,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.end("Not Found"); return; } // Check 3FA URL key parent.debug('web', 'handleRootPostRequest, action: ' + req.body.action); + // If a HTTP header is required, check new UserRequiredHttpHeader + if (domain.userrequiredhttpheader && (typeof domain.userrequiredhttpheader == 'object')) { var ok = false; for (var i in req.headers) { if (domain.userrequiredhttpheader[i.toLowerCase()] == req.headers[i]) { ok = true; } } if (ok == false) { res.sendStatus(404); return; } } + switch (req.body.action) { case 'login': { handleLoginRequest(req, res, true); break; } case 'tokenlogin': {