Node JS LDAP Auth User

后端 未结 3 1341

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

相关标签:
3条回答
  • 2020-12-23 15:21

    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);
        });
      });
    });
    
    0 讨论(0)
  • 2020-12-23 15:40

    Suggestions

    1.Don't use ldapauth-fork (Huge hanging issue, if we hit multiple requests then after some time library gets unresponsive and doesn't return anything.)

    2.Don't use passport-ldapauth (Internally calls ldapauth-fork)

    We can use ldapjs, which has easy implementation and is based on event driven approach.

    Below nodejs code explain complete solution for ldap auth and search.

    JS code

    const ldap = require('ldapjs');
    let client
    
    // unbind after completion of process
    function closeConnection() {
        console.log('closeConnection')
        client.unbind(err => {
            console.log('unbind error', err)
        });
    }
    
    function search() {
        const searchOptions = {
            filter: '(uid=yourSearchText)', // search text
            scope: 'sub'
        };
        return new Promise((resolve, reject) => {
            client.search('ou=consultants,' + 'ou="Your OU",ou=yourOu,dc=yourDc,dc=com', searchOptions, (err, res) => {
                res.on('searchEntry', entry => {
                    console.log('searchEntry', entry.object);
                    resolve(entry.object)
                });
                res.on('searchReference', referral => {
                    console.log('referral: ' + referral.uris.join());
                    resolve(referral.uris.join())
                });
                res.on('error', err => {
                    console.error('search error: ' + err.message);
                    reject(err)
                });
                res.on('end', result => {
                    console.log('If not found', result);
                    reject({ message:'User not found'})
                });
            });
        })
    }
    
    function authenticate() {
        const server = 'ldap server ip';
        client = ldap.createClient({
            url: `ldap://${server}`
        });
    
        return new Promise((resolve, reject) => {
            client.bind('cn=yourcn,dc=yourdc,dc=com', 'sortedSolutions', err => {
                if (err) {
                    reject(err)
                }
                resolve('Authenticated successfully')
            });
        })
    }
    
    function start(req, res) {
        let searchResponseData
        authenticate()
            .then(authenticateResponse => {
                console.log('authenticateResponse', authenticateResponse)
                return search()
            })
            .then(searchResponse => {
                console.log('searchResponsesearchResponse', searchResponse)
                searchResponseData = searchResponse
                return closeConnection()
            })
            .then(closeConnectionResponse => {
                console.log('ldap connection closed', closeConnectionResponse)
                res.status(200).send(searchResponseData)
            })
            .catch(error => {
                console.log('catch error', error)
                res.status(400).send(error)
            })
    
    }
    
    module.exports.start = start
    

    // We can use same code with no authentication, Just pass '' to bind function client.bind('', '', err => { //same as above })

    0 讨论(0)
  • 2020-12-23 15:42

    @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
    
    0 讨论(0)
提交回复
热议问题