Use authInfo obj vs weird params. auth factor 1: factor 2 for 2FA, etc.

This commit is contained in:
Bryan Ashby 2019-02-22 22:51:12 -07:00
parent 57938e761e
commit 23779c3abe
No known key found for this signature in database
GPG Key ID: B49EB437951D2542
4 changed files with 27 additions and 16 deletions

View File

@ -141,7 +141,7 @@ class NNTPServer extends NNTPServerBase {
return new Promise( resolve => { return new Promise( resolve => {
const user = new User(); const user = new User();
user.authenticate(username, password, err => { user.authenticateFactor1({ type : User.AuthFactor1Types.Password, username, password }, err => {
if(err) { if(err) {
// :TODO: Log IP address // :TODO: Log IP address
this.log.debug( { username, reason : err.message }, 'Authentication failure'); this.log.debug( { username, reason : err.message }, 'Authentication failure');

View File

@ -23,7 +23,6 @@ const fs = require('graceful-fs');
const util = require('util'); const util = require('util');
const _ = require('lodash'); const _ = require('lodash');
const assert = require('assert'); const assert = require('assert');
const crypto = require('crypto');
const ModuleInfo = exports.moduleInfo = { const ModuleInfo = exports.moduleInfo = {
name : 'SSH', name : 'SSH',
@ -108,7 +107,7 @@ function SSHClient(clientConn) {
}; };
const authWithPasswordOrPubKey = (authType) => { const authWithPasswordOrPubKey = (authType) => {
if('pubKey' !== authType || !self.user.isAuthenticated() || !ctx.signature) { if(User.AuthFactor1Types.PubKey !== authType || !self.user.isAuthenticated() || !ctx.signature) {
// step 1: login/auth using PubKey // step 1: login/auth using PubKey
userLogin(self, ctx.username, ctx.password, { authType, ctx }, (err) => { userLogin(self, ctx.username, ctx.password, { authType, ctx }, (err) => {
if(err) { if(err) {
@ -188,11 +187,11 @@ function SSHClient(clientConn) {
switch(ctx.method) { switch(ctx.method) {
case 'password' : case 'password' :
return authWithPasswordOrPubKey('password'); return authWithPasswordOrPubKey(User.AuthFactor1Types.Password);
//return authWithPassword(); //return authWithPassword();
case 'publickey' : case 'publickey' :
return authWithPasswordOrPubKey('pubKey'); return authWithPasswordOrPubKey(User.AuthFactor1Types.PubKey);
//return authWithPubKey(); //return authWithPubKey();
case 'keyboard-interactive' : case 'keyboard-interactive' :

View File

@ -178,17 +178,20 @@ module.exports = class User {
}); });
} }
authenticate(username, password, options, cb) { static get AuthFactor1Types() {
if(!cb && _.isFunction(options)) { return {
cb = options; PubKey : 'pubKey',
options = {}; Password : 'password',
} };
}
authenticateFactor1(authInfo, cb) {
const username = authInfo.username;
const self = this; const self = this;
const tempAuthInfo = {}; const tempAuthInfo = {};
const validatePassword = (props, callback) => { const validatePassword = (props, callback) => {
User.generatePasswordDerivedKey(password, props[UserProps.PassPbkdf2Salt], (err, dk) => { User.generatePasswordDerivedKey(authInfo.password, props[UserProps.PassPbkdf2Salt], (err, dk) => {
if(err) { if(err) {
return callback(err); return callback(err);
} }
@ -212,8 +215,8 @@ module.exports = class User {
return callback(Errors.AccessDenied('Invalid public key')); return callback(Errors.AccessDenied('Invalid public key'));
} }
if(options.ctx.key.algo != pubKeyActual.type || if(authInfo.pubKey.key.algo != pubKeyActual.type ||
!crypto.timingSafeEqual(options.ctx.key.data, pubKeyActual.getPublicSSH())) !crypto.timingSafeEqual(authInfo.pubKey.key.data, pubKeyActual.getPublicSSH()))
{ {
return callback(Errors.AccessDenied('Invalid public key')); return callback(Errors.AccessDenied('Invalid public key'));
} }
@ -234,12 +237,12 @@ module.exports = class User {
}, },
function getRequiredAuthProperties(callback) { function getRequiredAuthProperties(callback) {
// fetch properties required for authentication // fetch properties required for authentication
User.loadProperties( tempAuthInfo.userId, { names : User.StandardPropertyGroups.auth }, (err, props) => { User.loadProperties(tempAuthInfo.userId, { names : User.StandardPropertyGroups.auth }, (err, props) => {
return callback(err, props); return callback(err, props);
}); });
}, },
function validatePassOrPubKey(props, callback) { function validatePassOrPubKey(props, callback) {
if('pubKey' === options.authType) { if(User.AuthFactor1Types.PubKey === authInfo.type) {
return validatePubKey(props, callback); return validatePubKey(props, callback);
} }
return validatePassword(props, callback); return validatePassword(props, callback);

View File

@ -15,6 +15,7 @@ const {
const UserProps = require('./user_property.js'); const UserProps = require('./user_property.js');
const SysProps = require('./system_property.js'); const SysProps = require('./system_property.js');
const SystemLogKeys = require('./system_log.js'); const SystemLogKeys = require('./system_log.js');
const User = require('./user.js');
// deps // deps
const async = require('async'); const async = require('async');
@ -39,7 +40,15 @@ function userLogin(client, username, password, options, cb) {
}, 2000); }, 2000);
} }
client.user.authenticate(username, password, options, err => { const authInfo = {
username,
password,
};
authInfo.type = options.authType || User.AuthFactor1Types.Password;
authInfo.pubKey = options.ctx;
client.user.authenticateFactor1(authInfo, err => {
if(err) { if(err) {
client.user.sessionFailedLoginAttempts = _.get(client.user, 'sessionFailedLoginAttempts', 0) + 1; client.user.sessionFailedLoginAttempts = _.get(client.user, 'sessionFailedLoginAttempts', 0) + 1;
const disconnect = config.users.failedLogin.disconnect; const disconnect = config.users.failedLogin.disconnect;