-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
findUser error: "In order to perform this operation a successful bind must be completed on the connection." #78
Comments
Can you post the sample code you are using? I just went through my tests and I'm not getting any errors or failures. |
|
Thanks for the code sample. But sorry, I still can't replicate the problem. That code works for me, although 'johndoe' needs to be a userPrincipalName (johndoe@abc) for the authenticate to work. Do you have any referrals configured for active directory? Can you post the full stack trace / error? Optionally, can you enable the bunyan logging? To configure bunyan, change your AD config to include a 'logging' property: var adConfig = {
url: url,
baseDN: baseDN,
username: username,
password: password,
logging: {
name: 'ActiveDirectory',
streams: [
{ level: 'debug',
stream: process.stdout }
]
}
} |
|
I installed 0.6.4, and without changing any code, this is the bunyan log (names have been changed to protect the innocent):
|
I see this also on 0.6.5. Going back to 0.6.4 results in a working app. I switched from ldaps:// to ldap:// while on 0.6.5 and did a packet capture and saw that there was no longer a bind on the connection before searching. All my code does is call .authenticate and then .findUser. |
Hmm... I can't replicate this. Are you also running on Windows? |
No, Linux. |
I'm a total noob, but if it matters, Opts is empty in the 0.6.5 bunyan log when creating the ldapjs client for authentication (and not empty in the 0.6.4 log). |
Yeah. That is what I'm looking at right now. However, in my tests where I pass in a custom opts object as well as the default opts, I am seeing the same opts output. |
What version of node are you using? |
0.10.36 |
OK. Same here. |
0.12.2 |
I pushed some updated code to the git repository. Adding a console.log statement to see what is happening with the opts parsing. Please clone the latest GIT repository.
In particular, I'm looking for the createClient() output line. |
Here is the test code that I am using. Perhaps I'm doing something different and not seeing the subtle difference? This would be so much easier to fix if I could replicate the problem... var _ = require('../node_modules/underscore');
var config = require('./config').config;
var activeDirectory = new (require('../index'))(config);
var ad = activeDirectory;
var username = 'user@domain.com';
var password = 'password';
ad.authenticate(username, password, function(err, auth) {
if (err) {
console.log('ERROR: '+JSON.stringify(err));
return;
}
if (auth) {
console.log('Authenticated...');
ad.findUser(username, function(err, user) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! user) console.log('User: ' + username + ' not found.');
else console.log(JSON.stringify(user));
});
}
else {
console.log('Authentication failed!');
}
}); Where the config.js file contains: var url = 'ldap://domain.com';
var baseDN = 'dc=domain,dc=com';
var username = 'auth@domain.com';
var password = 'authpassword';
module.exports = {
url: url,
baseDN: baseDN,
username: username,
password: password,
config: {
url: url,
baseDN: baseDN,
username: username,
password: password,
logging: {
name: 'ActiveDirectory',
streams: [
{ level: 'debug',
stream: process.stdout }
]
}
}
}; I also have a secondary test that was in response to issue #77, which is nearly identical. The primary difference being that I clear our the preconfigured username/password and then pass in secondary authentication via the opts. var _ = require('../node_modules/underscore');
var config = require('./config').config;
// Here we exclude the preconfigured username/password
var activeDirectory = new (require('../index'))(_.omit(config, 'username', 'password'));
var ad = activeDirectory;
var username = 'user@domain.com';
var password = 'password';
ad.authenticate(username, password, function(err, auth) {
if (err) {
console.log('ERROR: '+JSON.stringify(err));
return;
}
if (auth) {
console.log('Authenticated...');
var opts = {
bindDN: username,
bindCredentials: password
};
ad.findUser(opts, username, function(err, user) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! user) console.log('User: ' + username + ' not found.');
else console.log(JSON.stringify(user));
});
}
else {
console.log('Authentication failed!');
}
}); Both of these test cases work. |
I think our AD at my work does not allow anonymous binds. Basically, you have to bind before searching for anything. That may be an option you can enable on your AD in order to replicate this? |
My AD doesn't allow anonymous searches either. You MUST bind before doing a search. In my example output, you can see the bindDN and bindCredentials being passed:
The first call to createClient is empty because we want to bind manually on an authenticate method call binding instead with the username/password that was provided. For all operations in node-activedirectory, except authenticate() and getRootDSE(), the username/password that are specified when you configure and create your AD object are used for the binding operations. Issue #77 added support to allow for alternate binding to be specified for all method calls via the opts object. |
Did you do a test run with the updated version on the GIT repository? |
|
A packet dump again shows an immediate search without a bind. Modifying the example to add tlsOptions { ca: ... } and switching to ldaps:// show the same results (although there are the tlsOptions in the printed debug). |
Here are the stack and debug log using the latest build. I got the same results when I tried passing the bindDN and bindCredentials into findUser() via opts.
|
A quick grep through ldapjs/lib/client/ for bindDN only hits in pool.js... some quick debugs show that with 0.6.5/6 the code path in ldapjs/lib/client/index.js returns the new Client(options) while 0.6.4 selects the ClientPool. |
Adding more debug in ldapjs/lib/client/index.js shows that 0.6.5/6 omit the maxConnections parameter (where 0.6.4 included it and many others) to createClient causing the selection of the non-pool Client. |
Checking my client libraries, I'm actually using the v0.7.1 ldapjs client.... |
|
I'm going to assuming applying the following diff: diff --git a/lib/activedirectory.js b/lib/activedirectory.js
index 6715e98..c074c3d 100755
--- a/lib/activedirectory.js
+++ b/lib/activedirectory.js
@@ -288,7 +288,7 @@ function createClient(url, opts) {
log.trace('createClient(%s)', url);
console.log('createClient('+JSON.stringify(url) + ')->'+JSON.stringify(getLdapClientOpts(_.defaults({}, { url: url }, opts, this.opts))));
- var opts = getLdapClientOpts(_.defaults({}, { url: url }, opts, this.opts));
+ var opts = getLdapClientOpts(_.defaults({}, { url: url }, this.opts));
log.debug('Creating ldapjs client for %s. Opts: %j', opts.url, _.omit(opts, 'url', 'bindDN', 'bindCredentials'));
var client = ldap.createClient(opts);
return(client); Resolves the problem? It should ignore the extra opts parsing that was recently added. But doing that removes the new features that were added. Grr... this is frustrating why I can't replicate the problem locally. |
Nope, non-pool Client is still selected.
|
It looks like, as you mention in a comment in your code, that the pooled client will be removed with the next ldapjs release... at which point, the same createClient() instance will need to be saved in your code so that a bind (authenticate) can be called followed by a search (e.g. findUser) through your API. Otherwise it will not be possible to perform a search on a bound client :( |
So with the patch I provided, you're still getting the client bind error? |
Correct. I applied that diff on top of 0.6.6. If I also delete the getLdapClientOpts() on that same line, it works. |
What was the output from the console.log for "createClient"? I'm trying to figure out what opts are getting dropped, etc. |
This issue seems to be caused by the dropping of maxConnections from the opts which is still valid in ldapjs 0.7.1. Your code sets maxConnections to 20 if it isn't supplied by the caller. Currently that parameter (when > 1) causes createClient to use a ldapjs pooled client which automatically binds to the bindDN. The non-pooled client does not do that in ldapjs 0.7.1. In ldapjs master, maxConnections is removed but the non-pooled client will bind to the bindDN automatically. |
But here is the output. Non-working:
Working:
I added in the REGULAR CLIENT and CLIENT POOL debug lines in the ldapjs code at lib/client/index.js around the if (options.maxConnections > 1). |
Oh, I also added the "createClient options" \n options debug splats in the same file in order to see what was actually being passed. You can see the addition of a ton of parameters. |
Yes. I think you are right. Before reading your previous message I was looking at the output and noticed that immediately and it makes sense. Can you apply the following patch: index 6715e98..ed2315f 100755
--- a/lib/activedirectory.js
+++ b/lib/activedirectory.js
@@ -287,8 +287,11 @@ function createClient(url, opts) {
}
log.trace('createClient(%s)', url);
-console.log('createClient('+JSON.stringify(url) + ')->'+JSON.stringify(getLdapClientOpts(_.defaults({}, { url: url }, opts, this.opts))));
+console.log('createClient BEFORE('+JSON.stringify(url) + ')->'+ JSON.stringify(opts || this.opts));
var opts = getLdapClientOpts(_.defaults({}, { url: url }, opts, this.opts));
+// var opts = _.defaults({}, { url: url }, this.opts);
+//console.log('createClient AFTER('+JSON.stringify(url) + ')->'+JSON.stringify(getLdapClientOpts(_.defaults({}, { url: url }, opts, this.opts))));
+console.log('createClient AFTER('+JSON.stringify(url) + ')->'+JSON.stringify(opts));
log.debug('Creating ldapjs client for %s. Opts: %j', opts.url, _.omit(opts, 'url', 'bindDN', 'bindCredentials'));
var client = ldap.createClient(opts);
return(client);
@@ -333,7 +336,8 @@ function getLdapClientOpts(opts) {
'host', 'port', 'secure', 'tlsOptions',
'socketPath', 'log', 'timeout', 'idleTimeout',
'reconnect', 'queue', 'queueSize', 'queueTimeout',
- 'queueDisable', 'bindDN', 'bindCredentials'
+ 'queueDisable', 'bindDN', 'bindCredentials',
+ 'maxConnections'
));
} I added the 'maxConnections' to the list of supported ldapjs values. |
…at the pooled ldapjs client is used.
Commit: 420c6cf |
Thanks!!! |
I am having this same problem ... WIndows 10, Node 6.5.0; I have verified my version of activeDirectory has the content of commit 420c6cf One thing that was a stumbling block is that I don't see anywhere in the documentation that says "findUser must run inside the authenticate() callback", which is implied by the working tests from the comment "gheeres commented on May 19, 2015" my "npm ls" says this about my activeDirectory installation:
I'll keep trying to figure out what I'm doing wrong, but I am hopeful someone will be able to help he mere! |
The findUser() does not need to be run inside of the authenticate() method. findUser() will use the credentials that were passed in when the ActiveDirectory object was created. There have been instances where users have wanted to avoid having a special lookup account where they wanted the findUser() to run in the context of the person that had just logged on. In that case, you would need to have it inside of the authenticate() method. This is an advanced scenario. The problem is likely that you are not initializing your ActiveDirectory object correctly. You must specify a valid username/password. This is an account that has permissions to view / search the entire active directory domain. It is typically NOT the user that is logged in, etc. var ad = activeDirectory({
url: 'ldap://server',
baseDN: 'DC=ABC,DC=LOCAL',
username: 'ldapuser@abc',
password: 'ldappass'
}); |
Thanks - I'll try some more :) ETA: Thanks - that helped my understanding a lot. With that and the SysInternals "Active Directory Explorer" tool, I was able to figure out the proper configuration to get this working. |
This error occurred during findUser after updating to 0.6.5. I reinstalled 0.6.3, and the error went away.
The text was updated successfully, but these errors were encountered: