ldapauth-fork
Advanced tools
Comparing version 5.0.4 to 5.0.5
@@ -5,35 +5,35 @@ # node-ldapauth-fork Changelog | ||
- [pull request #99] Ensure `groupDnProperty` is included in `attributes` | ||
- [pull request #99] Ensure `groupDnProperty` is included in `attributes` | ||
## 5.0.2 | ||
- [pull request #97] Sanitize group search filters | ||
- [pull request #97] Sanitize group search filters | ||
## 5.0.0 | ||
- Update `ldapjs` to version 2 | ||
- Update `ldapjs` to version 2 | ||
## 4.3.3 | ||
- [pull request #86] Fix typedef of tlsOptions | ||
- [pull request #86] Fix typedef of tlsOptions | ||
## 4.3.2 | ||
- [pull request #83] Allow any @types/node version | ||
- [pull request #83] Allow any @types/node version | ||
## 4.3.0 | ||
- [issue #59, pull request #80] Add starttls | ||
- [issue #59, pull request #80] Add starttls | ||
## 4.2.0 | ||
- [issue #69, pull request #71] Defer installation of reconnect event listener | ||
- [issue #69, pull request #71] Defer installation of reconnect event listener | ||
## 4.1.1 | ||
- [issue #74] Remove direct moment.js dependency | ||
- [issue #74] Remove direct moment.js dependency | ||
## 4.1.0 | ||
- [pull request #68] Rebind admin client after reconnect | ||
- [pull request #68] Rebind admin client after reconnect | ||
@@ -104,13 +104,11 @@ ## 4.0.2 | ||
new LdapAuth({ | ||
"url": "ldaps://ldap.example.com:636", | ||
"adminDn": "cn=LdapAdmin,dc=local", | ||
"adminPassword": "LdapAdminPassword", | ||
"searchBase": "dc=users,dc=local", | ||
"searchFilter": "(&(objectClass=person)(sAMAccountName={{username}}))", | ||
"searchAttributes": [ | ||
"dn", "cn", "givenName", "name", "memberOf", "sAMAccountName" | ||
], | ||
"groupSearchBase": "dc=groups,dc=local", | ||
"groupSearchFilter": "(member={{dn}})", | ||
"groupSearchAttributes": ["dn", "cn", "sAMAccountName"] | ||
url: 'ldaps://ldap.example.com:636', | ||
adminDn: 'cn=LdapAdmin,dc=local', | ||
adminPassword: 'LdapAdminPassword', | ||
searchBase: 'dc=users,dc=local', | ||
searchFilter: '(&(objectClass=person)(sAMAccountName={{username}}))', | ||
searchAttributes: ['dn', 'cn', 'givenName', 'name', 'memberOf', 'sAMAccountName'], | ||
groupSearchBase: 'dc=groups,dc=local', | ||
groupSearchFilter: '(member={{dn}})', | ||
groupSearchAttributes: ['dn', 'cn', 'sAMAccountName'], | ||
}); | ||
@@ -189,3 +187,2 @@ ``` | ||
## 2.2.2 | ||
@@ -195,3 +192,2 @@ | ||
## 2.2.1 | ||
@@ -202,3 +198,2 @@ | ||
## 2.2.0 | ||
@@ -210,3 +205,2 @@ | ||
## 2.1.0 | ||
@@ -216,3 +210,2 @@ | ||
## 2.0.0 | ||
@@ -224,7 +217,4 @@ | ||
## 1.0.2 | ||
First working version. | ||
@@ -18,3 +18,2 @@ /* | ||
/** | ||
@@ -35,3 +34,3 @@ * A LRU and expiring cache. | ||
this.log = log; | ||
this.name = (name ? name + ' ' : ''); | ||
this.name = name ? name + ' ' : ''; | ||
this.items = new LRU({ max: this.size }); | ||
@@ -62,3 +61,3 @@ } | ||
if (cached) { | ||
if (((new Date()).getTime() - cached.ctime) <= this.expiry) { | ||
if (new Date().getTime() - cached.ctime <= this.expiry) { | ||
if (this.log) { | ||
@@ -87,3 +86,3 @@ this.log.trace('%scache hit: key="%s": %o', this.name, key, cached); | ||
value: value, | ||
ctime: new Date().getTime() | ||
ctime: new Date().getTime(), | ||
}; | ||
@@ -110,3 +109,2 @@ if (this.log) { | ||
module.exports = Cache; |
@@ -13,131 +13,131 @@ // Type definitions for ldapauth-fork 4.0 | ||
declare namespace LdapAuth { | ||
type Scope = 'base' | 'one' | 'sub'; | ||
type Scope = 'base' | 'one' | 'sub'; | ||
interface Callback { | ||
(error: Error|string, result?: any): void; | ||
} | ||
interface Callback { | ||
(error: Error | string, result?: any): void; | ||
} | ||
interface GroupSearchFilterFunction { | ||
/** | ||
* Construct a group search filter from user object | ||
* | ||
* @param user The user retrieved and authenticated from LDAP | ||
*/ | ||
(user: any): string; | ||
} | ||
interface GroupSearchFilterFunction { | ||
/** | ||
* Construct a group search filter from user object | ||
* | ||
* @param user The user retrieved and authenticated from LDAP | ||
*/ | ||
(user: any): string; | ||
} | ||
interface Options extends ClientOptions { | ||
/** | ||
* Admin connection DN, e.g. uid=myapp,ou=users,dc=example,dc=org. | ||
* If not given at all, admin client is not bound. Giving empty | ||
* string may result in anonymous bind when allowed. | ||
* | ||
* Note: Not passed to ldapjs, it would bind automatically | ||
*/ | ||
bindDN?: string; | ||
/** | ||
* Password for bindDN | ||
*/ | ||
bindCredentials?: string; | ||
/** | ||
* The base DN from which to search for users by username. | ||
* E.g. ou=users,dc=example,dc=org | ||
*/ | ||
searchBase: 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 interpolated in for the LDAP search. | ||
*/ | ||
searchFilter: string; | ||
/** | ||
* Scope of the search. Default: 'sub' | ||
*/ | ||
searchScope?: Scope; | ||
/** | ||
* Array of attributes to fetch from LDAP server. Default: all | ||
*/ | ||
searchAttributes?: string[]; | ||
interface Options extends ClientOptions { | ||
/** | ||
* Admin connection DN, e.g. uid=myapp,ou=users,dc=example,dc=org. | ||
* If not given at all, admin client is not bound. Giving empty | ||
* string may result in anonymous bind when allowed. | ||
* | ||
* Note: Not passed to ldapjs, it would bind automatically | ||
*/ | ||
bindDN?: string; | ||
/** | ||
* Password for bindDN | ||
*/ | ||
bindCredentials?: string; | ||
/** | ||
* The base DN from which to search for users by username. | ||
* E.g. ou=users,dc=example,dc=org | ||
*/ | ||
searchBase: 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 interpolated in for the LDAP search. | ||
*/ | ||
searchFilter: string; | ||
/** | ||
* Scope of the search. Default: 'sub' | ||
*/ | ||
searchScope?: Scope; | ||
/** | ||
* Array of attributes to fetch from LDAP server. Default: all | ||
*/ | ||
searchAttributes?: string[]; | ||
/** | ||
* The base DN from which to search for groups. If defined, | ||
* also groupSearchFilter must be defined for the search to work. | ||
*/ | ||
groupSearchBase?: string; | ||
/** | ||
* 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. | ||
*/ | ||
groupSearchFilter?: string | GroupSearchFilterFunction; | ||
/** | ||
* Scope of the search. Default: sub | ||
*/ | ||
groupSearchScope?: Scope; | ||
/** | ||
* Array of attributes to fetch from LDAP server. Default: all | ||
*/ | ||
groupSearchAttributes?: string[]; | ||
/** | ||
* The base DN from which to search for groups. If defined, | ||
* also groupSearchFilter must be defined for the search to work. | ||
*/ | ||
groupSearchBase?: string; | ||
/** | ||
* 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. | ||
*/ | ||
groupSearchFilter?: string | GroupSearchFilterFunction; | ||
/** | ||
* Scope of the search. Default: sub | ||
*/ | ||
groupSearchScope?: Scope; | ||
/** | ||
* Array of attributes to fetch from LDAP server. Default: all | ||
*/ | ||
groupSearchAttributes?: string[]; | ||
/** | ||
* Property of the LDAP user object to use when binding to verify | ||
* the password. E.g. name, email. Default: dn | ||
*/ | ||
bindProperty?: string; | ||
/** | ||
* The property of user object to use in '{{dn}}' interpolation of | ||
* groupSearchFilter. Default: 'dn' | ||
*/ | ||
groupDnProperty?: string; | ||
/** | ||
* Property of the LDAP user object to use when binding to verify | ||
* the password. E.g. name, email. Default: dn | ||
*/ | ||
bindProperty?: string; | ||
/** | ||
* The property of user object to use in '{{dn}}' interpolation of | ||
* groupSearchFilter. Default: 'dn' | ||
*/ | ||
groupDnProperty?: string; | ||
/** | ||
* Set to true to add property '_raw' containing the original buffers | ||
* to the returned user object. Useful when you need to handle binary | ||
* attributes | ||
*/ | ||
includeRaw?: boolean; | ||
/** | ||
* If true, then up to 100 credentials at a time will be cached for | ||
* 5 minutes. | ||
*/ | ||
cache?: boolean; | ||
/** | ||
* If true, then intialize TLS using the starttls mechanism. | ||
*/ | ||
starttls?: boolean; | ||
/** | ||
* Provides the secure TLS options passed to tls.connect in ldapjs | ||
*/ | ||
tlsOptions?: ConnectionOptions; | ||
} | ||
} | ||
declare class LdapAuth extends EventEmitter { | ||
/** | ||
* @constructor | ||
* @param opts | ||
* Set to true to add property '_raw' containing the original buffers | ||
* to the returned user object. Useful when you need to handle binary | ||
* attributes | ||
*/ | ||
constructor(opts: LdapAuth.Options); | ||
includeRaw?: boolean; | ||
/** | ||
* Authenticate against LDAP server with given credentials | ||
* | ||
* @param username Username | ||
* @param password Password | ||
* @param callback Standard callback | ||
* If true, then up to 100 credentials at a time will be cached for | ||
* 5 minutes. | ||
*/ | ||
authenticate(username: string, password: string, callback: LdapAuth.Callback): void; | ||
cache?: boolean; | ||
/** | ||
* Unbind both admin and client connections | ||
* | ||
* @param callback Error callback | ||
* If true, then intialize TLS using the starttls mechanism. | ||
*/ | ||
close(callback?: ErrorCallback): void; | ||
starttls?: boolean; | ||
/** | ||
* Provides the secure TLS options passed to tls.connect in ldapjs | ||
*/ | ||
tlsOptions?: ConnectionOptions; | ||
} | ||
} | ||
declare class LdapAuth extends EventEmitter { | ||
/** | ||
* @constructor | ||
* @param opts | ||
*/ | ||
constructor(opts: LdapAuth.Options); | ||
/** | ||
* Authenticate against LDAP server with given credentials | ||
* | ||
* @param username Username | ||
* @param password Password | ||
* @param callback Standard callback | ||
*/ | ||
authenticate(username: string, password: string, callback: LdapAuth.Callback): void; | ||
/** | ||
* Unbind both admin and client connections | ||
* | ||
* @param callback Error callback | ||
*/ | ||
close(callback?: ErrorCallback): void; | ||
} | ||
export = LdapAuth; |
@@ -22,3 +22,2 @@ var assert = require('assert'); | ||
/** | ||
@@ -47,3 +46,3 @@ * Void callback | ||
*/ | ||
var getOption = function(obj, keys) { | ||
var getOption = function (obj, keys) { | ||
for (var i = 0; i < keys.length; i++) { | ||
@@ -66,3 +65,3 @@ if (keys[i] in obj) { | ||
*/ | ||
var sanitizeInput = function(input) { | ||
var sanitizeInput = function (input) { | ||
return input | ||
@@ -117,3 +116,3 @@ .replace(/\*/g, '\\2a') | ||
queueTimeout: opts.queueTimeout, | ||
queueDisable: opts.queueDisable | ||
queueDisable: opts.queueDisable, | ||
}; | ||
@@ -136,3 +135,3 @@ | ||
// When starttls is enabled, this callback supplants the 'connect' callback | ||
this._adminClient.starttls(this.opts.tlsOptions, this._adminClient.controls, function(err) { | ||
this._adminClient.starttls(this.opts.tlsOptions, this._adminClient.controls, function (err) { | ||
if (err) { | ||
@@ -144,3 +143,3 @@ self._handleError(err); | ||
}); | ||
this._userClient.starttls(this.opts.tlsOptions, this._userClient.controls, function(err) { | ||
this._userClient.starttls(this.opts.tlsOptions, this._userClient.controls, function (err) { | ||
if (err) { | ||
@@ -151,5 +150,5 @@ self._handleError(err); | ||
} else if (opts.reconnect) { | ||
this.once('_installReconnectListener', function() { | ||
this.once('_installReconnectListener', function () { | ||
self.log && self.log.trace('install reconnect listener'); | ||
self._adminClient.on('connect', function() { | ||
self._adminClient.on('connect', function () { | ||
self._onConnectAdmin(); | ||
@@ -166,3 +165,3 @@ }); | ||
var groupSearchFilter = opts.groupSearchFilter; | ||
opts.groupSearchFilter = function(user) { | ||
opts.groupSearchFilter = function (user) { | ||
return groupSearchFilter | ||
@@ -178,3 +177,3 @@ .replace(/{{dn}}/g, sanitizeInput(user[opts.groupDnProperty] || '')) | ||
// the authenticate function to have cache set up. | ||
this._getGroups = function(user, callback) { | ||
this._getGroups = function (user, callback) { | ||
return callback(null, user); | ||
@@ -193,7 +192,7 @@ }; | ||
*/ | ||
LdapAuth.prototype.close = function(callback) { | ||
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() { | ||
self._adminClient.unbind(function () { | ||
self._userClient.unbind(callback); | ||
@@ -203,3 +202,2 @@ }); | ||
/** | ||
@@ -212,3 +210,3 @@ * Mark admin client unbound so reconnect works as expected and re-emit the error | ||
*/ | ||
LdapAuth.prototype._handleError = function(err) { | ||
LdapAuth.prototype._handleError = function (err) { | ||
this.log && this.log.trace('ldap emitted error: %s', err); | ||
@@ -226,3 +224,3 @@ this._adminBound = false; | ||
*/ | ||
LdapAuth.prototype._onConnectAdmin = function(callback) { | ||
LdapAuth.prototype._onConnectAdmin = function (callback) { | ||
var self = this; | ||
@@ -237,19 +235,16 @@ | ||
self.log && self.log.trace('ldap authenticate: bind: %s', self.bindDN); | ||
self._adminClient.bind( | ||
self.bindDN, | ||
self.bindCredentials, | ||
function(err) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: bind error: %s', err); | ||
self._adminBound = false; | ||
return callback ? callback(err) : null; | ||
} | ||
self._adminClient.bind(self.bindDN, self.bindCredentials, function (err) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: bind error: %s', err); | ||
self._adminBound = false; | ||
return callback ? callback(err) : null; | ||
} | ||
self.log && self.log.trace('ldap authenticate: bind ok'); | ||
self._adminBound = true; | ||
if (self.opts.reconnect) { | ||
self.emit('_installReconnectListener'); | ||
} | ||
return callback ? callback() : null; | ||
}); | ||
self.log && self.log.trace('ldap authenticate: bind ok'); | ||
self._adminBound = true; | ||
if (self.opts.reconnect) { | ||
self.emit('_installReconnectListener'); | ||
} | ||
return callback ? callback() : null; | ||
}); | ||
}; | ||
@@ -264,3 +259,3 @@ | ||
*/ | ||
LdapAuth.prototype._adminBind = function(callback) { | ||
LdapAuth.prototype._adminBind = function (callback) { | ||
if (this._adminBound) { | ||
@@ -287,6 +282,6 @@ return callback(); | ||
*/ | ||
LdapAuth.prototype._search = function(searchBase, options, callback) { | ||
LdapAuth.prototype._search = function (searchBase, options, callback) { | ||
var self = this; | ||
self._adminBind(function(bindErr) { | ||
self._adminBind(function (bindErr) { | ||
if (bindErr) { | ||
@@ -296,3 +291,3 @@ return callback(bindErr); | ||
self._adminClient.search(searchBase, options, function(searchErr, searchResult) { | ||
self._adminClient.search(searchBase, options, function (searchErr, searchResult) { | ||
if (searchErr) { | ||
@@ -303,3 +298,3 @@ return callback(searchErr); | ||
var items = []; | ||
searchResult.on('searchEntry', function(entry) { | ||
searchResult.on('searchEntry', function (entry) { | ||
items.push(entry.object); | ||
@@ -313,3 +308,3 @@ if (self.opts.includeRaw === true) { | ||
searchResult.on('end', function(result) { | ||
searchResult.on('end', function (result) { | ||
if (result.status !== 0) { | ||
@@ -334,3 +329,3 @@ var err = 'non-zero status from LDAP search: ' + result.status; | ||
*/ | ||
LdapAuth.prototype._findUser = function(username, callback) { | ||
LdapAuth.prototype._findUser = function (username, callback) { | ||
var self = this; | ||
@@ -349,9 +344,19 @@ if (!username) { | ||
// so needs to be requested from the LDAP server. | ||
if (opts.attributes && self.opts.groupDnProperty && !opts.attributes.includes(self.opts.groupDnProperty)) { | ||
opts.attributes.push(self.optss.groupDnProperty); | ||
if ( | ||
opts.attributes && | ||
self.opts.groupDnProperty && | ||
!opts.attributes.includes(self.opts.groupDnProperty) | ||
) { | ||
opts.attributes.push(self.opts.groupDnProperty); | ||
} | ||
self._search(self.opts.searchBase, opts, function(err, result) { | ||
self._search(self.opts.searchBase, opts, function (err, result) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: user search error: %s %s %s', err.code, err.name, err.message); | ||
self.log && | ||
self.log.trace( | ||
'ldap authenticate: user search error: %s %s %s', | ||
err.code, | ||
err.name, | ||
err.message | ||
); | ||
return callback(err); | ||
@@ -361,10 +366,10 @@ } | ||
switch (result.length) { | ||
case 0: | ||
return callback(); | ||
case 1: | ||
return callback(null, result[0]); | ||
default: | ||
return callback(format( | ||
'unexpected number of matches (%s) for "%s" username', | ||
result.length, username)); | ||
case 0: | ||
return callback(); | ||
case 1: | ||
return callback(null, result[0]); | ||
default: | ||
return callback( | ||
format('unexpected number of matches (%s) for "%s" username', result.length, username) | ||
); | ||
} | ||
@@ -382,3 +387,3 @@ }); | ||
*/ | ||
LdapAuth.prototype._findGroups = function(user, callback) { | ||
LdapAuth.prototype._findGroups = function (user, callback) { | ||
var self = this; | ||
@@ -395,5 +400,11 @@ if (!user) { | ||
} | ||
self._search(self.opts.groupSearchBase, opts, function(err, result) { | ||
self._search(self.opts.groupSearchBase, opts, function (err, result) { | ||
if (err) { | ||
self.log && self.log.trace('ldap authenticate: group search error: %s %s %s', err.code, err.name, err.message); | ||
self.log && | ||
self.log.trace( | ||
'ldap authenticate: group search error: %s %s %s', | ||
err.code, | ||
err.name, | ||
err.message | ||
); | ||
return callback(err); | ||
@@ -415,3 +426,3 @@ } | ||
*/ | ||
LdapAuth.prototype.authenticate = function(username, password, callback) { | ||
LdapAuth.prototype.authenticate = function (username, password, callback) { | ||
var self = this; | ||
@@ -432,3 +443,3 @@ | ||
// 1. Find the user DN in question. | ||
self._findUser(username, function(findErr, user) { | ||
self._findUser(username, function (findErr, user) { | ||
if (findErr) { | ||
@@ -441,3 +452,3 @@ return callback(findErr); | ||
// 2. Attempt to bind as that user to check password. | ||
self._userClient.bind(user[self.opts.bindProperty], password, function(bindErr) { | ||
self._userClient.bind(user[self.opts.bindProperty], password, function (bindErr) { | ||
if (bindErr) { | ||
@@ -448,3 +459,3 @@ self.log && self.log.trace('ldap authenticate: bind error: %s', bindErr); | ||
// 3. If requested, fetch user groups | ||
self._getGroups(user, function(groupErr, userWithGroups) { | ||
self._getGroups(user, function (groupErr, userWithGroups) { | ||
if (groupErr) { | ||
@@ -455,3 +466,3 @@ self.log && self.log.trace('ldap authenticate: group search error %s', groupErr); | ||
if (self.opts.cache) { | ||
bcrypt.hash(password, self._salt, function(err, hash) { | ||
bcrypt.hash(password, self._salt, function (err, hash) { | ||
if (err) { | ||
@@ -472,4 +483,2 @@ self.log && self.log.trace('ldap authenticate: bcrypt error, not caching %s', err); | ||
module.exports = LdapAuth; |
{ | ||
"name": "ldapauth-fork", | ||
"version": "5.0.4", | ||
"version": "5.0.5", | ||
"main": "./lib/ldapauth.js", | ||
@@ -26,2 +26,4 @@ "types": "./lib/ldapauth.d.ts", | ||
"lint:watch": "watch 'npm run lint' ./lib --wait 0.5", | ||
"prettier:fix": "prettier --write '**/*.{js,json,md,ts}'", | ||
"prettier": "prettier --list-different '**/*.{js,json,md,ts}'", | ||
"pretest": "cd test && tsc", | ||
@@ -41,2 +43,3 @@ "test": "cd test && node test.js" | ||
"eslint": "^8.5.0", | ||
"prettier": "^2.7.1", | ||
"typescript": "^4.0.5", | ||
@@ -43,0 +46,0 @@ "watch": "^1.0.2" |
@@ -41,40 +41,40 @@ # ldapauth-fork | ||
- `url` - LDAP server URL, eg. *ldaps://ldap.example.org:636*, or a list of URLs, e.g. `["ldaps://ldap.example.org:636"]` | ||
- `url` - LDAP server URL, eg. _ldaps://ldap.example.org:636_, or a list of URLs, e.g. `["ldaps://ldap.example.org:636"]` | ||
ldapauth-fork 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*. | ||
- `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_. | ||
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. *{{username}}* is also available and will be replaced with the *uid* of the found user. This is useful for example to filter PosixGroups by *memberUid*. 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*. | ||
- `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. _{{username}}_ is also available and will be replaced with the _uid_ of the found user. This is useful for example to filter PosixGroups by _memberUid_. 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. | ||
- `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` | ||
- `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` | ||
@@ -102,12 +102,12 @@ ## How it works | ||
searchFilter: '(uid={{username}})', | ||
reconnect: true | ||
reconnect: true, | ||
}); | ||
var rejectBasicAuth = function(res) { | ||
var rejectBasicAuth = function (res) { | ||
res.statusCode = 401; | ||
res.setHeader('WWW-Authenticate', 'Basic realm="Example"'); | ||
res.end('Access denied'); | ||
} | ||
}; | ||
var basicAuthMiddleware = function(req, res, next) { | ||
var basicAuthMiddleware = function (req, res, next) { | ||
var credentials = basicAuth(req); | ||
@@ -118,3 +118,3 @@ if (!credentials) { | ||
ldap.authenticate(credentials.name, credentials.pass, function(err, user) { | ||
ldap.authenticate(credentials.name, credentials.pass, function (err, user) { | ||
if (err) { | ||
@@ -121,0 +121,0 @@ return rejectBasicAuth(res); |
34039
11
665
7