node-ldapjs: LDAP Connection error

Hello,

I do my connection like this

const client = ldap.createClient({
            url: `ldap://url:389`,
            reconnect: true
        });

        client.bind(_this.options.genericEmail, _this.options.genericPassword, err => {
            if (err) {
                callback(err);
            }
        });

And unbind after a search.

client.unbind( err => {
                        if (err) {
                            console.log(err);
                        }
                    });

But after a while on the development server, if it tries to connect again, I get this error and breaks the node server. I am running this application on a kubernetes environment.

events.js:167
--
  | throw er; // Unhandled 'error' event
  | ^
  |  
  | Error: read ECONNRESET
  | at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
  | Emitted 'error' event at:
  | at Socket.onSocketError (/usr/src/app/node_modules/ldapjs/lib/client/client.js:1169:12)
  | at Socket.emit (events.js:182:13)
  | at emitErrorNT (internal/streams/destroy.js:82:8)
  | at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
  | at process._tickCallback (internal/process/next_tick.js:63:19)

Please help me fix this error.

Thank you.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 23 (3 by maintainers)

Commits related to this issue

Most upvoted comments

I think this is the timeout error, I can’t test your code right now since my desktop is updating to F29 but should be able to later today.

In the meantime you can add a listener for the errors, so they hopefully won’t crash your application. Here is an example of listening for errors on the client.

// Return errors
client.on('error', error => {
    // Do something with the error
});

@tastypackets Thank you so much for detailed testing and explanation. Looks like switching to ldapts is the best option, and looks like no one maintains this code base. I will leave this open if at all someone wants to pick it up in the future. I would love to contribute, but my knowledge in LDAP is very very limited.

I’m not 100% sure this is your issue based off what you posted, but looks similar to when the client is left open and connection is reset due to inactivity.

The client is connected the minute it’s created, I think it’s a poor decision in this lib. If you don’t destroy / disconnect the client you will get an error from the connection timing out.

The client code is documented saying it can be reused and auto-reconnect, however in my expierence this has not worked so well especially with Active Directory servers.

If the auto-reconnection is working for you then disconnecting the client might be a good option. If not you can create a new client for each bind request.

Honestly though, if you have the option to switch packages you should look at ldapts. It’s what I have been monitoring and planning to switch to if sometime soon.

It’s created by someone else here who was unable to get there updates merged with this lib do to author inactivity.

https://github.com/ldapts/ldapts

No I am just getting User Groups. Let me share the code that I am using.

this.adSuffix = "OU=Employees,OU=<Company> Users,DC=<company>,DC=com";
const searchOptions = {
            scope: "sub",
            filter: `(cn=${_this.options.getACLForUser})`,
            attributes: 'memberOf' // just get memberOf to optimise. 
        };
        // Create client and bind to AD
        const client = ldap.createClient({
            url: `ldap://ds.company.com:389`,
            reconnect: true,
            idleTimeout: 259200000
        });

        client.bind(_this.options.genericEmail, _this.options.genericPassword, err => {
            if (err) {
                callback(err);
            }
        });

        client.search(_this.adSuffix, searchOptions, (err, res) => {
            if (err) {
                callback(err);
            } else {
                let memberOf = [];
                res.on('error', err => {
                    callback(err);
                });
                res.on('searchEntry', entry => {
                    memberOf = entry.object.memberOf;
                });
                res.on('end', result => {
                    callback(null, memberOf);
                    client.destroy();
                });
            }
        });

This gives me the below error and crashes the server. I placed forever to run on crash currently. But would prefer better solution.

We have a Java application and it connects to same ldap source with similar parameters. And that application runs without crashing.

events.js:167
--
  | throw er; // Unhandled 'error' event
  | ^
  |  
  | Error: read ECONNRESET
  | at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
  | Emitted 'error' event at:
  | at Socket.onSocketError (/usr/src/app/node_modules/ldapjs/lib/client/client.js:1169:12)
  | at Socket.emit (events.js:182:13)
  | at emitErrorNT (internal/streams/destroy.js:82:8)
  | at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
  | at process._tickCallback (internal/process/next_tick.js:63:19)
  | [nodemon] app crashed - waiting for file changes before starting...