3

I am using ldapjs in two sections of my project. The first is using the passport-windowsauth strategy for passportjs and the second is part of my authentication function where I connect to retrieve user roles. I have attached an event handler to the latter to catch error events, but I have never had it trigger. I suspect the error is occurring on the passport strategy, but I am unsure how to attach an event handler to the strategy. How would I go about catching the error event on the strategy? Console log shows the following after about 15 minutes and repeats every couple of minutes indefinitely. Other than the errors in the log, the implementation works perfect.

LDAP connection error: { [Error: read ECONNRESET] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }

ldap.js

var ldap = require('ldapjs'),
fs = require('fs');

ldapClient = null;

exports.createClient = function() {
  if(ldapClient) return ldapClient;
  else {
    ldapClient = ldap.createClient({
      url: 'ldaps://srv01.contoso.local:636',
      reconnect: true,
      tlsOptions: {
        rejectUnauthorized: true,
        ca: [ fs.readFileSync(__dirname + '/../config/ca.pem') ]
      }
    });
    ldapClient.bind('binduser','C0nn3ctM3', function(err) {if(err) {
      console.log('Bind error: ' + err); assert.ifError(err); }
    });
    ldapClient.on('error', function(err) { console.log('Caught ', err.code) })
    return ldapClient;
  }
}

exports.destroyClient = function() {
  if(!ldapClient) return true;
  else {
    ldapClient.unbind();
    ldapClient.destroy();
    return true;
  }
}

passport.js

var passport = require('passport'),
    mongoose = require('mongoose'),
    WindowsStrategy = require('passport-windowsauth'),
    User = mongoose.model('User'),
    fs = require('fs');

module.exports = function() {
  passport.use(new WindowsStrategy({
    ldap: {
      url: 'ldaps://srv01.contoso.local:636/',
      base: 'DC=Contoso,DC=local',
      bindDN: 'binduser',
      bindCredentials: 'C0nn3ctM3',
      reconnect: true,
      tlsOptions: {
        rejectUnauthorized: true,
        ca: [ fs.readFileSync(__dirname + '/ca.pem') ]
      }
    },
    integrated: false
  }, function(profile, done) {
    if(!profile) { console.log('Error: Cannot retrieve profile. Bad password?'); }
    else {
      User.findOne({'userName': profile._json.sAMAccountName}, function(err, user) {
        if(user) {
          done(null, user);
        }
        else {
          var newuser = new User();
          newuser.getRoles(profile._json.sAMAccountName).then(function(userRoles) {
            var account = {
              userName: profile._json.sAMAccountName,
              firstName: profile._json.givenName,
              lastName: profile._json.sn,
              emailAddress: profile._json.mail,
              roles: userRoles
            };
            User.create(account, function (err, user) {
              if(err) {
                if(err.toString().indexOf('E11000') > -1) {
                  err = new Error('Duplicate username');
                }
              }
              done(null, user);
            });
          });
        }
      });
    }
  }));

  passport.serializeUser(function(user, done) {
    if(user) {
      done(null, user.userName);
    }
  });

  passport.deserializeUser(function(id, done) {
    User.findOne({'userName': id}).exec(function(err, user) {
      if(user) {
        return done(null, user);
      }
      else {
        return done(null, false);
      }
    })
  });
}

Update I ended up finding the line responsible for the repeated console spamming in the passport-windowsauth file LdapLookup.js and modified it. I would still like to now how I would attach an event handler to a strategy or what the alternative solution would be.

2 Answers 2

7

Maybe its too late to reply but for other reader's sake, I'm adding this reply.

ECONNRESET error occurs when after some idle time, the connection to LDAP service is reset. This is a common problem since a prolonged connection to ldap cannot be maintained. I too faced this problem recently.

There are multiple ways to solve this problem.

  1. Set reconnect option true. I see that you've already done that b
  2. Next option would be to destroy the client when ERRCONNRESET occur and recreate. You've already implemented the destroy client and recreating it every time.

You could also find this link which discuss this problem is detail.

Sign up to request clarification or add additional context in comments.

Comments

0

To further add to the response @prajnavantha gave, for the createClient {reconnect: true} option to function, you also have to bind an error event listener to the client or the reconnect will get short circuited by the default error event handler.

For instance:

const ldapjs = require("ldapjs");
const client = ldapjs.createClient({url: 'ldap://host', reconnect: true});
client.on('error', err => {
  console.debug('connection failed, retrying');
});
client.bind('user', 'password', err => {
  if (err) process.exit();
});
// ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.