ad-promise
Advanced tools
Comparing version 1.5.1 to 1.5.2
module.exports = { | ||
chunks : null, | ||
maxSearchesAtOnce: 3000 | ||
maxSearchesAtOnce: 2000, | ||
searchTimeoutAndReject : { | ||
// Timeout : { | ||
// timeoutBehaviour : "retry", | ||
// retryAttempts: 1, | ||
// timeoutMillis: 2000 | ||
// }, | ||
Reject : { | ||
rejectBehaviour : "retry", | ||
retryAttempts : 1 | ||
} | ||
}, | ||
} |
@@ -1,2 +0,3 @@ | ||
const _ = require('underscore'); | ||
const _ = require('underscore'); | ||
const defaultOpts = require('../../configs/config.defaultClientOpts'); | ||
/** | ||
@@ -8,4 +9,5 @@ * From the list of options, retrieves the ldapjs client specific options. | ||
*/ | ||
const getLdapClientOpts = function (opts) { | ||
return (_.pick(opts || {}, | ||
const getLdapClientOpts = function (Opts) { | ||
let opts = (_.pick(Opts || {}, | ||
// Client | ||
@@ -17,6 +19,12 @@ 'url', | ||
'queueDisable', 'bindDN', 'bindCredentials', | ||
'maxConnections' | ||
'maxConnections', 'reconnect' | ||
)); | ||
for(key in defaultOpts){ | ||
opts[key] = opts[key] || defaultOpts[key]; | ||
} | ||
return opts; | ||
} | ||
module.exports = getLdapClientOpts; |
const ldap = require('ldapjs'); | ||
const _ = require('underscore'); | ||
const Url = require('url'); | ||
const createClient = require('./service.createClient'); | ||
const truncateLogOutput = require('./service.truncateLogOutput'); | ||
const getLdapOpts = require('./service.getLdapOpts'); | ||
const isAllowedReferral = require('./service.isAllowedReferral'); | ||
const log = require('./service.log'); | ||
const limitpromises = require('limitpromises'); | ||
const maxPromiseConfig = require('../../configs/config.maxPromiseGroup'); | ||
const onClientError = require('./search/service.search.onClientError'); | ||
const onSearchEnd = require('./search/service.onSearchEnd'); | ||
const onSearchEntry = require('./search/service.search.onSearchEntry'); | ||
const onReferralChase = require('./search/service.search.onReferralChase'); | ||
const defaultPageSize = 1000; // The maximum number of results that AD will return in a single call. Default=1000 | ||
@@ -25,3 +29,5 @@ | ||
let searchStarted = new Date(); | ||
var self = this; | ||
let self = this; | ||
let results = []; | ||
let isDone = false; | ||
@@ -41,140 +47,7 @@ if (typeof (opts) === 'function') { | ||
var isDone = false; | ||
var pendingReferrals = []; | ||
var pendingRangeRetrievals = 0; | ||
var client = createClient.call(self, null, opts); | ||
client.on('error', onClientError); | ||
client.on('error', err => { | ||
onClientError(err, client, searchStarted, baseDN, opts, null, null, "Client") | ||
}); | ||
/** | ||
* Call to remove the specified referral client. | ||
* @param {Object} client The referral client to remove. | ||
*/ | ||
function removeReferral(client) { | ||
if (!client) return; | ||
client.unbind(); | ||
var indexOf = pendingReferrals.indexOf(client); | ||
if (indexOf >= 0) { | ||
pendingReferrals.splice(indexOf, 1); | ||
} | ||
} | ||
/** | ||
* The default entry parser to use. Does not modifications. | ||
* @params {Object} entry The original / raw ldapjs entry to augment | ||
* @params {Function} callback The callback to execute when complete. | ||
*/ | ||
var entryParser = (opts || {}).entryParser || (self.opts || {}).entryParser || function onEntryParser(item, raw, callback) { | ||
callback(item); | ||
}; | ||
/** | ||
* Occurs when a search entry is received. Cleans up the search entry and pushes it to the result set. | ||
* @param {Object} entry The entry received. | ||
*/ | ||
function onSearchEntry(entry) { | ||
const parseRangeAttributes = require('./service.parseRangeAttributes'); | ||
log.trace('onSearchEntry(%j)', entry); | ||
var result = entry.object; | ||
delete result.controls; // Remove the controls array returned as part of the SearchEntry | ||
// Some attributes can have range attributes (paging). Execute the query | ||
// again to get additional items. | ||
pendingRangeRetrievals++; | ||
parseRangeAttributes.call(self, result, opts, function (err, item) { | ||
pendingRangeRetrievals--; | ||
if (err) item = entry.object; | ||
entryParser(item, entry.raw, function (item) { | ||
if (item) results.push(item); | ||
if ((!pendingRangeRetrievals) && (isDone)) { | ||
onSearchEnd(); | ||
} | ||
}); | ||
}); | ||
} | ||
/** | ||
* Occurs when a search reference / referral is received. Follows the referral chase if | ||
* enabled. | ||
* @param {Object} ref The referral. | ||
*/ | ||
function onReferralChase(ref) { | ||
var index = 0; | ||
var referralUrl; | ||
// Loop over the referrals received. | ||
while (referralUrl = (ref.uris || [])[index++]) { | ||
if (isAllowedReferral(referralUrl)) { | ||
log.debug('Following LDAP referral chase at %s', referralUrl); | ||
var referralClient = createClient.call(self, referralUrl, opts); | ||
pendingReferrals.push(referralClient); | ||
var referral = Url.parse(referralUrl); | ||
var referralBaseDn = (referral.pathname || '/').substring(1); | ||
referralClient.search(referralBaseDn, getLdapOpts(opts), controls, function (err, res) { | ||
/** | ||
* Occurs when a error is encountered with the referral client. | ||
* @param {Object} err The error object or string. | ||
*/ | ||
function onReferralError(err) { | ||
log.error(err, '[%s] An error occurred chasing the LDAP referral on %s (%j)', | ||
(err || {}).errno, referralBaseDn, opts); | ||
removeReferral(referralClient); | ||
} | ||
// If the referral chase / search failed, fail silently. | ||
if (err) { | ||
onReferralError(err); | ||
return; | ||
} | ||
res.on('searchEntry', onSearchEntry); | ||
res.on('searchReference', onReferralChase); | ||
res.on('error', onReferralError); | ||
res.on('end', function (result) { | ||
removeReferral(referralClient); | ||
onSearchEnd(); | ||
}); | ||
}); | ||
} | ||
} | ||
} | ||
/** | ||
* Occurs when a client / search error occurs. | ||
* @param {Object} err The error object or string. | ||
* @param {Object} res The optional server response. | ||
*/ | ||
function onClientError(err, res) { | ||
if ((err || {}).name === 'SizeLimitExceededError') { | ||
onSearchEnd(res); | ||
return; | ||
} | ||
if((err || {}).errno === 'ETIMEDOUT'){ | ||
err.timeoutAfter = (new Date() - searchStarted); | ||
} | ||
client.unbind(); | ||
log.error(err, '[%s] An error occurred performing the requested LDAP search on %s (%j)', | ||
(err || {}).errno || 'UNKNOWN', baseDN, opts); | ||
if (callback) callback(err); | ||
} | ||
/** | ||
* Occurs when a search results have all been processed. | ||
* @param {Object} result | ||
*/ | ||
function onSearchEnd(result) { | ||
if ((!pendingRangeRetrievals) && (pendingReferrals.length <= 0)) { | ||
client.unbind(); | ||
log.info('Active directory search (%s) for "%s" returned %d entries.', | ||
baseDN, truncateLogOutput(opts.filter), | ||
(results || []).length); | ||
if (callback) callback(null, results); | ||
} | ||
} | ||
var results = []; | ||
var controls = opts.controls || (opts.controls = []); | ||
@@ -208,32 +81,23 @@ // Add paging results control by default if not already added. | ||
reject(err); | ||
return; | ||
} | ||
res.on('searchEntry', entry => { | ||
onSearchEntry(entry); | ||
resolve(); | ||
onSearchEntry(entry, self, opts, isDone, results, resolve, reject); | ||
}); | ||
res.on('searchReference', ref => { | ||
onReferralChase(ref); | ||
resolve(); | ||
onReferralChase(self, ref, opts, controls, results, resolve, reject); | ||
}); | ||
res.on('error', function (err) { | ||
onClientError(err, res); | ||
return resolve(); | ||
onClientError(err, client, searchStarted, baseDN, opts, callback, resolve, reject, "Search"); | ||
}); | ||
res.on('end', function (result) { | ||
isDone = true; // Flag that the primary query is complete | ||
onSearchEnd(result); | ||
return resolve(); | ||
onSearchEnd(client, baseDN, opts, results, callback, resolve, reject); | ||
}); | ||
}); | ||
}); | ||
}, [true], self.opts.maxSearchesAtOnce || maxPromiseConfig.maxSearchesAtOnce, "searches", { | ||
Reject : { | ||
rejectBehaviour : "retry", | ||
retryAttempts : 1 | ||
} | ||
}); | ||
}, [true], self.opts.maxSearchesAtOnce || maxPromiseConfig.maxSearchesAtOnce, "searches", maxPromiseConfig.searchTimeoutAndReject); | ||
} | ||
module.exports = search; |
@@ -14,3 +14,3 @@ const _ = require('underscore'); | ||
return new Promise((resole, reject) => { | ||
return new Promise((resolve, reject) => { | ||
if (typeof (groupName) === 'function') { | ||
@@ -17,0 +17,0 @@ callback = groupName; |
{ | ||
"author": "Relief Melone (relief.melone@gmail.com)", | ||
"name": "ad-promise", | ||
"version": "1.5.1", | ||
"version": "1.5.2", | ||
"description": "This is a fork of the gheeres node-activedirectory. It fixes some issues with timeouts with very large AD-Groups as well as returning also promises so you won't have to use callbacks", | ||
@@ -6,0 +6,0 @@ "main": "index.js", |
220931
83
4297