Search code examples
node.jsmeteorldap

meteorJS LDAP authentication cannot complete a successful bind


Hi i am trying to setup LDAP authentication for my meteorJS app and i am following the steps listed in here https://janikvonrotz.ch/2017/02/08/meteor-register-ldap-login-request-handler/

i changed the search filter from mail to username and pushed everything inside of Meteor.startup() here is my code set up

UI code written in /imports/ui/loginform.jsx

let loginUserWithLDAP = (username, password, callback) => {
        var loginRequest = {
          ldap: true,
          username: username,
          email: username+"@company.com",
          pass: password,
        }
        Accounts.callLoginMethod({
          methodArguments: [loginRequest],
          userCallback: callback
        })
      }

in my /server/ldap.js

Meteor.startup(() => {

    var ldapAuth = {
        url: 'ldap://company.com:389',
        searchOu: 'ou=Employees,ou=\'company Users\', dc=company,dc=com',
        searchQuery: (username) => {
        return {
            filter: '(&(objectclass=user)(samaccountname='+username+'))',
            scope: 'sub'
        }
        }
    }

    ldapAuth.checkAccount = (options) => {
        options = options || {}
        ldapAuth.client = ldap.createClient({
            url: ldapAuth.url
        })
        let dn = ['company', 'com']
        var future = new Future()

        ldapAuth.client.search(
            ldapAuth.searchOu, 
            ldapAuth.searchQuery(options.username),
            (error, result)=> {
                assert.ifError(error)

                result.on('searchEntry', (entry) => {
                    dn.push(entry.objectName)
                    return ldapAuth.profile = {
                        firstname: entry.object.cn,
                        lastname: entry.object.sn
                    }
                })
                
                result.on('error', function(error){
                    throw new Meteor.Error(500, "LDAP server error")
                })

                result.on('end', function(){
                    if (dn.length === 0) {
                        future['return'](false)
                        return false
                    }

                    return ldapAuth.client.bind(dn[0], options.pass, (error) =>{
                        if (error){
                            future['return'](false)
                            return false
                        }

                        return ldapAuth.client.unbind((error) => {
                            assert.ifError(error)
                            return future['return'](!error)

                        });
                    })
                })
            })
        return future.wait()
    }

    Accounts.registerLoginHandler('ldap', (loginRequest)=>{
        if (!loginRequest.ldap) {
            return undefined
        }
    
        if (ldapAuth.checkAccount(loginRequest)){
            var userId = null
            var user = Meteor.users.findOne({"username": loginRequest.username })
            if (!user) {
                userId = Accounts.createUser({
                    username: loginRequest.username,
                    password: loginRequest.pass,
                    profile: ldapAuth.profile,
                    roles: ['user'],
                })
                Meteor.users.update(userId, { $set: { 'emails.0.verified': true } })
            } else {
                userId = user._id
            }
    
            let stampedToken = Accounts._generateStampedLoginToken()
            let hashStampedToken = Accounts._hashStampedToken(stampedToken)
            Meteor.users.update(userId, 
                { $push: {'services.resume.loginTokens': hashStampedToken } }
            )
    
            return {
                userId: userId,
                token: stampedToken.token
            }
        }
    })
});


In my debugging i found that its erroring out at

result.on('error', function(error){
                    throw new Meteor.Error(500, "LDAP server error")
                })

due to '000004DC: LdapErr: DSID-0C0907E9, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580' what does this mean?

What is my code missing?


Solution

  • In short you need to define a search user that does the binding with the LDAP directory.

    The post is outdated, I've got you this example: https://github.com/janikvonrotz/Zenkom/blob/0583f01abca96847178a248ff446d84c754965e9/server/actions/ldap.js#L18

    Setup the search user like this:

    "searchUser": {
        "dn": "CN=username,OU=org,DC=company,DC=ch",
        "password": "password"
      }
    

    The bind user is simply for search the directory. Another bind is executed to authenticate the found user.