LDAP authentication using passport-ldapauth npm

24.7k views Asked by At

I am trying to authenticate openLDAP username and password using passport-ldapauth npm. While executing the below code I am always getting error as { message: 'Missing credentials' }. Kindly help me what is wrong with my code.

var connect = require('connect'),
    app = connect(),
    passport = require('passport'),
    LdapStrategy = require('passport-ldapauth');

// Credentials from the free LDAP test server by forumsys
// More info at: http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
var OPTS = {
    server: {
        url: 'ldap://<ip>',
        bindDn: '<admin username>',
        bindCredentials: '<admin password>',
        usernameField: "<passing actual username>",
        passwordField: "<password>"
    }
};

passport.use(new LdapStrategy(OPTS));

app.use(passport.initialize());


app.use(connectRoute(function (router) {
        router.post('/login', function (req, res, next) {
            passport.authenticate('ldapauth', {session: false}, function (err, user, info) {
                console.log(info);
                if (err) {
                    return next(err); // will generate a 500 error
                }
                // Generate a JSON response reflecting authentication status
                if (!user) {
                    return res.send({success: false, message: 'authentication failed'});
                }
                return res.send({success: true, message: 'authentication succeeded'});
            })(req, res, next);
        });
    }))

app.listen(8080);

For more details, please see this badRequestMessage flash message for missing username/password (default: 'Missing credentials')

9

There are 9 answers

1
user8414217 On
var basicAuth = require('basic-auth');
var LdapAuth = require('ldapauth-fork');
var username: string = req.body.username;
var password: string = req.body.password;

var ldap = new LdapAuth({
   url:                Constants.LDAP_SERVER_URL_STRING,
   bindDN:             Constants.LDAP_BIND_DN_STRING,
   bindCredentials:    Constants.LDAP_PASSWORD_STRING,
   searchBase:         'uid=' + username + ',' + Constants.LDAP_SEARCHBASE_STRING,
   searchFilter:       Constants.LDAP_SEARCHFILTER_STRING
   //  reconnect: true
});    

ldap.authenticate(username, password, function(err, user) {  
   if (err) {     
       console.log("login Error");   
       res.send({ success : false, message : 'authentication failed' });
   } else if(!user.uid) {
      console.log("user not found Error");
      res.send({ success : false, message : 'authentication failed' });
   } else if(user.uid) {
      console.log("success : user "+ user.uid +" found ");
   }
});
0
warun26 On

According to the documentation provided by passport-ldapauth, the object which is the value of server does not contain the usernameField and passwordField. Your strategy should look like:

var OPTS = {
  server: {
    url: 'ldap://<ip>',
    bindDn: '<admin username>',
    bindCredentials: '<admin password>'
  },
  usernameField: "<field containing username>",
  passwordField: "<field containing password>"
};

But as G Chen mentions in his answer, the usernameField and passwordField are optional.

2
G Chen On

Here is my configuration:

var passport = require('passport');
var LdapStrategy = require('passport-ldapauth').Strategy;

var OPTS = {
  server: {
    url: '<ldap server>',
    bindDn: '<admin username>',
    bindCredentials: '<admin password>',
    searchBase: '<base dn>',
    searchFilter: '(sAMAccountName={{username}})'
  }
};

passport.use(new LdapStrategy(OPTS));

app.use(passport.initialize());
app.use(passport.session());

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

passport.deserializeUser(function(user, done) {
  done(null, user);
});

The usernameField and passwordField in OPTS are optional. My program is using the default value username and password. If the usernameField is set, you need to modify searchFilter as (sAMAccountName={{<usernameField value>}}) or (uid={{<usernameField value>}}).

Also, in order to store the login status in your session, express-session module is required. The session configuration is like:

var session = require('express-session');
app.use(session({
  secret: 'ldap secret',
  resave: false,
  saveUninitialized: true,
  cookie : { httpOnly: true, maxAge: 2419200000 } /// maxAge in milliseconds
}));

Then, you can use the LDAP authentication as:

app.post('/login', passport.authenticate('ldapauth', {
  successRedirect: '/users/profile', failureRedirect: '/login'
})); 
0
user8414217 On

Please check the following Code where Basic Authentication of the user has to be performed. This code works when a user login credentials have to be verified.

We need to use 3 fields viz. usernameField, passwordField and credentialsLookup

`var basicAuth = require('basic-auth');
var OPTS = {
server: {
url: Constants.LDAP_SERVER_URL_STRING,
bindDn: Constants.LDAP_ADMIN_STRING, 
bindCredentials: Constants.LDAP_PASSWORD_STRING,
// searchBase: Constants.LDAP_SEARCHBASE_STRING,
// searchFilter: Constants.LDAP_SEARCHFILTER_STRING
//          reconnect: true

},
usernameField: username,
passwordField: password,
credentialsLookup: basicAuth
};

LDAP Administration tools like Userbooster light are very useful in understanding how the authentication process happens.

Fields such as searchBase, searchFilter are of no use. The disclaimer however is that you need to test to see if it is true

0
grzech o On

A Change in ldapauth-fork/lib/ldapauth.js bindProperty from dn to upn : this.opts.bindProperty || (this.opts.bindProperty = 'userPrincipalName') causes username authentication. Full dn is not needed.

0
Pranoy Sarkar On

After wasting lot of time, I finally able to fix it. Some my findings

  1. {{username}} replacement happens ONLY ON searchFilter. I was doing it on searchBase
  2. Make sure your request body has username and password filed and you have used correct body-parser otherwise passport will notable to extract
  3. As passport was not showing any error it was failing silently, add debugger in two places in the of the library In ldapauth.js search for LdapAuth.prototype.authenticate here you will able to see ldapauth is able to extract password/username

    In strategy.js search for ldap.authenticate here you will be able to see what is the actuall error

0
Jingshao Chen On

Don't use admin username or password in DN. If you want to authenticate a user, all you need is the user's own username and password.

The dn is the Bind DN in LDAP. Depends on your ldap server configuration, it varies. Use ldapsearch to experiment to find out which one should you use.

I wrote an npm module based on passport-ldapauth to simplify the ldap authentication login.Please check it out at: https://github.com/shaozi/express-passport-ldap-mongoose

Simple usage:

LdapAuth.init(CONFIG.ldap.dn, CONFIG.ldap.url, app,
  (id) => User.findOne({ uid: id }).exec(),
  (user) => User.findOneAndUpdate({ uid: user.uid }, user, { upsert: true, new: true }).exec()
)
0
user8414217 On

Please check NPM with "LDAP Authentication"

You will come across a package called ldapauth-fork. This package seems to be working correctly.

Please check the following link https://www.npmjs.com/package/ldapauth-fork

0
ruichao On

Maybe the issue is not caused by the passport-ldapauth. There may be some problems with your post requests. Check if there are [usernameField], [passwordField] in your request before using passport.authenticate.