Merge pull request #477 from thisisdarshan/ldap

LDAP support
This commit is contained in:
Jérémie Astori 2016-08-09 23:58:21 -04:00 committed by GitHub
commit 1fb14771ef
6 changed files with 112 additions and 23 deletions

View File

@ -292,7 +292,7 @@
</label> </label>
</div> </div>
<% if (!public) { %> <% if (!public && !ldap.enable) { %>
<div id="change-password"> <div id="change-password">
<form action="" method="post"> <form action="" method="post">
<div class="col-sm-12"> <div class="col-sm-12">

View File

@ -321,4 +321,42 @@ module.exports = {
// @default null // @default null
// //
oidentd: null, oidentd: null,
//
// LDAP authentication settings (only available if public=false)
// @type object
// @default {}
//
ldap: {
//
// Enable LDAP user authentication
//
// @type boolean
// @default false
//
enable: false,
//
// LDAP server URL
//
// @type string
//
url: "ldaps://example.com",
//
// LDAP base dn
//
// @type string
//
baseDN: "ou=accounts,dc=example,dc=com",
//
// LDAP primary key
//
// @type string
// @default "uid"
//
primaryKey: "uid"
}
}; };

View File

@ -55,7 +55,8 @@
"request": "2.72.0", "request": "2.72.0",
"semver": "5.1.0", "semver": "5.1.0",
"socket.io": "1.4.5", "socket.io": "1.4.5",
"spdy": "3.3.2" "spdy": "3.3.2",
"ldapjs": "1.0.0"
}, },
"devDependencies": { "devDependencies": {
"chai": "3.5.0", "chai": "3.5.0",

View File

@ -14,10 +14,10 @@ function ClientManager() {
} }
} }
ClientManager.prototype.findClient = function(name) { ClientManager.prototype.findClient = function(name, token) {
for (var i in this.clients) { for (var i in this.clients) {
var client = this.clients[i]; var client = this.clients[i];
if (client.name === name) { if (client.name === name || (token && token === client.token)) {
return client; return client;
} }
} }

View File

@ -21,7 +21,7 @@ program
mode = false; mode = false;
} }
if (!mode && !users.length) { if (!mode && !users.length && !Helper.config.ldap.enable) {
log.warn("No users found!"); log.warn("No users found!");
log.info("Create a new user with 'lounge add <name>'."); log.info("Create a new user with 'lounge add <name>'.");

View File

@ -10,8 +10,11 @@ var fs = require("fs");
var io = require("socket.io"); var io = require("socket.io");
var dns = require("dns"); var dns = require("dns");
var Helper = require("./helper"); var Helper = require("./helper");
var ldap = require("ldapjs");
var manager = null; var manager = null;
var ldapclient = null;
var authFunction = localAuth;
module.exports = function() { module.exports = function() {
manager = new ClientManager(); manager = new ClientManager();
@ -24,6 +27,10 @@ module.exports = function() {
var config = Helper.config; var config = Helper.config;
var server = null; var server = null;
if (config.public && (config.ldap || {}).enable) {
throw "Server is public and set to use LDAP. Please disable public if trying to use LDAP authentication.";
}
if (!config.https.enable) { if (!config.https.enable) {
server = require("http"); server = require("http");
server = server.createServer(app).listen(config.port, config.host); server = server.createServer(app).listen(config.port, config.host);
@ -43,6 +50,13 @@ module.exports = function() {
require("./identd").start(config.identd.port); require("./identd").start(config.identd.port);
} }
if ((config.ldap || {}).enable) {
ldapclient = ldap.createClient({
url: config.ldap.url
});
authFunction = ldapAuth;
}
var sockets = io(server, { var sockets = io(server, {
transports: config.transports transports: config.transports
}); });
@ -138,7 +152,7 @@ function init(socket, client) {
client.connect(data); client.connect(data);
} }
); );
if (!Helper.config.public) { if (!Helper.config.public && !Helper.config.ldap.enable) {
socket.on( socket.on(
"change-password", "change-password",
function(data) { function(data) {
@ -223,10 +237,39 @@ function reverseDnsLookup(socket, client) {
}); });
} }
function localAuth(client, user, password, callback) {
var result = false;
try {
result = bcrypt.compareSync(password || "", client.config.password);
} catch (error) {
if (error === "Not a valid BCrypt hash.") {
console.error("User (" + user + ") with no local password set tried signed in. (Probably a ldap user)");
}
result = false;
} finally {
callback(result);
}
}
function ldapAuth(client, user, password, callback) {
var userDN = user.replace(/([,\\\/#+<>;"= ])/g, "\\$1");
var bindDN = Helper.config.ldap.primaryKey + "=" + userDN + "," + Helper.config.ldap.baseDN;
ldapclient.bind(bindDN, password, function(err) {
if (!err && !client) {
if (!manager.addUser(user, null)) {
console.log("Unable to create new user", user);
}
}
callback(!err);
});
}
function auth(data) { function auth(data) {
var socket = this; var socket = this;
var client;
if (Helper.config.public) { if (Helper.config.public) {
var client = new Client(manager); client = new Client(manager);
manager.clients.push(client); manager.clients.push(client);
socket.on("disconnect", function() { socket.on("disconnect", function() {
manager.clients = _.without(manager.clients, client); manager.clients = _.without(manager.clients, client);
@ -238,28 +281,35 @@ function auth(data) {
init(socket, client); init(socket, client);
} }
} else { } else {
var success = false; client = manager.findClient(data.user, data.token);
_.each(manager.clients, function(client) { var signedIn = data.token && client && client.token === data.token;
if (data.token) { var token;
if (data.token === client.config.token) {
success = true; if (data.remember || data.token) {
} token = client.token;
} else if (client.config.user === data.user) {
if (bcrypt.compareSync(data.password || "", client.config.password)) {
success = true;
}
} }
var authCallback = function(success) {
if (success) { if (success) {
if (!client) {
// LDAP just created a user
manager.loadUser(data.user);
client = manager.findClient(data.user);
}
if (Helper.config.webirc !== null && !client.config["ip"]) { if (Helper.config.webirc !== null && !client.config["ip"]) {
reverseDnsLookup(socket, client); reverseDnsLookup(socket, client);
} else { } else {
init(socket, client); init(socket, client, token);
} }
return false; } else {
}
});
if (!success) {
socket.emit("auth", {success: success}); socket.emit("auth", {success: success});
} }
};
if (signedIn) {
authCallback(true);
} else {
authFunction(client, data.user, data.password, authCallback);
}
} }
} }