1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-03-09 15:40:18 +00:00

Added user account, user session and agent session per-domain limits.

This commit is contained in:
Ylian Saint-Hilaire 2019-02-11 14:41:15 -08:00
parent a932a66044
commit a0edd68ac4
11 changed files with 212 additions and 29 deletions

View file

@ -320,7 +320,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Return true if this user has 2-step auth active
function checkUserOneTimePasswordRequired(domain, user) {
return (user.otpsecret) || (user.otphkeys && (user.otphkeys.length > 0));
return ((user.otpsecret != null) || ((user.otphkeys != null) && (user.otphkeys.length > 0)));
}
// Check the 2-step auth token
@ -377,7 +377,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
}
// Return a U2F hardware key challenge
// TODO: Figure out how to support many U2F keys at the same time.
function getHardwareKeyChallenge(req, domain, user, func) {
if (req.session.u2fchallenge) { delete req.session.u2fchallenge; };
if (user.otphkeys && (user.otphkeys.length > 0)) {
@ -419,7 +418,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
var user = obj.users[userid];
// Check if this user has 2-step login active
if (checkUserOneTimePasswordRequired(req.domain, user)) {
if (checkUserOneTimePasswordRequired(domain, user)) {
checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
if (result == false) {
// 2-step auth is required, but the token is not present or not valid.
@ -427,7 +426,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
req.session.loginmode = '4';
req.session.tokenusername = xusername;
req.session.tokenpassword = xpassword;
req.session.tokenRetry = true;
res.redirect(domain.url);
} else {
// Login succesful
@ -465,6 +463,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
delete req.session.loginmode;
delete req.session.tokenusername;
delete req.session.tokenpassword;
delete req.session.tokenemail;
delete req.session.success;
delete req.session.error;
delete req.session.passhint;
@ -503,7 +502,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if ((domain.newaccounts === 0) || (domain.newaccounts === false)) { res.sendStatus(401); return; }
// Check if we exceed the maximum number of user accounts
obj.db.isMaxType(domain.maxaccounts, 'user', function (maxExceed) {
obj.db.isMaxType(domain.limits.maxuseraccounts, 'user', domain.id, function (maxExceed) {
if (maxExceed) {
req.session.loginmode = 2;
req.session.error = '<b style=color:#8C001A>Account limit reached.</b>';
@ -569,28 +568,58 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
const domain = checkUserIpAddress(req, res);
if ((domain == null) || (domain.auth == 'sspi')) return;
var email = req.body.email;
if ((email == null) || (email == '')) { email = req.session.tokenemail; }
if ((domain.newaccounts === 0) || (domain.newaccounts === false)) { res.sendStatus(401); return; }
if (!req.body.email || checkEmail(req.body.email) == false) {
if (!email || checkEmail(email) == false) {
req.session.loginmode = 3;
req.session.error = '<b style=color:#8C001A>Invalid email.</b>';
res.redirect(domain.url);
} else {
obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
if (docs.length == 0) {
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
if ((err != null) || (docs.length == 0)) {
req.session.loginmode = 3;
req.session.error = '<b style=color:#8C001A>Account not found.</b>';
res.redirect(domain.url);
} else {
var userFound = docs[0];
if (obj.parent.mailserver != null) {
obj.parent.mailserver.sendAccountResetMail(domain, userFound.name, userFound.email);
req.session.loginmode = 1;
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
res.redirect(domain.url);
var user = docs[0];
if (checkUserOneTimePasswordRequired(domain, user) == true) {
// Second factor setup, request it now.
checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
if (result == false) {
// 2-step auth is required, but the token is not present or not valid.
if ((req.body.token != null) || (req.body.hwtoken != null)) { req.session.error = '<b style=color:#8C001A>Invalid token, try again.</b>'; }
req.session.loginmode = '5';
req.session.tokenemail = email;
res.redirect(domain.url);
} else {
// Send email to perform recovery.
delete req.session.tokenemail;
if (obj.parent.mailserver != null) {
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email);
req.session.loginmode = 1;
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
res.redirect(domain.url);
} else {
req.session.loginmode = 3;
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
res.redirect(domain.url);
}
}
});
} else {
req.session.loginmode = 3;
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
res.redirect(domain.url);
// No second factor, send email to perform recovery.
if (obj.parent.mailserver != null) {
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email);
req.session.loginmode = 1;
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
res.redirect(domain.url);
} else {
req.session.loginmode = 3;
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
res.redirect(domain.url);
}
}
}
});
@ -632,7 +661,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.db.SetUser(user);
// Event the change
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(userinfo.email) + ')', domain: domain.id });
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(user.email) + ')', domain: domain.id });
// Send the confirmation page
res.render(obj.path.join(obj.parent.webViewsPath, 'message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
@ -660,7 +689,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
userinfo.hash = hash;
userinfo.passchange = Math.floor(Date.now() / 1000);
userinfo.passhint = null;
delete userinfo.otpsecret; // Currently a email password reset will turn off 2-step login.
//delete userinfo.otpsecret; // Currently a email password reset will turn off 2-step login.
obj.db.SetUser(userinfo);
// Event the change
@ -920,6 +949,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
} else {
// Send back the login application
// If this is a 2 factor auth request, look for a hardware key challenge.
// Normal login 2 factor request
if ((req.session.loginmode == '4') && (req.session.tokenusername)) {
var user = obj.users['user/' + domain.id + '/' + req.session.tokenusername];
if (user != null) {
@ -927,6 +957,24 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
return;
}
}
// Password recovery 2 factor request
if ((req.session.loginmode == '5') && (req.session.tokenemail)) {
obj.db.GetUserWithVerifiedEmail(domain.id, req.session.tokenemail, function (err, docs) {
if ((err != null) || (docs.length == 0)) {
req.session = null;
res.redirect(domain.url);
} else {
var user = obj.users[docs[0]._id];
if (user != null) {
getHardwareKeyChallenge(req, domain, user, function (u2fChallenge) { handleRootRequestLogin(req, res, domain, u2fChallenge, passRequirements); });
} else {
req.session = null;
res.redirect(domain.url);
}
}
});
return;
}
handleRootRequestLogin(req, res, domain, '', passRequirements);
}
}