Commit 47ba3ae4 by Johannes Zellner

Consolidate user verification

1 parent 7af3d855
...@@ -33,12 +33,12 @@ ...@@ -33,12 +33,12 @@
"del": "^2.2.0", "del": "^2.2.0",
"express": "^4.16.2", "express": "^4.16.2",
"express-session": "^1.15.6", "express-session": "^1.15.6",
"ldapjs": "^1.0.2",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"morgan": "^1.9.0", "morgan": "^1.9.0",
"multiparty": "^4.1.2", "multiparty": "^4.1.2",
"passport": "^0.2.2", "passport": "^0.2.2",
"passport-http-bearer": "^1.0.1", "passport-http-bearer": "^1.0.1",
"passport-ldapjs": "^1.0.3",
"readline-sync": "^1.4.9", "readline-sync": "^1.4.9",
"request": "^2.83.0", "request": "^2.83.0",
"safetydance": "^0.1.1", "safetydance": "^0.1.1",
......
...@@ -7,13 +7,22 @@ var passport = require('passport'), ...@@ -7,13 +7,22 @@ var passport = require('passport'),
bcrypt = require('bcryptjs'), bcrypt = require('bcryptjs'),
uuid = require('uuid/v4'), uuid = require('uuid/v4'),
BearerStrategy = require('passport-http-bearer').Strategy, BearerStrategy = require('passport-http-bearer').Strategy,
LdapStrategy = require('passport-ldapjs').Strategy, ldapjs = require('ldapjs'),
HttpError = require('connect-lastmile').HttpError, HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess, HttpSuccess = require('connect-lastmile').HttpSuccess,
webdavErrors = require('webdav-server').v2.Errors; webdavErrors = require('webdav-server').v2.Errors;
const LDAP_URL = process.env.LDAP_URL;
const LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN;
const LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json'); const LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json');
const TOKENSTORE_FILE = path.resolve(process.env.TOKENSTORE_FILE || './.tokens.json'); const TOKENSTORE_FILE = path.resolve(process.env.TOKENSTORE_FILE || './.tokens.json');
const AUTH_METHOD = (LDAP_URL && LDAP_USERS_BASE_DN) ? 'ldap' : 'local';
if (AUTH_METHOD === 'ldap') {
console.log('Use ldap auth');
} else {
console.log(`Use local auth file ${LOCAL_AUTH_FILE}`);
}
var tokenStore = { var tokenStore = {
data: {}, data: {},
...@@ -68,54 +77,62 @@ passport.deserializeUser(function (id, done) { ...@@ -68,54 +77,62 @@ passport.deserializeUser(function (id, done) {
done(null, { uid: id }); done(null, { uid: id });
}); });
var LDAP_URL = process.env.LDAP_URL; function verifyUser(username, password, callback) {
var LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN; if (AUTH_METHOD === 'ldap') {
var ldapClient = ldapjs.createClient({ url: process.env.LDAP_URL });
ldapClient.on('error', function (error) {
console.error('LDAP error', error);
});
ldapClient.bind(process.env.LDAP_BIND_DN, process.env.LDAP_BIND_PASSWORD, function (error) {
if (error) return callback(error);
if (LDAP_URL && LDAP_USERS_BASE_DN) { var filter = `(|(uid=${username})(mail=${username})(username=${username})(sAMAccountName=${username}))`;
console.log('Using ldap auth'); ldapClient.search(process.env.LDAP_USERS_BASE_DN, { filter: filter }, function (error, result) {
if (error) return callback(error);
exports.login = [ passport.authenticate('ldap'), issueAccessToken() ]; var items = [];
} else {
console.log(`Using local user file: ${LOCAL_AUTH_FILE}`);
exports.login = [ result.on('searchEntry', function(entry) { items.push(entry.object); });
function (req, res, next) { result.on('error', callback);
result.on('end', function (result) {
if (result.status !== 0 || items.length === 0) return callback(error);
// pick the first found
var user = items[0];
ldapClient.bind(user.dn, password, function (error) {
if (error) return callback('Invalid credentials');
callback(null, { username: username });
});
});
});
});
} else {
var users = safe.JSON.parse(safe.fs.readFileSync(LOCAL_AUTH_FILE)); var users = safe.JSON.parse(safe.fs.readFileSync(LOCAL_AUTH_FILE));
if (!users) return res.send(401); if (!users || !users[username]) return callback('Invalid credentials');
if (!users[req.body.username]) return res.send(401);
bcrypt.compare(req.body.password, users[req.body.username].passwordHash, function (error, valid) { bcrypt.compare(password, users[username].passwordHash, function (error, valid) {
if (error || !valid) return res.send(401); if (error || !valid) return callback('Invalid credentials');
req.user = { callback(null, { username: username });
username: req.body.username });
}; }
}
exports.login = [
function (req, res, next) {
verifyUser(req.body.username, req.body.password, function (error, user) {
if (error) return next(new HttpError(401, 'Invalid credentials'));
req.user = user;
next(); next();
}); });
}, },
issueAccessToken() issueAccessToken()
]; ];
}
var opts = {
server: {
url: LDAP_URL,
},
base: LDAP_USERS_BASE_DN,
search: {
filter: '(|(username={{username}})(mail={{username}}))',
attributes: ['displayname', 'username', 'mail', 'uid'],
scope: 'sub'
},
uidTag: 'cn',
usernameField: 'username',
passwordField: 'password',
};
passport.use(new LdapStrategy(opts, function (profile, done) {
done(null, profile);
}));
exports.verify = passport.authenticate('bearer', { session: false }); exports.verify = passport.authenticate('bearer', { session: false });
...@@ -162,18 +179,14 @@ WebdavUserManager.prototype.getDefaultUser = function (callback) { ...@@ -162,18 +179,14 @@ WebdavUserManager.prototype.getDefaultUser = function (callback) {
}; };
WebdavUserManager.prototype.getUserByNamePassword = function (username, password, callback) { WebdavUserManager.prototype.getUserByNamePassword = function (username, password, callback) {
var users = safe.JSON.parse(safe.fs.readFileSync(LOCAL_AUTH_FILE)); verifyUser(username, password, function (error, user) {
if (!users) return callback(webdavErrors.UserNotFound); if (error) return callback(webdavErrors.UserNotFound);
if (!users[username]) return callback(webdavErrors.UserNotFound);
bcrypt.compare(password, users[username].passwordHash, function (error, valid) {
if (error || !valid) return callback(webdavErrors.UserNotFound);
callback(null, { callback(null, {
username: username, username: user.username,
isAdministrator: true, isAdministrator: true,
isDefaultUser: false, isDefaultUser: false,
uid: username uid: user.username
}); });
}); });
}; };
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!