3

I've been struggling with passport-ldapauth for a couple of days, and I have no more ideas left what am I doing wrong.

Briefly, I have a project that uses two passport strategies: local and LDAP. Local strategy works perfectly for me, but LDAP is the problematic one.

I have a read-only user for AD (let's call it "ldap-read-only-admin"), and I am able to connect with this user via external LDAP client and view the relevant OU. I have also triple-checked the SearchBase, and it seems to be correct.

However, when passing the same configuration to passport-ldapauth, it seems that it cannot bind user credentials (I guess). Any ideas on how to debug this will be much appreciated.

This is the app.js:

    var express = require("express");
    var app     = express();
    var path    = require("path");
    var session = require("express-session");
    var mongoose = require("mongoose");
    var passport = require("passport");
    var flash = require("connect-flash");
    var cookieParser = require("cookie-parser");
    var bodyParser = require("body-parser");
    var morgan = require("morgan");

    var configDB = require('./config/database.js');
    require('./config/passport.js')(passport); // pass passport for configuration


    app.use(express.static(__dirname + '/public'));  

    app.set('view engine', 'ejs');

    //connect to the Database
    var promise = mongoose.connect(configDB.url, {
      useMongoClient: true,
    });      

    app.use(morgan('dev')); // log every request to the console
    app.use(cookieParser()); // read cookies (needed for auth)
    //app.use(bodyParser()); // get information from html forms
    app.use(bodyParser.urlencoded({
      extended: true
    }));
    app.use(bodyParser.json({
      extended: true
    }));

    // configuring passport
    app.use(session({ secret: 'secret',  resave: true, saveUninitialized: true })); // session secret
    app.use(passport.initialize());
    app.use(passport.session()); // persistent login sessions
    app.use(flash()); // use connect-flash for flash messages stored in session


    require('./modules/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport


    //make Web server listen on a specific port
    app.listen(3000);

    logger.info("Listening on port 3000");

This is routes.js (the relevant part):

module.exports = function(app, passport) {
app.post('/', function(req, res, next) {

    passport.authenticate('ldap-login', {session: true}, function(err, user, info) {
    console.log("user: " + user);
    console.log("info: " + JSON.stringify(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);
  });


}

And this is passport.js:

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

    // load the user model
    var User            = require('../modules/user.js');

    // expose this function to our app using module.exports
    module.exports = function(passport) {

        // =========================================================================
        // passport session setup ==================================================
        // =========================================================================
        // required for persistent login sessions
        // passport needs ability to serialize and unserialize users out of session

        // used to serialize the user for the session
        passport.serializeUser(function(user, done) {
            done(null, user.id);
        });

        // used to deserialize the user
        passport.deserializeUser(function(id, done) {
            User.findById(id, function(err, user) {
                done(err, user);
            });
        });


      // =========================================================================
        // LOCAL LOGIN =============================================================
        // =========================================================================

        passport.use('local-login', new LocalStrategy({

           passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) { // callback with email and password from our form

            // find a user whose email is the same as the forms email
            // we are checking to see if the user trying to login already exists
            User.findOne({ username :  username }, function(err, user) {
                // if there are any errors, return the error before anything else
                if (err)
                    return done(err);

                // if no user is found, return the message
                if (!user)
                    return done(null, false, req.flash('loginMessage', 'The username "' + username + '" is not found.')); // req.flash is the way to set flashdata using connect-flash

                // if the user is found but the password is wrong
                if (!user.validPassword(password))
                   return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata

                // all is well, return successful user
                return done(null, user);
            });

        }));



        // =========================================================================
        // LDAP Login ==============================================================
        // =========================================================================

        var opts = {
            server: {
                    url: 'ldap://<ldap server address>:389',
                    bindDn: 'cn=ldap-read-only-admin',
                    bindCredentials: 'password',
                    searchBase: 'OU=XX1, OU=XX2, DC=domain, DC=local',
                    searchFilter: '(uid={{username}})',    
                   // passReqToCallback : true
                  }
        };

      passport.use('ldap-login', new LdapStrategy(opts, function(req, user, done) {
            console.log("Passport LDAP authentication.");
          done(null, user);
        }

    ));   

    };

1 Answer 1

5

After another five hours of trying, I managed to fix my problem.

First, my "ldap-read-only-admin" was under the same OUs as other users, so I had to put the whole path to my ldap-read-only-admin in the bindDN string. Second, I needed to use sAMAccountName instead of uid. And third, I had to remove req from the LdapStrategy function.

Here is how ldap login in passport.js looks like:

// =========================================================================
    // LDAP Login ==============================================================
    // =========================================================================

    var opts = {
        server: {
                url: 'ldap://<ldap server address>:389',
                bindDn: 'cn=ldap-read-only-admin,OU=XX1, OU=XX2, DC=domain, DC=local',
                bindCredentials: 'password',
                searchBase: 'OU=XX1, OU=XX2, DC=domain, DC=local',
                searchFilter: '(sAMAccountName={{username}})',    
               // passReqToCallback : true
              }
    };

  passport.use('ldap-login', new LdapStrategy(opts, function(user, done) {
        console.log("Passport LDAP authentication.");
      done(null, user);
    }

)); 

Hope it will help someone.

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

2 Comments

Glad. I was about to suggest that. I had faced some issue months ago.
I have written an npm module to make it simple. Check out github.com/shaozi/express-passport-ldap-mongoose. You jusst need to call init with the dn, ldapurl, and pass your own user find and upsert function to it.

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.