Added failed login logging and reporting.

This commit is contained in:
Ylian Saint-Hilaire 2019-11-17 16:20:53 -08:00
parent bcef76863e
commit 32eb3fe72b
4 changed files with 18 additions and 1 deletions

2
db.js
View File

@ -693,6 +693,7 @@ module.exports.CreateDB = function (parent, func) {
obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); };
obj.RemoveAllEvents = function (domain) { obj.eventsfile.deleteMany({ domain: domain }, { multi: true }); };
obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.deleteMany({ domain: domain, nodeid: nodeid }, { multi: true }); };
obj.GetFailedLoginCount = function (username, domainid, lastlogin, func) { obj.eventsfile.count({ action: 'authfail', username: username, domain: domainid, time: { "$gte": lastlogin } }, function (err, count) { func((err == null)?count:0); }); }
// Database actions on the power collection
obj.getAllPower = function (func) { obj.powerfile.find({}).toArray(func); };
@ -825,6 +826,7 @@ module.exports.CreateDB = function (parent, func) {
obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } };
obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); };
obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); };
obj.GetFailedLoginCount = function (username, domainid, lastlogin, func) { obj.eventsfile.count({ action: 'authfail', username: username, domain: domainid, time: { "$gte": lastlogin } }, function (err, count) { func((err == null) ? count : 0); }); }
// Database actions on the power collection
obj.getAllPower = function (func) { obj.powerfile.find({}, func); };

View File

@ -360,6 +360,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { }
}
// See how many times bad login attempts where made since the last login
const lastLoginTime = parent.users[user._id].pastlogin;
if (lastLoginTime != null) {
db.GetFailedLoginCount(user.name, user.domain, new Date(lastLoginTime * 1000), function (count) {
if (count > 0) { try { ws.send(JSON.stringify({ action: 'msg', type: 'notify', title: "Security Warning", tag: 'ServerNotify', value: "There has been " + count + " failed login attempts on this account since the last login." })); } catch (ex) { } delete user.pastlogin; }
});
}
// We are all set, start receiving data
ws._socket.resume();
});

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.4.4-i",
"version": "0.4.4-j",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -659,6 +659,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
randomWaitTime = 2000 + (obj.crypto.randomBytes(2).readUInt16BE(0) % 4095); // This is a fail, wait a random time. 2 to 6 seconds.
req.session.messageid = 108; // Invalid token, try again.
parent.debug('web', 'handleLoginRequest: invalid 2FA token');
obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + cleanRemoteAddr(req.ip) });
} else {
parent.debug('web', 'handleLoginRequest: 2FA token required');
}
@ -686,12 +687,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Login failed, wait a random delay
setTimeout(function () {
// If the account is locked, display that.
var xuserid = 'user/' + domain.id + '/' + xusername.toLowerCase();
if (err == 'locked') {
parent.debug('web', 'handleLoginRequest: login failed, locked account');
req.session.messageid = 110; // Account locked.
obj.parent.DispatchEvent(['*', 'server-users', xuserid], obj, { action: 'authfail', userid: xuserid, username: xusername, domain: domain.id, msg: 'User login attempt on locked account from ' + cleanRemoteAddr(req.ip) });
} else {
parent.debug('web', 'handleLoginRequest: login failed, bad username and password');
req.session.messageid = 112; // Login failed, check username and password.
obj.parent.DispatchEvent(['*', 'server-users', xuserid], obj, { action: 'authfail', userid: xuserid, username: xusername, domain: domain.id, msg: 'Invalid user login attempt from ' + cleanRemoteAddr(req.ip) });
}
// Clean up login mode and display password hint if present.
@ -722,6 +726,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
}
// Save login time
user.pastlogin = user.login;
user.login = Math.floor(Date.now() / 1000);
obj.db.SetUser(user);
@ -1007,6 +1012,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
parent.debug('web', 'handleResetAccountRequest: Invalid 2FA token, try again');
if ((req.body.token != null) || (req.body.hwtoken != null)) {
req.session.messageid = 108; // Invalid token, try again.
obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + cleanRemoteAddr(req.ip) });
}
req.session.loginmode = '5';
req.session.tokenemail = email;
@ -3467,6 +3473,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
} else {
// If not authenticated, close the websocket connection
parent.debug('web', 'ERR: Websocket bad user/pass auth');
//obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + obj.args.user.toLowerCase()], obj, { action: 'authfail', userid: 'user/' + domain.id + '/' + obj.args.user.toLowerCase(), username: obj.args.user, domain: domain.id, msg: 'Invalid user login attempt from ' + cleanRemoteAddr(req.ip) });
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
}
}