ldapauth-fork
Advanced tools
Comparing version 3.0.1 to 4.0.0
# node-ldapauth-fork Changelog | ||
## 4.0.0 | ||
- Added TypeScript types | ||
- Switch to Bunyan logger since ldapjs uses Bunyan as well | ||
- Pass all ldapjs client options to it. The available options were taken from the ldapjs TypeScript types. | ||
## 3.0.1 | ||
@@ -4,0 +10,0 @@ |
@@ -15,3 +15,2 @@ /* | ||
var debug = console.warn; | ||
var assert = require('assert'); | ||
@@ -24,7 +23,7 @@ var LRU = require('lru-cache'); | ||
* | ||
* @param size {Number} Max number of entries to cache. | ||
* @param expiry {Number} Number of seconds after which to expire entries. | ||
* @param log {log4js Logger} Optional. | ||
* All logging is at the Trace level. | ||
* @param name {string} Optional name for this cache. Just used for logging. | ||
* @param {number} size Max number of entries to cache. | ||
* @param {number} expiry Number of seconds after which to expire entries. | ||
* @param {object} log Optional. All logging is at the Trace level. | ||
* @param {string} name Optional name for this cache. Just used for logging. | ||
* @constructor | ||
*/ | ||
@@ -41,7 +40,7 @@ function Cache(size, expiry, log, name) { | ||
// Debugging stuff: .getAll isn't in official lru-cache | ||
//Cache.prototype.getAll = function getAll() { | ||
// return this.items.getAll(); | ||
//} | ||
/** | ||
* Clear cache | ||
* | ||
* @returns {undefined} | ||
*/ | ||
Cache.prototype.reset = function reset() { | ||
@@ -52,4 +51,10 @@ if (this.log) { | ||
this.items.reset(); | ||
} | ||
}; | ||
/** | ||
* Get object from cache by given key | ||
* | ||
* @param {string} key - The cache key | ||
* @returns {*} The cached value or null if not found | ||
*/ | ||
Cache.prototype.get = function get(key) { | ||
@@ -70,4 +75,11 @@ assert.ok(key !== undefined); | ||
return null; | ||
} | ||
}; | ||
/** | ||
* Set a value to cache | ||
* | ||
* @param {string} key - Cache key | ||
* @param {*} value - The value to cache | ||
* @returns {*} The given value | ||
*/ | ||
Cache.prototype.set = function set(key, value) { | ||
@@ -84,4 +96,10 @@ assert.ok(key !== undefined); | ||
return item; | ||
} | ||
}; | ||
/** | ||
* Delete a single entry from cache | ||
* | ||
* @param {string} key - The cache key | ||
* @returns {undefined} | ||
*/ | ||
Cache.prototype.del = function del(key) { | ||
@@ -92,5 +110,5 @@ if (this.log) { | ||
this.items.del(key); | ||
} | ||
}; | ||
module.exports = Cache; |
/** | ||
* Copyright 2011 (c) Trent Mick. | ||
* Modified Work Copyright 2013 Vesa Poikajärvi. | ||
* | ||
@@ -10,10 +11,8 @@ * LDAP auth. | ||
* ... | ||
* auth.authenticate(username, password, function (err, user) { ... }); | ||
* auth.authenticate(username, password, function(err, user) { ... }); | ||
* ... | ||
* auth.close(function (err) { ... }) | ||
* auth.close(function(err) { ... }) | ||
*/ | ||
var assert = require('assert'); | ||
var ldap = require('ldapjs'); | ||
var debug = console.warn; | ||
var format = require('util').format; | ||
@@ -24,4 +23,24 @@ var bcrypt = require('bcryptjs'); | ||
// Get option that may be defined under different names, but accept | ||
// the first one that is actually defined in the given object | ||
/** | ||
* Void callback | ||
* | ||
* @callback voidCallback | ||
* @param {(Error|undefined)} Possible error | ||
*/ | ||
/** | ||
* Result callback | ||
* | ||
* @callback resultCallback | ||
* @param {(Error|undefined)} Possible error | ||
* @param {(Object|undefined)} Result | ||
*/ | ||
/** | ||
* Get option that may be defined under different names, but accept | ||
* the first one that is actually defined in the given object | ||
* | ||
* @param {object} obj - Config options | ||
* @param {string[]} keys - List of keys to look for | ||
* @return {*} The value of the first matching key | ||
*/ | ||
var getOption = function(obj, keys) { | ||
@@ -39,71 +58,4 @@ for (var i = 0; i < keys.length; i++) { | ||
* | ||
* @param opts {Object} Config options. Keys (required, unless says | ||
* otherwise) are: | ||
* url {String} | ||
* E.g. 'ldaps://ldap.example.com:663' | ||
* bindDn {String} | ||
* Optional, e.g. 'uid=myapp,ou=users,o=example.com'. Alias: adminDn | ||
* bindCredentials {String} | ||
* Password for bindDn. Aliases: Credentials, adminPassword | ||
* bindProperty {String} | ||
* Optional, default 'dn'. Property of user to bind against client | ||
* e.g. 'name', 'email' | ||
* searchBase {String} | ||
* The base DN from which to search for users by username. | ||
* E.g. 'ou=users,o=example.com' | ||
* searchScope {String} | ||
* Optional, default 'sub'. Scope of the search, one of 'base', | ||
* 'one', or 'sub'. | ||
* searchFilter {String} | ||
* LDAP search filter with which to find a user by username, e.g. | ||
* '(uid={{username}})'. Use the literal '{{username}}' to have the | ||
* given username be interpolated in for the LDAP search. | ||
* searchAttributes {Array} | ||
* Optional, default all. Array of attributes to fetch from LDAP server. | ||
* groupDnProperty {String} | ||
* Optional, default 'dn'. The property of user object to use in | ||
* '{{dn}}' interpolation of groupSearchFilter. | ||
* groupSearchBase {String} | ||
* Optional. The base DN from which to search for groups. If defined, | ||
* also groupSearchFilter must be defined for the search to work. | ||
* groupSearchScope {String} | ||
* Optional, default 'sub'. | ||
* groupSearchFilter {String | function(User): String } | ||
* Optional. LDAP search filter for groups. The following literals are | ||
* interpolated from the found user object: '{{dn}}' the property | ||
* configured with groupDnProperty. Optionally you can also assign a function instead, | ||
* which passes a user object, from this a dynamic groupsearchfilter can be retrieved. | ||
* groupSearchAttributes {Array} | ||
* Optional, default all. Array of attributes to fetch from LDAP server. | ||
* log4js {Module} | ||
* Optional. The require'd log4js module to use for logging. If given | ||
* this will result in TRACE-level logging for ldapauth. | ||
* verbose {Boolean} | ||
* Optional, default false. If `log4js` is also given, this will add | ||
* TRACE-level logging for ldapjs (quite verbose). | ||
* cache {Boolean} | ||
* Optional, default false. If true, then up to 100 credentials at a | ||
* time will be cached for 5 minutes. | ||
* timeout {Integer} | ||
* Optional, default Infinity. How long the client should let | ||
* operations live for before timing out. | ||
* connectTimeout {Integer} | ||
* Optional, default is up to the OS. How long the client should wait | ||
* before timing out on TCP connections. | ||
* idleTimeout {Integer} | ||
* Optional, milliseconds after last activity before client emits idle event. | ||
* queueDisable {Boolean} | ||
* Optional, disables the queue in LDAPJS making connection requests instantly fail | ||
* instead of sitting in the queue with no timeout. | ||
* tlsOptions {Object} | ||
* Additional options passed to the TLS connection layer when | ||
* connecting via ldaps://. See | ||
* http://nodejs.org/api/tls.html#tls_tls_connect_options_callback | ||
* for available options | ||
* includeRaw {boolean} | ||
* Optional, default false. Set to true to add property '_raw' | ||
* containing the original buffers to the returned user object. | ||
* Useful when you need to handle binary attributes | ||
* reconnect {object} | ||
* Optional, node-ldap reconnect option. | ||
* @param {Object} opts - Config options | ||
* @constructor | ||
*/ | ||
@@ -115,3 +67,3 @@ function LdapAuth(opts) { | ||
this.log = opts.log4js && opts.log4js.getLogger('ldapauth'); | ||
this.log = opts.log && opts.log.child({ component: 'ldapauth' }, true); | ||
@@ -126,21 +78,28 @@ this.opts.searchScope || (this.opts.searchScope = 'sub'); | ||
if (opts.cache) { | ||
// eslint-disable-next-line global-require | ||
var Cache = require('./cache'); | ||
this.userCache = new Cache(100, 300, this.log, 'user'); | ||
this._salt = bcrypt.genSaltSync(); | ||
} | ||
// TODO: This should be fixed somehow | ||
this.clientOpts = { | ||
url: opts.url, | ||
tlsOptions: opts.tlsOptions, | ||
socketPath: opts.socketPath, | ||
log: opts.log, | ||
timeout: opts.timeout, | ||
connectTimeout: opts.connectTimeout, | ||
timeout: opts.timeout, | ||
idleTimeout: opts.idleTimeout, | ||
queueDisable: opts.queueDisable, | ||
tlsOptions: opts.tlsOptions, | ||
bindDn: getOption(opts, ['bindDn', 'adminDn']), | ||
bindCredentials: getOption(opts, ['bindCredentials', 'Credentials', 'adminPassword']), | ||
reconnect: opts.reconnect | ||
reconnect: opts.reconnect, | ||
strictDN: opts.strictDN, | ||
queueSize: opts.queueSize, | ||
queueTimeout: opts.queueTimeout, | ||
queueDisable: opts.queueDisable | ||
}; | ||
if (opts.log4js && opts.verbose) { | ||
this.clientOpts.log4js = opts.log4js; | ||
} | ||
// Not passed to ldapjs, don't want to autobind | ||
// https://github.com/mcavage/node-ldapjs/blob/v1.0.1/lib/client/client.js#L343-L356 | ||
this.bindDN = getOption(opts, ['bindDn', 'bindDN', 'adminDn']); | ||
this.bindCredentials = getOption(opts, ['bindCredentials', 'Credentials', 'adminPassword']); | ||
@@ -154,6 +113,2 @@ this._adminClient = ldap.createClient(this.clientOpts); | ||
if (opts.cache) { | ||
this._salt = bcrypt.genSaltSync(); | ||
} | ||
if (opts.groupSearchBase && opts.groupSearchFilter) { | ||
@@ -171,14 +126,21 @@ if (typeof opts.groupSearchFilter === 'string') { | ||
// the authenticate function to have cache set up. | ||
this._getGroups = function (user, callback) { | ||
this._getGroups = function(user, callback) { | ||
return callback(null, user); | ||
} | ||
}; | ||
} | ||
}; | ||
} | ||
inherits(LdapAuth, EventEmitter); | ||
LdapAuth.prototype.close = function (callback) { | ||
/** | ||
* Unbind connections | ||
* | ||
* @param {errorCallback} callback - Callback | ||
* @returns {undefined} | ||
*/ | ||
LdapAuth.prototype.close = function(callback) { | ||
var self = this; | ||
// It seems to be OK just to call unbind regardless of if the | ||
// client has been bound (e.g. how ldapjs pool destroy does) | ||
self._adminClient.unbind(function(err) { | ||
self._adminClient.unbind(function() { | ||
self._userClient.unbind(callback); | ||
@@ -191,2 +153,5 @@ }); | ||
* Mark admin client unbound so reconnect works as expected and re-emit the error | ||
* | ||
* @param {Error} err - The error to be logged and emitted | ||
* @returns {undefined} | ||
*/ | ||
@@ -201,6 +166,9 @@ LdapAuth.prototype._handleError = function(err) { | ||
* Ensure that `this._adminClient` is bound. | ||
* | ||
* @param {voidCallback} callback - Callback that checks possible error | ||
* @returns {undefined} | ||
*/ | ||
LdapAuth.prototype._adminBind = function (callback) { | ||
LdapAuth.prototype._adminBind = function(callback) { | ||
// Anonymous binding | ||
if (typeof this.clientOpts.bindDn === 'undefined' || this.clientOpts.bindDn === null) { | ||
if (typeof this.bindDN === 'undefined' || this.bindDN === null) { | ||
return callback(); | ||
@@ -212,11 +180,14 @@ } | ||
var self = this; | ||
this._adminClient.bind(this.clientOpts.bindDn, this.clientOpts.bindCredentials, | ||
function (err) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: bind error: %s', err); | ||
return callback(err); | ||
this._adminClient.bind( | ||
this.bindDN, | ||
this.bindCredentials, | ||
function(err) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: bind error: %s', err); | ||
return callback(err); | ||
} | ||
self._adminBound = true; | ||
return callback(); | ||
} | ||
self._adminBound = true; | ||
return callback(); | ||
}); | ||
); | ||
}; | ||
@@ -228,19 +199,25 @@ | ||
* | ||
* @param searchBase {String} LDAP search base | ||
* @param options {Object} LDAP search options | ||
* @param {Function} `function (err, result)`. | ||
* @param {string} searchBase - LDAP search base | ||
* @param {Object} options - LDAP search options | ||
* @param {string} options.filter - LDAP search filter | ||
* @param {string} options.scope - LDAP search scope | ||
* @param {(string[]|undefined)} options.attributes - Attributes to fetch | ||
* @param {resultCallback} callback - The result handler callback | ||
* @returns {undefined} | ||
*/ | ||
LdapAuth.prototype._search = function (searchBase, options, callback) { | ||
LdapAuth.prototype._search = function(searchBase, options, callback) { | ||
var self = this; | ||
self._adminBind(function (err) { | ||
if (err) | ||
return callback(err); | ||
self._adminBind(function(bindErr) { | ||
if (bindErr) { | ||
return callback(bindErr); | ||
} | ||
self._adminClient.search(searchBase, options, function (err, result) { | ||
if (err) | ||
return callback(err); | ||
self._adminClient.search(searchBase, options, function(searchErr, searchResult) { | ||
if (searchErr) { | ||
return callback(searchErr); | ||
} | ||
var items = []; | ||
result.on('searchEntry', function (entry) { | ||
searchResult.on('searchEntry', function(entry) { | ||
items.push(entry.object); | ||
@@ -252,5 +229,5 @@ if (self.opts.includeRaw === true) { | ||
result.on('error', callback); | ||
searchResult.on('error', callback); | ||
result.on('end', function (result) { | ||
searchResult.on('end', function(result) { | ||
if (result.status !== 0) { | ||
@@ -266,5 +243,12 @@ var err = 'non-zero status from LDAP search: ' + result.status; | ||
// https://tools.ietf.org/search/rfc4515#section-3 | ||
var sanitizeInput = function (username) { | ||
return username | ||
/** | ||
* Sanitize LDAP special characters from input | ||
* | ||
* {@link https://tools.ietf.org/search/rfc4515#section-3} | ||
* | ||
* @param {string} input - String to sanitize | ||
* @returns {string} Sanitized string | ||
*/ | ||
var sanitizeInput = function(input) { | ||
return input | ||
.replace(/\*/g, '\\2a') | ||
@@ -281,15 +265,15 @@ .replace(/\(/g, '\\28') | ||
* | ||
* @param username {String} | ||
* @param callback {Function} `function (err, user)`. If no such user is | ||
* found but no error processing, then `user` is undefined. | ||
* | ||
* @param {string} username - Username to search for | ||
* @param {resultCallback} callback - Result handling callback. If user is | ||
* not found but no error happened, result is undefined. | ||
* @returns {undefined} | ||
*/ | ||
LdapAuth.prototype._findUser = function (username, callback) { | ||
LdapAuth.prototype._findUser = function(username, callback) { | ||
var self = this; | ||
if (!username) { | ||
return callback("empty username"); | ||
return callback(new Error('empty username')); | ||
} | ||
var searchFilter = self.opts.searchFilter.replace(/{{username}}/g, sanitizeInput(username)); | ||
var opts = {filter: searchFilter, scope: self.opts.searchScope}; | ||
var opts = { filter: searchFilter, scope: self.opts.searchScope }; | ||
if (self.opts.searchAttributes) { | ||
@@ -299,3 +283,3 @@ opts.attributes = self.opts.searchAttributes; | ||
self._search(self.opts.searchBase, opts, function (err, result) { | ||
self._search(self.opts.searchBase, opts, function(err, result) { | ||
if (err) { | ||
@@ -310,3 +294,3 @@ self.log && self.log.trace('ldap authenticate: user search error: %s %s %s', err.code, err.name, err.message); | ||
case 1: | ||
return callback(null, result[0]) | ||
return callback(null, result[0]); | ||
default: | ||
@@ -320,6 +304,13 @@ return callback(format( | ||
/** | ||
* Find groups for given user | ||
* | ||
* @param {Object} user - The LDAP user object | ||
* @param {resultCallback} callback - Result handling callback | ||
* @returns {undefined} | ||
*/ | ||
LdapAuth.prototype._findGroups = function(user, callback) { | ||
var self = this; | ||
if (!user) { | ||
return callback("no user"); | ||
return callback(new Error('no user')); | ||
} | ||
@@ -329,7 +320,7 @@ | ||
var opts = {filter: searchFilter, scope: self.opts.groupSearchScope}; | ||
var opts = { filter: searchFilter, scope: self.opts.groupSearchScope }; | ||
if (self.opts.groupSearchAttributes) { | ||
opts.attributes = self.opts.groupSearchAttributes; | ||
} | ||
self._search(self.opts.groupSearchBase, opts, function (err, result) { | ||
self._search(self.opts.groupSearchBase, opts, function(err, result) { | ||
if (err) { | ||
@@ -346,9 +337,14 @@ self.log && self.log.trace('ldap authenticate: group search error: %s %s %s', err.code, err.name, err.message); | ||
/** | ||
* Authenticate given credentials against LDAP server | ||
* | ||
* @param {string} username - The username to authenticate | ||
* @param {string} password - The password to verify | ||
* @param {resultCallbac} callback - Result handling callback | ||
* @returns {undefined} | ||
*/ | ||
LdapAuth.prototype.authenticate = function (username, password, callback) { | ||
LdapAuth.prototype.authenticate = function(username, password, callback) { | ||
var self = this; | ||
if (typeof password === 'undefined' || password === null || password === '') { | ||
return callback('no password given'); | ||
return callback(new Error('no password given')); | ||
} | ||
@@ -360,3 +356,3 @@ | ||
if (cached && bcrypt.compareSync(password, cached.password)) { | ||
return callback(null, cached.user) | ||
return callback(null, cached.user); | ||
} | ||
@@ -366,29 +362,34 @@ } | ||
// 1. Find the user DN in question. | ||
self._findUser(username, function (err, user) { | ||
if (err) | ||
return callback(err); | ||
if (!user) | ||
self._findUser(username, function(findErr, user) { | ||
if (findErr) { | ||
return callback(findErr); | ||
} else if (!user) { | ||
return callback(format('no such user: "%s"', username)); | ||
} | ||
// 2. Attempt to bind as that user to check password. | ||
self._userClient.bind(user[self.opts.bindProperty], password, function (err) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: bind error: %s', err); | ||
return callback(err); | ||
self._userClient.bind(user[self.opts.bindProperty], password, function(bindErr) { | ||
if (bindErr) { | ||
self.log && self.log.trace('ldap authenticate: bind error: %s', bindErr); | ||
return callback(bindErr); | ||
} | ||
// 3. If requested, fetch user groups | ||
self._getGroups(user, function(err, user) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: group search error %s', err); | ||
return callback(err); | ||
self._getGroups(user, function(groupErr, userWithGroups) { | ||
if (groupErr) { | ||
self.log && self.log.trace('ldap authenticate: group search error %s', groupErr); | ||
return callback(groupErr); | ||
} | ||
if (self.opts.cache) { | ||
bcrypt.hash(password, self._salt, function (err, hash) { | ||
self.userCache.set(username, {password: hash, user: user}); | ||
return callback(null, user); | ||
bcrypt.hash(password, self._salt, function(err, hash) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: bcrypt error, not caching %s', err); | ||
} else { | ||
self.userCache.set(username, { password: hash, user: userWithGroups }); | ||
} | ||
return callback(null, userWithGroups); | ||
}); | ||
} else { | ||
return callback(null, user); | ||
return callback(null, userWithGroups); | ||
} | ||
}) | ||
}); | ||
}); | ||
@@ -395,0 +396,0 @@ }); |
{ | ||
"name": "ldapauth-fork", | ||
"version": "3.0.1", | ||
"version": "4.0.0", | ||
"main": "./lib/ldapauth.js", | ||
"types": "./lib/ldapauth.d.ts", | ||
"description": "Authenticate against an LDAP server", | ||
@@ -18,10 +19,26 @@ "author": "Vesa Poikajärvi <vesa.poikajarvi@iki.fi>", | ||
}, | ||
"engines": [ | ||
"node >=0.8.0" | ||
], | ||
"engines": { | ||
"node": ">=0.8.0" | ||
}, | ||
"scripts": { | ||
"prepublish": "npm run lint", | ||
"lint": "eslint ./lib", | ||
"lint:watch": "watch 'npm run lint' ./lib --wait 0.5", | ||
"pretest": "cd test && tsc", | ||
"test": "cd test && node test.js" | ||
}, | ||
"dependencies": { | ||
"bcryptjs": "2.4.0", | ||
"ldapjs": "~1.0.1", | ||
"lru-cache": "4.0.2" | ||
"@types/ldapjs": "^1.0.0", | ||
"@types/node": "^7.0.21", | ||
"bcryptjs": "^2.4.0", | ||
"ldapjs": "^1.0.1", | ||
"lru-cache": "^4.0.2" | ||
}, | ||
"devDependencies": { | ||
"@types/bunyan": "0.0.36", | ||
"bunyan": "^1.8.10", | ||
"eslint": "^3.19.0", | ||
"typescript": "^2.3.3", | ||
"watch": "^1.0.2" | ||
} | ||
} |
@@ -18,3 +18,3 @@ # ldapauth-fork | ||
var options = { | ||
url: 'ldaps://ldap.example.com:636', | ||
url: 'ldaps://ldap.example.org:636', | ||
... | ||
@@ -32,2 +32,4 @@ }; | ||
`LdapAuth` inherits from `EventEmitter`. | ||
## Install | ||
@@ -37,13 +39,54 @@ | ||
## `LdapAuth` Config Options | ||
## License | ||
Required ldapjs client options: | ||
MIT. See "LICENSE" file. | ||
- `url` - LDAP server URL, eg. *ldaps://ldap.example.org:663* | ||
ldapauth-fork options: | ||
## `LdapAuth` Config Options | ||
- `bindDN` - Admin connection DN, e.g. *uid=myapp,ou=users,dc=example,dc=org*. Optional. If not given at all, admin client is not bound. Giving empty string may result in anonymous bind when allowed. | ||
- `bindCredentials` - Password for bindDN. | ||
- `searchBase` - The base DN from which to search for users by username. E.g. *ou=users,dc=example,dc=org* | ||
- `searchFilter` - LDAP search filter with which to find a user by username, e.g. *(uid={{username}})*. Use the literal *{{username}}* to have the given username interpolated in for the LDAP search. | ||
- `searchAttributes` - Optional, default all. Array of attributes to fetch from LDAP server. | ||
- `bindProperty` - Optional, default *dn*. Property of the LDAP user object to use when binding to verify the password. E.g. *name*, *email* | ||
- `searchScope` - Optional, default *sub*. Scope of the search, one of *base*, *one*, or *sub*. | ||
[Use the source Luke](https://github.com/vesse/node-ldapauth-fork/blob/master/lib/ldapauth.js#L35-L99) | ||
ldapauth-fork can look for valid users groups too. Related options: | ||
- `groupSearchBase` - Optional. The base DN from which to search for groups. If defined, also `groupSearchFilter` must be defined for the search to work. | ||
- `groupSearchFilter` - Optional. LDAP search filter for groups. Place literal *{{dn}}* in the filter to have it replaced by the property defined with `groupDnProperty` of the found user object. Optionally you can also assign a function instead. The found user is passed to the function and it should return a valid search filter for the group search. | ||
- `groupSearchAttributes` - Optional, default all. Array of attributes to fetch from LDAP server. | ||
- `groupDnProperty` - Optional, default *dn*. The property of user object to use in *{{dn}}* interpolation of `groupSearchFilter`. | ||
- `groupSearchScope` - Optional, default *sub*. | ||
Other ldapauth-fork options: | ||
- `includeRaw` - Optional, default false. Set to true to add property `_raw` containing the original buffers to the returned user object. Useful when you need to handle binary attributes | ||
- `cache` - Optional, default false. If true, then up to 100 credentials at a time will be cached for 5 minutes. | ||
- `log` - Bunyan logger instance, optional. If given this will result in TRACE-level error logging for component:ldapauth. The logger is also passed forward to ldapjs. | ||
Optional ldapjs options, see [ldapjs documentation](https://github.com/mcavage/node-ldapjs/blob/v1.0.1/docs/client.md): | ||
- `tlsOptions` - Needed for TLS connection. See [Node.js documentation](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback) | ||
- `socketPath` | ||
- `timeout` | ||
- `connectTimeout` | ||
- `idleTimeout` | ||
- `reconnect` | ||
- `strictDN` | ||
- `queueSize` | ||
- `queueTimeout` | ||
- `queueDisable` | ||
## How it works | ||
The LDAP authentication flow is usually: | ||
1. Bind the admin client using the given `bindDN` and `bindCredentials` | ||
2. Use the admin client to search for the user by substituting `{{username}}` from the `searchFilter` with given username | ||
3. If user is found, verify the given password by trying to bind the user client with the found LDAP user object and given password | ||
4. If password was correct and group search options were provided, search for the groups of the user | ||
## express/connect basicAuth example | ||
@@ -56,7 +99,7 @@ | ||
var ldap = new LdapAuth({ | ||
url: "ldaps://ldap.example.com:636", | ||
bindDn: "uid=myadminusername,ou=users,o=example.com", | ||
bindCredentials: "mypassword", | ||
searchBase: "ou=users,o=example.com", | ||
searchFilter: "(uid={{username}})", | ||
url: 'ldaps://ldap.example.org:636', | ||
bindDN: 'uid=myadminusername,ou=users,dc=example,dc=org', | ||
bindCredentials: 'mypassword', | ||
searchBase: 'ou=users,dc=example,dc=org', | ||
searchFilter: '(uid={{username}})', | ||
reconnect: true | ||
@@ -88,2 +131,6 @@ }); | ||
## License | ||
MIT | ||
`ldapauth-fork` has been partially sponsored by [Leonidas Ltd](https://leonidasoy.fi/opensource). |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
0
100
753
132
35811
5
5
14
1
+ Added@types/ldapjs@^1.0.0
+ Added@types/node@^7.0.21
+ Added@types/ldapjs@1.0.11(transitive)
+ Added@types/node@7.10.14(transitive)
+ Addedbcryptjs@2.4.3(transitive)
+ Addedlru-cache@4.1.5(transitive)
- Removedbcryptjs@2.4.0(transitive)
- Removedlru-cache@4.0.2(transitive)
Updatedbcryptjs@^2.4.0
Updatedldapjs@^1.0.1
Updatedlru-cache@^4.0.2