Skip to content

Commit

Permalink
init version
Browse files Browse the repository at this point in the history
  • Loading branch information
shaozi committed Jan 6, 2020
0 parents commit d7f19b9
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# A simple library that authenticates a user against an LDAP/AD server

## Features:

* Can use an admin to authenticate a user
* Can also use a regular user and authenticate the user itself
* Support ldap STARTTLS

127 changes: 127 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
const assert = require('assert')
const ldap = require('ldapjs')

// bind and return the ldap client
function _ldapBind(dn, password, starttls, ldapOpts) {
return new Promise(function (resolve, reject) {
var client = ldap.createClient(ldapOpts)
if (starttls) {
client.starttls(ldapOpts.tlsOptions, null, function (error) {
if (error) {
reject(error.message)
return
}
client.bind(dn, password, function (err) {
if (err) {
reject(err.message)
client.unbind()
return
}
ldapOpts.log && ldapOpts.log.trace('bind success!')
resolve(client)
})
})
} else {
client.bind(dn, password, function (err) {
if (err) {
reject(err.message)
client.unbind()
return
}
ldapOpts.log && ldapOpts.log.trace('bind success!')
resolve(client)
})
}
})
}

// search a user and return the object
async function _searchUser(ldapClient, searchBase, usernameFilter) {
return new Promise(function (resolve, reject) {
ldapClient.search(searchBase, {
filter: usernameFilter,
scope: 'sub'
}, function (err, res) {
var user = null
if (err) {
reject(err.message)
ldapClient.unbind()
return
}
res.on('searchEntry', function (entry) {
user = entry.object
});
res.on('searchReference', function (referral) {
console.log('referral: ' + referral.uris.join());
});
res.on('error', function (err) {
console.error('error: ' + err.message);
reject(err.message)
ldapClient.unbind()
});
res.on('end', function (result) {
if (result.status != 0) {
reject('search failed')
} else {
//console.error('status = 0' + result);
resolve(user)
}
ldapClient.unbind()
})
})
})
}

async function authenticateWithAdmin(adminDn, adminPassword, userSearchBase, userSearchString, userPassword, starttls, ldapOpts) {
var ldapAdminClient = await _ldapBind(adminDn, adminPassword, starttls, ldapOpts)
var user = await _searchUser(ldapAdminClient, userSearchBase, userSearchString)
ldapAdminClient.unbind()
if (!user || !user.dn) {
throw new Error('user not found or userSearchString is wrong')
}
var userDn = user.dn
let ldapUserClient = await _ldapBind(userDn, userPassword, starttls, ldapOpts)
ldapUserClient.unbind()
return user
}

async function authenticateWithUser(userDn, userSearchBase, userSearchString, userPassword, starttls, ldapOpts) {
let ldapUserClient = await _ldapBind(userDn, userPassword, starttls, ldapOpts)
var user = await _searchUser(ldapUserClient, userSearchBase, userSearchString)
if (!user || !user.dn) {
throw new Error('user not found')
}
ldapUserClient.unbind()
return user
}

async function authenticate(options) {
assert(options.userSearchBase, 'userSearchBase must be provided')
assert(options.userSearchString, 'userSearchString must be provided')
assert(options.userPassword, 'userPassword must be provided')
assert(options.ldapOpts && options.ldapOpts.url, 'ldapOpts.url must be provided')
if (options.adminDn) {
assert(options.adminPassword, 'adminDn and adminPassword must be both provided.')
return await authenticateWithAdmin(
options.adminDn,
options.adminPassword,
options.userSearchBase,
options.userSearchString,
options.userPassword,
options.starttls,
options.ldapOpts
)
}
assert(options.userDn, 'adminDn/adminPassword OR userDn must be provided')
return await authenticateWithUser(
options.userDn,
options.userSearchBase,
options.userSearchString,
options.userPassword,
options.starttls,
options.ldapOpts
)
}

module.exports.authenticate = authenticate

0 comments on commit d7f19b9

Please sign in to comment.