hardlounge/src/plugins/auth/ldap.js

154 lines
3.6 KiB
JavaScript
Raw Normal View History

"use strict";
2018-06-15 20:31:06 +00:00
const log = require("../../log");
const Helper = require("../../helper");
// Forked ldapjs for 2 reasons:
// 1. Removed bunyan https://github.com/joyent/node-ldapjs/pull/399
// 2. Remove dtrace-provider dependency
const ldap = require("thelounge-ldapjs-non-maintained-fork");
2017-08-30 09:49:21 +00:00
function ldapAuthCommon(user, bindDN, password, callback) {
2017-08-29 17:11:06 +00:00
const config = Helper.config;
const ldapclient = ldap.createClient({
url: config.ldap.url,
tlsOptions: config.ldap.tlsOptions,
2017-08-29 17:11:06 +00:00
});
ldapclient.on("error", function(err) {
2017-09-01 09:29:52 +00:00
log.error(`Unable to connect to LDAP server: ${err}`);
2018-12-12 20:33:30 +00:00
callback(false);
2017-08-29 17:11:06 +00:00
});
ldapclient.bind(bindDN, password, function(err) {
ldapclient.unbind();
2018-12-12 20:33:30 +00:00
if (err) {
log.error(`LDAP bind failed: ${err}`);
callback(false);
} else {
callback(true);
}
2017-08-29 17:11:06 +00:00
});
}
2017-08-30 09:49:21 +00:00
function simpleLdapAuth(user, password, callback) {
if (!user || !password) {
return callback(false);
}
const config = Helper.config;
const userDN = user.replace(/([,\\/#+<>;"= ])/g, "\\$1");
2017-09-01 09:29:52 +00:00
const bindDN = `${config.ldap.primaryKey}=${userDN},${config.ldap.baseDN}`;
2017-09-01 09:29:52 +00:00
log.info(`Auth against LDAP ${config.ldap.url} with provided bindDN ${bindDN}`);
2017-08-30 09:49:21 +00:00
ldapAuthCommon(user, bindDN, password, callback);
2017-08-29 17:11:06 +00:00
}
/**
* LDAP auth using initial DN search (see config comment for ldap.searchDN)
*/
2017-08-30 09:49:21 +00:00
function advancedLdapAuth(user, password, callback) {
if (!user || !password) {
2017-08-29 17:11:06 +00:00
return callback(false);
}
const config = Helper.config;
const userDN = user.replace(/([,\\/#+<>;"= ])/g, "\\$1");
const ldapclient = ldap.createClient({
url: config.ldap.url,
tlsOptions: config.ldap.tlsOptions,
2017-08-29 17:11:06 +00:00
});
const base = config.ldap.searchDN.base;
const searchOptions = {
scope: config.ldap.searchDN.scope,
2017-09-01 09:29:52 +00:00
filter: `(&(${config.ldap.primaryKey}=${userDN})${config.ldap.searchDN.filter})`,
attributes: ["dn"],
2017-08-29 17:11:06 +00:00
};
ldapclient.on("error", function(err) {
2017-09-01 09:29:52 +00:00
log.error(`Unable to connect to LDAP server: ${err}`);
2018-12-12 20:33:30 +00:00
callback(false);
2017-08-29 17:11:06 +00:00
});
ldapclient.bind(config.ldap.searchDN.rootDN, config.ldap.searchDN.rootPassword, function(err) {
if (err) {
log.error("Invalid LDAP root credentials");
ldapclient.unbind();
callback(false);
} else {
ldapclient.search(base, searchOptions, function(err2, res) {
if (err2) {
2018-12-12 20:33:30 +00:00
log.warn(`LDAP User not found: ${userDN}`);
2017-08-29 17:11:06 +00:00
ldapclient.unbind();
callback(false);
} else {
let found = false;
res.on("searchEntry", function(entry) {
found = true;
const bindDN = entry.objectName;
2019-07-17 09:33:59 +00:00
log.info(
`Auth against LDAP ${config.ldap.url} with found bindDN ${bindDN}`
);
2017-08-29 17:11:06 +00:00
ldapclient.unbind();
2017-08-30 09:49:21 +00:00
ldapAuthCommon(user, bindDN, password, callback);
2017-08-29 17:11:06 +00:00
});
res.on("error", function(err3) {
2017-09-01 09:29:52 +00:00
log.error(`LDAP error: ${err3}`);
2017-08-29 17:11:06 +00:00
callback(false);
});
2018-12-12 20:33:30 +00:00
res.on("end", function(result) {
2017-10-06 09:53:08 +00:00
ldapclient.unbind();
2017-08-29 17:11:06 +00:00
if (!found) {
2019-07-17 09:33:59 +00:00
log.warn(
`LDAP Search did not find anything for: ${userDN} (${result.status})`
);
2017-08-29 17:11:06 +00:00
callback(false);
}
});
}
});
}
});
}
function ldapAuth(manager, client, user, password, callback) {
2017-08-30 09:49:21 +00:00
// TODO: Enable the use of starttls() as an alternative to ldaps
// TODO: move this out of here and get rid of `manager` and `client` in
// auth plugin API
function callbackWrapper(valid) {
if (valid && !client) {
2018-02-24 01:07:08 +00:00
manager.addUser(user, null, true);
2017-08-30 09:49:21 +00:00
}
2017-08-30 09:49:21 +00:00
callback(valid);
}
let auth;
2017-08-29 17:11:06 +00:00
if ("baseDN" in Helper.config.ldap) {
auth = simpleLdapAuth;
} else {
auth = advancedLdapAuth;
}
2017-08-30 09:49:21 +00:00
return auth(user, password, callbackWrapper);
2017-08-29 17:11:06 +00:00
}
function isLdapEnabled() {
return !Helper.config.public && Helper.config.ldap.enable;
}
2017-08-29 17:11:06 +00:00
module.exports = {
auth: ldapAuth,
isEnabled: isLdapEnabled,
2017-08-29 17:11:06 +00:00
};