I try to implement a logIn in Meteor 0.9.2.1 with LDAPJS and Meteor methods. The code for the server-side is:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
LDAP = {};
LDAP.ldap = ldap;
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
LDAP.searchQuery = function(user) {
return{
filter: '(uid=username)',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
search.on('searchEntry', function(entry){
//console.log('entry: ' + JSON.stringify(entry.object));
dn.push(entry.object.uid);
dn.push(entry.object.userPassword)
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
var testBind = LDAP.ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
testBind.bind(dn[10], options.password, function (err) {
future['return'](!err);
});
client.unbind(function (err) {
assert.ifError(err);
future['return'](!err);
});
});
});
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
var loginHandler = function (username, password) {
Accounts.registerLoginHandler("ldapjs",function(loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var user = Meteor.users.findOne({ username: loginRequest.username });
if(err){
console.log(err)
}
return {
userId: uid
}
}
});
};
Meteor.methods({
setSignIn: function(username, password) {
loginHandler(username,password)
}
});
My Problem is, that when I want to log in it starts with the loginHandler. But than the console throws back that Object has no method checkAccount
. I changed today a lot and I'm already totally confused.
You need to instantiate the empty object as var LDAP = {}
. Rest will be solved magically :)
I finally got to work it. Referneces:
http://notjoshmiller.com/using-ldaps-in-meteor/, https://github.com/emgee3/meteor-accounts-ldap
server-side:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
var LDAP = {};
LDAP.ldap = ldap;
//provides the variables, needed for the connection
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
//is needed for the searchQuery, which delivers the Filter so that only the uid with
//the given username get searched
LDAP.searchQuery = function(username) {
return{
filter: '(uid=' + username + ')',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
//connects the client, nginx is here not necessary
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
//create the connection
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
if(err){
console.log(err)
}
//uses the class searchEntry, which is node-specific
search.on('searchEntry', function (entry) {
dn.push(entry.objectName);
LDAP.displayName = entry.object.displayName
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
//uses the end class to 'fulfill' the connection by binding
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
LDAP.client.bind(dn[0], options.password, function (err) {
future['return'](!err);
});
});
});
return future.wait();
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
Meteor.startup(function(){
Accounts.registerLoginHandler("ldapjs", function (loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var userId;
var user = Meteor.users.findOne({
username : loginRequest.username
//'profile.name': LDAP.displayName
});
if (user) {
userId = user._id;
} else {
// If no Meteor Account is found for a valid LDAP logon,
// you can either prevent logon by passing 'undefined' or
// you can automatically create the new account.
// return undefined;
userId = Meteor.users.insert({ username : loginRequest.username });
}
return {
userId: userId
}
}
return undefined;
});
});
client side:
Meteor.ldapLogin = function (username, password, callback) {
var loginRequest = {
username: username,
password: password
};
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: function (err) {
if (err) {
console.log(err);
Session.set('alert', 'No valid inputs!');
} else {
Router.go('/Home');
}
}
});
};
//handles LogIn-Button, by using LDAPJS
Template.signIn.events({
"submit #box-login": function (e, t) {
e.preventDefault();
var signInForm = $(e.currentTarget),
username = trimInput(signInForm.find('#emailSignIn').val().toLowerCase()),
password = signInForm.find('#passwordSignIn').val();
if(isNotEmpty(username)&& isNotEmpty(password)) {
Meteor.ldapLogin(username, password, function (err) {
if (err) {
console.log(err)
Session.set('alert', 'Sorry, something went wrong.');
}
});
} else {
Session.set('alert','Please insert your username and password!')
}
return false;
}
});
PS: No Meteor.methods and Meteor.call is needed! It might change with every new Meteor version and package, but I guess u're aware of that ;)