WIP on OTP 2FA, stats, etc.
This commit is contained in:
parent
e960e2800d
commit
e5398db07b
|
@ -51,4 +51,5 @@ exports.ErrorReasons = {
|
||||||
Inactive : 'INACTIVE',
|
Inactive : 'INACTIVE',
|
||||||
Locked : 'LOCKED',
|
Locked : 'LOCKED',
|
||||||
NotAllowed : 'NOTALLOWED',
|
NotAllowed : 'NOTALLOWED',
|
||||||
|
Invalid2FA : 'INVALID2FA',
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,9 @@ const User = require('./user.js');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
exports.userLogin = userLogin;
|
exports.userLogin = userLogin;
|
||||||
|
exports.recordLogin = recordLogin;
|
||||||
|
exports.transformLoginError = transformLoginError;
|
||||||
|
|
||||||
function userLogin(client, username, password, options, cb) {
|
function userLogin(client, username, password, options, cb) {
|
||||||
if(!cb && _.isFunction(options)) {
|
if(!cb && _.isFunction(options)) {
|
||||||
|
@ -50,20 +52,13 @@ function userLogin(client, username, password, options, cb) {
|
||||||
|
|
||||||
client.user.authenticateFactor1(authInfo, err => {
|
client.user.authenticateFactor1(authInfo, err => {
|
||||||
if(err) {
|
if(err) {
|
||||||
client.user.sessionFailedLoginAttempts = _.get(client.user, 'sessionFailedLoginAttempts', 0) + 1;
|
return cb(transformLoginError(err, client, username));
|
||||||
const disconnect = config.users.failedLogin.disconnect;
|
|
||||||
if(disconnect > 0 && client.user.sessionFailedLoginAttempts >= disconnect) {
|
|
||||||
err = Errors.BadLogin('To many failed login attempts', ErrorReasons.TooMany);
|
|
||||||
}
|
|
||||||
|
|
||||||
client.log.info( { username, ip : client.remoteAddress, reason : err.message }, 'Failed login attempt');
|
|
||||||
return cb(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = client.user;
|
const user = client.user;
|
||||||
|
|
||||||
// Good login; reset any failed attempts
|
// Good login; reset any failed attempts
|
||||||
delete user.sessionFailedLoginAttempts;
|
delete client.sessionFailedLoginAttempts;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ensure this user is not already logged in.
|
// Ensure this user is not already logged in.
|
||||||
|
@ -104,41 +99,59 @@ function userLogin(client, username, password, options, cb) {
|
||||||
|
|
||||||
Events.emit(Events.getSystemEvents().UserLogin, { user } );
|
Events.emit(Events.getSystemEvents().UserLogin, { user } );
|
||||||
|
|
||||||
async.parallel(
|
setClientTheme(client, user.properties[UserProps.ThemeId]);
|
||||||
[
|
if(user.authenticated) {
|
||||||
function setTheme(callback) {
|
return recordLogin(client, cb);
|
||||||
setClientTheme(client, user.properties[UserProps.ThemeId]);
|
}
|
||||||
return callback(null);
|
|
||||||
},
|
|
||||||
function updateSystemLoginCount(callback) {
|
|
||||||
StatLog.incrementNonPersistentSystemStat(SysProps.LoginsToday, 1);
|
|
||||||
return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback);
|
|
||||||
},
|
|
||||||
function recordLastLogin(callback) {
|
|
||||||
return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
|
|
||||||
},
|
|
||||||
function updateUserLoginCount(callback) {
|
|
||||||
return StatLog.incrementUserStat(user, UserProps.LoginCount, 1, callback);
|
|
||||||
},
|
|
||||||
function recordLoginHistory(callback) {
|
|
||||||
const loginHistoryMax = Config().statLog.systemEvents.loginHistoryMax;
|
|
||||||
const historyItem = JSON.stringify({
|
|
||||||
userId : user.userId,
|
|
||||||
sessionId : user.sessionId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return StatLog.appendSystemLogEntry(
|
// recordLogin() must happen after 2FA!
|
||||||
SystemLogKeys.UserLoginHistory,
|
return cb(null);
|
||||||
historyItem,
|
|
||||||
loginHistoryMax,
|
|
||||||
StatLog.KeepType.Max,
|
|
||||||
callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
],
|
|
||||||
err => {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function recordLogin(client, cb) {
|
||||||
|
const user = client.user;
|
||||||
|
async.parallel(
|
||||||
|
[
|
||||||
|
(callback) => {
|
||||||
|
StatLog.incrementNonPersistentSystemStat(SysProps.LoginsToday, 1);
|
||||||
|
return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback);
|
||||||
|
},
|
||||||
|
(callback) => {
|
||||||
|
return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
|
||||||
|
},
|
||||||
|
(callback) => {
|
||||||
|
return StatLog.incrementUserStat(user, UserProps.LoginCount, 1, callback);
|
||||||
|
},
|
||||||
|
(callback) => {
|
||||||
|
const loginHistoryMax = Config().statLog.systemEvents.loginHistoryMax;
|
||||||
|
const historyItem = JSON.stringify({
|
||||||
|
userId : user.userId,
|
||||||
|
sessionId : user.sessionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return StatLog.appendSystemLogEntry(
|
||||||
|
SystemLogKeys.UserLoginHistory,
|
||||||
|
historyItem,
|
||||||
|
loginHistoryMax,
|
||||||
|
StatLog.KeepType.Max,
|
||||||
|
callback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformLoginError(err, client, username) {
|
||||||
|
client.sessionFailedLoginAttempts = _.get(client, 'sessionFailedLoginAttempts', 0) + 1;
|
||||||
|
const disconnect = Config().users.failedLogin.disconnect;
|
||||||
|
if(disconnect > 0 && client.sessionFailedLoginAttempts >= disconnect) {
|
||||||
|
err = Errors.BadLogin('To many failed login attempts', ErrorReasons.TooMany);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.log.info( { username, ip : client.remoteAddress, reason : err.message }, 'Failed login attempt');
|
||||||
|
return err;
|
||||||
|
}
|
Loading…
Reference in New Issue