Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node JS LDAP Auth User

I am creating a login authentication page, where a user would input there active directory username and password and using NodeJS I would check to see if it's valid, but I keep getting

[Error: LDAP Error Bad search filter]

or

[Error: Search returned != 1 results]

When I'm trying to search for the username and password, my code is below:

I'm using: https://github.com/jeremycx/node-LDAP, let's say that the user entered a username of hhill

    var ldap = require('LDAP');
    var ldapServer = new ldap({ uri: 'ldap://batman.lan', version: 3});

    ldapServer.open(function(error) {
        if(error) {
           throw new Error('Cant not connect');
        } else {
            console.log('---- connected to ldap ----');

            username = '(cn='+username+')';
            ldapServer.findandbind({
                base: 'ou=users,ou=compton,dc=batman,dc=lan',
                filter: username,
                password: password
            }, function(error, data) {
                if(error){
                    console.log(error);
                } else {
                    console.log('---- verified user ----');
                }
            });
        }
    });

Does anyone have any suggestions on what I'm doing wrong?

UPDATE

Here is the solution I came up with if anyone ever needs it, with the help of the answer below

    var username = request.param('username');
    var password = request.param('password');

    var ldap = require('ldapjs');
    ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
    var client = ldap.createClient({
          url: 'ldap://batman.com/cn='+username+', ou=users, ou=compton, dc=batman, dc=com',
          timeout: 5000,
          connectTimeout: 10000
    });
    var opts = {
      filter: '(&(objectclass=user)(samaccountname='+username+'))',
      scope: 'sub',
      attributes: ['objectGUID']
    };

    console.log('--- going to try to connect user ---');

    try {
        client.bind(username, password, function (error) {
            if(error){
                console.log(error.message);
                client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
            } else {
                console.log('connected');
                client.search('ou=users, ou=compton, dc=batman, dc=com', opts, function(error, search) {
                    console.log('Searching.....');

                    search.on('searchEntry', function(entry) {
                        if(entry.object){
                            console.log('entry: %j ' + JSON.stringify(entry.object));
                        }
                    });

                    search.on('error', function(error) {
                        console.error('error: ' + error.message);
                    });

                    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
                });
            }
        });
    } catch(error){
        console.log(error);
        client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
    }
like image 977
Sukh Avatar asked Jul 22 '13 18:07

Sukh


2 Answers

In this case, you need ldapClient rather than ldapServer, this is the example code from the official doc:

var ldap = require('ldapjs');

ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;

var client = ldap.createClient({
  url: 'ldap://127.0.0.1/CN=test,OU=Development,DC=Home'
});

var opts = {
  filter: '(objectclass=user)',
  scope: 'sub',
  attributes: ['objectGUID']
};

client.bind('username', 'password', function (err) {
  client.search('CN=test,OU=Development,DC=Home', opts, function (err, search) {
    search.on('searchEntry', function (entry) {
      var user = entry.object;
      console.log(user.objectGUID);
    });
  });
});
like image 123
zs2020 Avatar answered Oct 30 '22 19:10

zs2020


@Sukh Thank you for posting your UPDATE solution; however, there is a problem with the code you posted in your UPDATE. While it works for simple cases, with larger queries, you will find you are unbinding before the results have been output. The solution for me was to move your unbinds into the search.on functions.

Here is an edit of your UPDATE:

var ldap = require('ldapjs');
ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
var client = ldap.createClient({
      url: 'ldap://batman.com/cn='+username+', ou=users, ou=compton, dc=batman, dc=com',
      timeout: 5000,
      connectTimeout: 10000
});
var opts = {
  filter: '(&(objectclass=user)(samaccountname='+username+'))',
  scope: 'sub',
  //attributes: ['objectGUID']
  // This attribute list is what broke your solution
  attributes: ['objectGUID','sAMAccountName','cn','mail','manager','memberOf']
};

console.log('--- going to try to connect user ---');

try {
    client.bind(username, password, function (error) {
        if(error){
            console.log(error.message);
            client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
        } else {
            console.log('connected');
            client.search('ou=users, ou=compton, dc=batman, dc=com', opts, function(error, search) {
                console.log('Searching.....');

                search.on('searchEntry', function(entry) {
                    if(entry.object){
                        console.log('entry: %j ' + JSON.stringify(entry.object));
                    }
                    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
                });

                search.on('error', function(error) {
                    console.error('error: ' + error.message);
                    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
                });

                // don't do this here
                //client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
            });
        }
    });
} catch(error){
    console.log(error);
    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
}

At least this is what I discovered when using your solution with Active Directory searches. memberOf returns A LOT of entries in my use case and the unbinds were being done prematurely, so I was getting the following error:

error: 1__ldap://my.domain.com/,OU=Employees,OU=Accounts,DC=my,DC=domain,DC=com closed
client disconnected
like image 9
Shaun Avatar answered Oct 30 '22 18:10

Shaun