authn.js
'use strict';
const util = require('util');
exports._verify_user = (userdn, passwd, cb, connection) => {
const pool = connection.server.notes.ldappool;
function onError(err) {
connection.logerror(
`Could not verify userdn and password: ${util.inspect(err)}`,
);
cb(false);
}
if (!pool) return onError('LDAP Pool not found');
pool._create_client((err, client) => {
if (err) return onError(err);
client.bind(userdn, passwd, (err2) => {
client.unbind();
if (err2) {
connection.logdebug(
`Login failed, could not bind ${util.inspect(userdn)}: ${util.inspect(err)}`,
);
return cb(false);
}
cb(true);
});
});
};
exports._get_search_conf = (user, connection) => {
const pool = connection.server.notes.ldappool;
const filter = pool.config.authn.searchfilter || '(&(objectclass=*)(uid=%u))';
return {
basedn: pool.config.authn.basedn || pool.config.basedn,
filter: filter.replace(/%u/g, user),
scope: pool.config.authn.scope || pool.config.scope,
attributes: ['dn'],
};
};
exports._get_dn_for_uid = function (uid, callback, connection) {
const pool = connection.server.notes.ldappool;
function onError(err) {
connection.logerror(`Could not get DN for UID ${uid}`);
connection.logdebug(`: ${util.inspect(err)}`);
callback(err);
}
if (!pool) return onError('LDAP Pool not found!');
pool.get((err, client) => {
if (err) return onError(err);
const config = this._get_search_conf(uid, connection);
connection.logdebug(`Getting DN for uid: ${util.inspect(config)}`);
try {
client.search(config.basedn, config, (search_error, res) => {
if (search_error) onError(search_error);
const userdn = [];
res.on('searchEntry', (entry) => {
userdn.push(entry.object.dn);
});
res.on('error', onError);
res.on('end', () => {
callback(null, userdn);
});
});
} catch (e) {
onError(e);
}
});
};
exports.check_plain_passwd = function (connection, user, passwd, cb) {
if (Array.isArray(connection.server.notes.ldappool.config.authn.dn)) {
return this.check_plain_passwd_dn(connection, user, passwd, cb);
}
connection.logdebug(`Looking up user ${util.inspect(user)} by search.`);
this._get_dn_for_uid(
user,
(err, userdn) => {
if (err) {
connection.logerror(
`Could not use LDAP for password check: ${util.inspect(err)}`,
);
cb(false);
} else if (userdn.length !== 1) {
connection.logdebug(
`None or nonunique LDAP search result for user ${util.inspect(user)}, access denied`,
);
cb(false);
} else {
this._verify_user(userdn[0], passwd, cb, connection);
}
},
connection,
);
};
exports.check_plain_passwd_dn = function (connection, user, passwd, cb) {
connection.logdebug(`Looking up user ${util.inspect(user)} by DN.`);
let iter = 0;
let cbCalled = false;
function cbOnce(result) {
iter++;
if (cbCalled) return;
if (result) {
cbCalled = true;
return cb(result);
}
if (iter === connection.server.notes.ldappool.config.authn.dn.length) {
cbCalled = true;
cb(result);
}
}
for (const dn of connection.server.notes.ldappool.config.authn.dn) {
this._verify_user(dn.replace(/%u/g, user), passwd, cbOnce, connection);
}
};