activedirectory = function (url, baseDN, username, password, defaults) {
if (this instanceof ActiveDirectory) {
this.opts = {};
if (typeof(url) === 'string') {
this.opts.url = url;
this.baseDN = baseDN;
this.opts.bindDN = username;
this.opts.bindCredentials = password;
if (typeof((defaults || {}).entryParser) === 'function') {
this.opts.entryParser = defaults.entryParser;
}
}
else {
this.opts = _.defaults({}, url);
this.baseDN = this.opts.baseDN;
if (! this.opts.bindDN) this.opts.bindDN = this.opts.username;
if (! this.opts.bindCredentials) this.opts.bindCredentials = this.opts.password;
if (this.opts.logging) {
log = bunyan.createLogger(_.defaults({}, this.opts.logging));
delete(this.opts.logging);
}
}
defaultAttributes = _.extend({}, originalDefaultAttributes, (this.opts || {}).attributes || {}, (defaults || {}).attributes || {});
defaultReferrals = _.extend({}, originalDefaultReferrals, (this.opts || {}).referrals || {}, (defaults || {}).referrals || {});
log.info('Using username/password (%s/%s) to bind to ActiveDirectory (%s).', this.opts.bindDN,
isPasswordLoggingEnabled ? this.opts.bindCredentials : '********', this.opts.url);
log.info('Referrals are %s', defaultReferrals.enabled ? 'enabled. Exclusions: '+JSON.stringify(defaultReferrals.exclude): 'disabled
');
log.info('Default user attributes: %j', defaultAttributes.user || []);
log.info('Default group attributes: %j', defaultAttributes.group || []);
// Enable connection pooling
// TODO: To be disabled / removed in future release of ldapjs > 0.7.1
if (typeof(this.opts.maxConnections) === 'undefined') {
this.opts.maxConnections = 20;
}
events.EventEmitter.call(this);
}
else {
return(new ActiveDirectory(url, baseDN, username, password, defaults));
}
}n/a
function AndFilter(options) {
parents.AndFilter.call(this, options);
}n/a
function ApproximateFilter(options) {
parents.ApproximateFilter.call(this, options);
}n/a
function EqualityFilter(options) {
parents.EqualityFilter.call(this, options);
}n/a
function ExtensibleFilter(options) {
parents.ExtensibleFilter.call(this, options);
}n/a
function GreaterThanEqualsFilter(options) {
parents.GreaterThanEqualsFilter.call(this, options);
}n/a
function LessThanEqualsFilter(options) {
parents.LessThanEqualsFilter.call(this, options);
}n/a
function NotFilter(options) {
parents.NotFilter.call(this, options);
}n/a
function OrFilter(options) {
parents.OrFilter.call(this, options);
}n/a
function PresenceFilter(options) {
parents.PresenceFilter.call(this, options);
}n/a
function SubstringFilter(options) {
parents.SubstringFilter.call(this, options);
}n/a
rangeretrievalspecifierattribute = function (attribute) {
if (this instanceof RangeRetrievalSpecifierAttribute) {
if (! attribute) throw new Error('No attribute provided to create a range retrieval specifier.');
if (typeof(attribute) === 'string') {
attribute = parseRangeRetrievalSpecifierAttribute(attribute);
}
for(var property in attribute) {
if (Array.prototype.hasOwnProperty.call(attribute, property)) {
this[property] = attribute[property];
}
}
}
else {
return(new RangeRetrievalSpecifierAttribute(attribute));
}
}n/a
function EventEmitter() {
EventEmitter.init.call(this);
}n/a
user = function (properties) {
if (this instanceof User) {
for (var property in (properties || {})) {
if (Array.prototype.hasOwnProperty.call(properties, property)) {
this[property] = properties[property];
}
}
}
else {
return(new User(properties));
}
}n/a
activedirectory = function (url, baseDN, username, password, defaults) {
if (this instanceof ActiveDirectory) {
this.opts = {};
if (typeof(url) === 'string') {
this.opts.url = url;
this.baseDN = baseDN;
this.opts.bindDN = username;
this.opts.bindCredentials = password;
if (typeof((defaults || {}).entryParser) === 'function') {
this.opts.entryParser = defaults.entryParser;
}
}
else {
this.opts = _.defaults({}, url);
this.baseDN = this.opts.baseDN;
if (! this.opts.bindDN) this.opts.bindDN = this.opts.username;
if (! this.opts.bindCredentials) this.opts.bindCredentials = this.opts.password;
if (this.opts.logging) {
log = bunyan.createLogger(_.defaults({}, this.opts.logging));
delete(this.opts.logging);
}
}
defaultAttributes = _.extend({}, originalDefaultAttributes, (this.opts || {}).attributes || {}, (defaults || {}).attributes || {});
defaultReferrals = _.extend({}, originalDefaultReferrals, (this.opts || {}).referrals || {}, (defaults || {}).referrals || {});
log.info('Using username/password (%s/%s) to bind to ActiveDirectory (%s).', this.opts.bindDN,
isPasswordLoggingEnabled ? this.opts.bindCredentials : '********', this.opts.url);
log.info('Referrals are %s', defaultReferrals.enabled ? 'enabled. Exclusions: '+JSON.stringify(defaultReferrals.exclude): 'disabled
');
log.info('Default user attributes: %j', defaultAttributes.user || []);
log.info('Default group attributes: %j', defaultAttributes.group || []);
// Enable connection pooling
// TODO: To be disabled / removed in future release of ldapjs > 0.7.1
if (typeof(this.opts.maxConnections) === 'undefined') {
this.opts.maxConnections = 20;
}
events.EventEmitter.call(this);
}
else {
return(new ActiveDirectory(url, baseDN, username, password, defaults));
}
}n/a
function EventEmitter() {
EventEmitter.init.call(this);
}n/a
function _getDefaultAttributes() {
return(_.defaults({}, defaultAttributes));
}...
});
it('should replace default user attributes if specified', function(done) {
var ad = new ActiveDirectory(_.extend({}, config, {
attributes: {
user: [ 'mycustomuserattribute' ]
}
}));
var defaultAttributes = ad._getDefaultAttributes() || {};
assert.equal(1, (defaultAttributes.user || []).length);
assert((defaultAttributes.group || []).length > 0);
done();
});
it('should replace default group attributes if specified', function(done) {
var ad = new ActiveDirectory(_.extend({}, config, {
attributes: {
...function _getDefaultGroupAttributes() {
return(_.defaults({}, (defaultAttributes || {}).group));
}n/a
function _getDefaultUserAttributes() {
return(_.defaults({}, (defaultAttributes || {}).user));
}n/a
function authenticate(username, password, callback) {
var self = this;
log.trace('authenticate(%j,%s)', username, isPasswordLoggingEnabled ? password : '********');
// Skip authentication if an empty username or password is provided.
if ((! username) || (! password)) {
var err = {
'code': 0x31,
'errno': 'LDAP_INVALID_CREDENTIALS',
'description': 'The supplied credential is invalid'
};
return(callback(err, false));
}
var errorHandled = false;
function handleError(err) {
if (! errorHandled) {
errorHandled = true;
if (hasEvents.call(self, 'error')) self.emit('error', err);
return(callback(err, false));
}
}
var client = createClient.call(self);
client.on('error', handleError);
client.bind(username, password, function(err) {
client.unbind();
var message = util.format('Authentication %s for "%s" as "%s" (password: "%s")',
err ? 'failed' : 'succeeded',
self.opts.url, username, isPasswordLoggingEnabled ? password : '********');
if (err) {
log.warn('%s. Error: %s', message, err);
return(handleError(err));
}
log.info(message);
return(callback(err, true));
});
}...
__Example__
```js
var ad = new ActiveDirectory(config);
var username = 'john.smith@domain.com';
var password = 'password';
ad.authenticate(username, password, function(err, auth) {
if (err) {
console.log('ERROR: '+JSON.stringify(err));
return;
}
if (auth) {
console.log('Authenticated!');
...function find(opts, callback) {
var self = this;
if (typeof(opts) === 'function') {
callback = opts;
opts = undefined;
}
if (typeof(opts) === 'string') {
opts = {
filter: opts
};
}
log.trace('find(%j)', opts);
var localOpts = _.defaults(_.omit(opts || {}, 'attributes'), {
scope: 'sub',
attributes: joinAttributes((opts || {}).attributes || [], defaultAttributes.group || [], defaultAttributes.user || [],
getRequiredLdapAttributesForGroup(opts), getRequiredLdapAttributesForUser(opts),
[ 'objectCategory' ])
});
search.call(self, localOpts, function onFind(err, results) {
if (err) {
if (callback) callback(err);
return;
}
if ((! results) || (results.length === 0)) {
log.warn('No results found for query "%s"', truncateLogOutput(localOpts.filter));
if (callback) callback();
self.emit('done');
return;
}
var result = {
users: [],
groups: [],
other: []
};
// Parse the results in parallel.
async.forEach(results, function(item, asyncCallback) {
if (isGroupResult(item)) {
var group = new Group(pickAttributes(item, (opts || {}).attributes || defaultAttributes.group));
result.groups.push(group);
// Also retrieving user group memberships?
if (includeGroupMembershipFor(opts, 'group')) {
getGroupMembershipForDN.call(self, opts, group.dn, function(err, groups) {
if (err) return(asyncCallback(err));
group.groups = groups;
self.emit('group', group);
asyncCallback();
});
} else {
self.emit('group', group);
asyncCallback();
}
}
else if (isUserResult(item)) {
var user = new User(pickAttributes(item, (opts || {}).attributes || defaultAttributes.user));
result.users.push(user);
// Also retrieving user group memberships?
if (includeGroupMembershipFor(opts, 'user')) {
getGroupMembershipForDN.call(self, opts, user.dn, function(err, groups) {
if (err) return(asyncCallback(err));
user.groups = groups;
self.emit('user', user);
asyncCallback();
});
} else {
self.emit('user', user);
asyncCallback();
}
}
else {
var other = pickAttributes(item, (opts || {}).attributes || _.union(defaultAttributes.user, defaultAttributes.group));
result.other.push(other);
self.emit('other', other);
asyncCallback();
}
}, function(err) {
if (err) {
if (callback) callback(err);
return;
}
log.info('%d group(s), %d user(s), %d other found for query "%s". Results: %j',
result.groups.length, result.users.length, result.other.length,
truncateLogOutput(opts.filter), result);
self.emit('groups', result.groups);
self.emit('users', result.users);
if (callback) callback(null, result);
});
});
}...
var query = 'cn=*Exchange*';
var opts = {
includeMembership : [ 'group', 'user' ], // Optionally can use 'all'
includeDeleted : false
};
var ad = new ActiveDirectory(config);
ad.find(query, function(err, results) {
if ((err) || (! results)) {
console.log('ERROR: ' + JSON.stringify(err));
return;
}
console.log('Groups');
_.each(results.groups, function(group) {
...function find(opts, callback) {
var self = this;
if (typeof(opts) === 'function') {
callback = opts;
opts = undefined;
}
if (typeof(opts) === 'string') {
opts = {
filter: opts
};
}
log.trace('findDeletedObjects(%j)', opts);
var defaultDeletedAttributes = [
'attributeID', 'attributeSyntax', 'dnReferenceUpdate' , 'dNSHostName' , 'flatName',
'governsID', 'groupType', 'instanceType', 'lDAPDisplayName', 'legacyExchangeDN',
'mS-DS-CreatorSID', 'mSMQOwnerID', 'nCName', 'objectClass', 'objectGUID', 'objectSid',
'oMSyntax', 'proxiedObjectName', 'replPropertyMetaData', 'sAMAccountName', 'securityIdentifier',
'sIDHistory', 'subClassOf', 'systemFlags', 'trustPartner', 'trustDirection', 'trustType',
'trustAttributes', 'userAccountControl', 'uSNChanged', 'uSNCreated', 'whenCreated',
'msDS-AdditionalSamÂAccountName', 'msDS-Auxiliary-Classes', 'msDS-Entry-Time-To-Die',
'msDS-IntId', 'msSFU30NisDomain', 'nTSecurityDescriptor', 'uid'
];
/**
* Performs the actul search of the specified baseDN for any deleted (tombstoned) objects.
* @param {String} baseDN The baseDN to search on.
* @param {Object} opts The ldapjs query options.
*/
function searchDeletedObjects(baseDN, opts) {
search.call(self, baseDN, _.defaults({}, opts, { includeDeleted: true }), function onFind(err, results) {
if (err) {
if (callback) callback(err);
return;
}
if ((! results) || (results.length === 0)) {
log.warn('No deleted objects found for query "%s"', truncateLogOutput(opts.filter));
if (callback) callback();
self.emit('done');
return;
}
var deletedItems = [];
// Parse the results in parallel.
_.forEach(deletedItemss, function(item) {
var deletedItem = pickAttributes(item, (opts | {}).attributes || []);
self.emit('entry:deleted', deletedItem);
deletedItems.push(deletedItem);
});
log.info('%d deleted objects found for query "%s". Results: %j',
deletedItems.length, truncateLogOutput(localOpts.filter), deletedItems);
self.emit('deleted', deletedItems);
if (callback) callback(null, deletedItems);
});
}
var localOpts = _.defaults(opts || {}, {
scope: 'one',
attributes: joinAttributes((opts || {}).attributes || [], defaultDeletedAttributes),
controls: [ ]
});
// Get the BaseDN for the tree
if (! localOpts.baseDN) {
log.debug('No baseDN specified for Deleted Object. Querying RootDSE at %s.', self.opts.url);
ActiveDirectory.prototype.getRootDSE(self.opts.url, [ 'defaultNamingContext' ], function(err, result) {
if (err) {
if (callback) callback(err);
return;
}
log.info('Retrieved defaultNamingContext (%s) from RootDSE at %s.', result.defaultNamingContext, self.opts.url);
searchDeletedObjects('CN=Deleted Objects,' + result.defaultNamingContext, localOpts);
});
}
else searchDeletedObjects(localOpts.baseDN, localOpts);
}...
```js
var url = 'ldap://yourdomain.com';
var opts = {
baseDN: 'ou=Deleted Objects, dc=yourdomain, dc=com',
filter: 'cn=*Bob*'
};
ad.findDeletedObjects(opts, function(err, result) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log('findDeletedObjects: '+JSON.stringify(result));
});
...function findGroup(opts, groupName, callback) {
var self = this;
if (typeof(groupName) === 'function') {
callback = groupName;
groupName = opts;
opts = undefined;
}
if (typeof(opts) === 'string') {
groupName = opts;
opts = undefined;
}
log.trace('findGroup(%j,%s)', opts, groupName);
var localOpts = _.defaults(_.omit(opts || {}, 'attributes'), {
filter: getGroupQueryFilter.call(self, groupName),
scope: 'sub',
attributes: joinAttributes((opts || {}).attributes || defaultAttributes.group, getRequiredLdapAttributesForGroup(opts))
});
search.call(self, localOpts, function onSearch(err, results) {
if (err) {
if (callback) callback(err);
return;
}
if ((! results) || (results.length === 0)) {
log.warn('Group "%s" not found for query "%s"', groupName, truncateLogOutput(localOpts.filter));
if (callback) callback();
return;
}
var group = new Group(pickAttributes(results[0], (opts || {}).attributes || defaultAttributes.group));
log.info('%d group(s) found for query "%s". Returning first group: %j',
results.length, truncateLogOutput(localOpts.filter), group);
// Also retrieving user group memberships?
if (includeGroupMembershipFor(opts, 'group')) {
getGroupMembershipForDN.call(self, opts, group.dn, function(err, groups) {
if (err) {
if (callback) callback(err);
return;
}
group.groups = groups;
self.emit('group', group);
if (callback) callback(err, group);
});
}
else {
self.emit('group', group);
if (callback) callback(err, group);
}
});
}...
```js
// Any of the following group names can be searched on
var groupName = 'Employees';
var dn = 'CN=Employees,OU=Groups,DC=domain,DC=com'
// Find group by common name
var ad = new ActiveDirectory(config);
ad.findGroup(groupName, function(err, group) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! user) console.log('Group: ' + groupName + ' not found.');
else {
...function findGroup(opts, callback) {
var self = this;
var defaultGroupFilter = '(objectClass=group)(!(objectClass=computer))(!(objectClass=user))(!(objectClass=person))';
if (typeof(opts) === 'function') {
callback = opts;
opts = '';
}
if ((typeof(opts) === 'string') && (opts)) {
opts = {
filter: '(&'+defaultGroupFilter+getCompoundFilter(opts)+')'
};
}
log.trace('findGroups(%j)', opts);
var localOpts = _.defaults(_.omit(opts || {}, 'attributes'), {
filter: '(&'+defaultGroupFilter+')',
scope: 'sub',
attributes: joinAttributes((opts || {}).attributes || defaultAttributes.group || [], getRequiredLdapAttributesForGroup(opts),
[ 'groupType' ])
});
search.call(self, localOpts, function onSearch(err, results) {
if (err) {
if (callback) callback(err);
return;
}
if ((! results) || (results.length === 0)) {
log.warn('No groups found matching query "%s"', truncateLogOutput(localOpts.filter));
if (callback) callback();
return;
}
var groups = [];
// Parse the results in parallel.
async.forEach(results, function(result, asyncCallback) {
if (isGroupResult(result)) {
var group = new Group(pickAttributes(result, (opts || {}).attributes || defaultAttributes.user));
groups.push(group);
// Also retrieving user group memberships?
if (includeGroupMembershipFor(opts, 'group')) {
getGroupMembershipForDN.call(self, opts, group.dn, function(err, groups) {
if (err) return(asyncCallback(err));
group.groups = groups;
self.emit('group', group);
asyncCallback();
});
}
else {
self.emit('group', group);
asyncCallback();
}
}
else asyncCallback();
}, function(err) {
if (err) {
if (callback) callback(err);
return;
}
log.info('%d group(s) found for query "%s". Groups: %j', groups.length, truncateLogOutput(localOpts.filter), groups);
self.emit('groups', groups);
if (callback) callback(null, groups);
});
});
}...
__Example__
```js
var query = 'CN=*Admin*';
var ad = new ActiveDirectory(config);
ad.findGroups(query, function(err, groups) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if ((! groups) || (groups.length == 0)) console.log('No groups found.');
else {
...function findUser(opts, username, includeMembership, callback) {
var self = this;
if (typeof(includeMembership) === 'function') {
callback = includeMembership;
includeMembership = undefined;
}
if (typeof(username) === 'function') {
callback = username;
username = opts;
opts = undefined;
}
if (typeof(username) === 'boolean') {
includeMembership = username;
username = opts;
}
if (typeof(opts) === 'string') {
username = opts;
opts = undefined;
}
log.trace('findUser(%j,%s,%s)', opts, username, includeMembership);
var localOpts = _.defaults(_.omit(opts || {}, 'attributes'), {
filter: getUserQueryFilter.call(self, username),
scope: 'sub',
attributes: joinAttributes((opts || {}).attributes || defaultAttributes.user || [], getRequiredLdapAttributesForUser(opts))
});
search.call(self, localOpts, function onSearch(err, results) {
if (err) {
if (callback) callback(err);
return;
}
if ((! results) || (results.length === 0)) {
log.warn('User "%s" not found for query "%s"', username, truncateLogOutput(localOpts.filter));
if (callback) callback();
return;
}
var user = new User(pickAttributes(results[0], (opts || {}).attributes || defaultAttributes.user));
log.info('%d user(s) found for query "%s". Returning first user: %j', results.length, truncateLogOutput(localOpts.filter), user
);
// Also retrieving user group memberships?
if (includeGroupMembershipFor(opts, 'user') || includeMembership) {
getGroupMembershipForDN.call(self, opts, user.dn, function(err, groups) {
if (err) {
if (callback) callback(err);
return;
}
user.groups = groups;
self.emit('user', user);
if (callback) callback(err, user);
});
}
else {
self.emit('user', user);
if (callback) callback(err, user);
}
});
}...
// Any of the following username types can be searched on
var sAMAccountName = 'username';
var userPrincipalName = 'username@domain.com';
var dn = 'CN=Smith\\, John,OU=Users,DC=domain,DC=com';
// Find user by a sAMAccountName
var ad = new ActiveDirectory(config);
ad.findUser(sAMAccountName, function(err, user) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! user) console.log('User: ' + sAMAccountName + ' not found.');
else console.log(JSON.stringify(user));
...function findUsers(opts, includeMembership, callback) {
var self = this;
var defaultUserFilter = '(|(objectClass=user)(objectClass=person))(!(objectClass=computer))(!(objectClass=group))';
if (typeof(includeMembership) === 'function') {
callback = includeMembership;
includeMembership = false;
}
if (typeof(opts) === 'function') {
callback = opts;
opts = '';
}
if ((typeof(opts) === 'string') && (opts)) {
opts = {
filter: '(&'+defaultUserFilter+getCompoundFilter(opts)+')'
};
}
log.trace('findUsers(%j,%s)', opts, includeMembership);
var localOpts = _.defaults(_.omit(opts || {}, 'attributes'), {
filter: '(&'+defaultUserFilter+')',
scope: 'sub',
attributes: joinAttributes((opts || {}).attributes || defaultAttributes.user || [],
getRequiredLdapAttributesForUser(opts), [ 'objectCategory' ])
});
search.call(self, localOpts, function onSearch(err, results) {
if (err) {
if (callback) callback(err);
return;
}
if ((! results) || (results.length === 0)) {
log.warn('No users found matching query "%s"', truncateLogOutput(localOpts.filter));
if (callback) callback();
return;
}
var users = [];
// Parse the results in parallel.
async.forEach(results, function(result, asyncCallback) {
if (isUserResult(result)) {
var user = new User(pickAttributes(result, (opts || {}).attributes || defaultAttributes.user));
users.push(user);
// Also retrieving user group memberships?
if (includeGroupMembershipFor(opts, 'user') || includeMembership) {
getGroupMembershipForDN.call(self, opts, user.dn, function(err, groups) {
if (err) return(asyncCallback(err));
user.groups = groups;
self.emit('user', user);
asyncCallback();
});
}
else {
self.emit('user', user);
asyncCallback();
}
}
else asyncCallback();
}, function(err) {
if (err) {
if (callback) callback(err);
return;
}
log.info('%d user(s) found for query "%s". Users: %j', users.length, truncateLogOutput(opts.filter), users);
self.emit('users', users);
if (callback) callback(null, users);
});
});
}...
__Example__
```js
var query = 'cn=*George*';
var ad = new ActiveDirectory(config);
ad.findUsers(query, true, function(err, users) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if ((! users) || (users.length == 0)) console.log('No users found.');
else {
...function getGroupMembershipForGroup(opts, groupName, callback) {
var self = this;
if (typeof(groupName) === 'function') {
callback = groupName;
groupName = opts;
opts = undefined;
}
log.trace('getGroupMembershipForGroup(%j,%s)', opts, groupName);
getGroupDistinguishedName.call(self, opts, groupName, function(err, dn) {
if (err) {
if (callback) callback(err);
return;
}
if (! dn) {
log.warn('Could not find a distinguishedName for the specified group name: "%s"', groupName);
if (callback) callback();
return;
}
getGroupMembershipForDN.call(self, opts, dn, function(err, groups) {
if (err) {
if (callback) callback(err);
return;
}
var results = [];
_.each(groups, function(group) {
var result = new Group(pickAttributes(group, (opts || {}).attributes || defaultAttributes.group));
self.emit(result);
results.push(result);
});
if (callback) callback(err, results);
});
});
}...
__Example__
```js
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.getGroupMembershipForGroup(groupName, function(err, groups) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! groups) console.log('Group: ' + groupName + ' not found.');
else console.log(JSON.stringify(groups));
...function getGroupMembershipForUser(opts, username, callback) {
var self = this;
if (typeof(username) === 'function') {
callback = username;
username = opts;
opts = undefined;
}
log.trace('getGroupMembershipForUser(%j,%s)', opts, username);
getUserDistinguishedName.call(self, opts, username, function(err, dn) {
if (err) {
if (callback) callback(err);
return;
}
if (! dn) {
log.warn('Could not find a distinguishedName for the specified username: "%s"', username);
if (callback) callback();
return;
}
getGroupMembershipForDN.call(self, opts, dn, function(err, groups) {
if (err) {
if (callback) callback(err);
return;
}
var results = [];
_.each(groups, function(group) {
var result = new Group(pickAttributes(group, (opts || {}).attributes || defaultAttributes.group));
self.emit(result);
results.push(result);
});
if (callback) callback(err, results);
});
});
}...
__Example__
```js
var sAMAccountName = 'john.smith@domain.com';
var ad = new ActiveDirectory(config);
ad.getGroupMembershipForUser(sAMAccountName, function(err, groups) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! groups) console.log('User: ' + sAMAccountName + ' not found.');
else console.log(JSON.stringify(groups));
...function getRootDSE(url, attributes, callback) {
var self = this;
if (typeof(attributes) === 'function') {
callback = attributes;
attributes = undefined;
}
if (typeof(url) === 'function') {
callback = url;
url = self.url || self.opts.url;
attributes = undefined;
}
if (! url) throw new Error('No url specified for the root DSE. Please specify an ldap url in the following format: "ldap://yourdomain
.com:389".');
log.trace('getRootDSE(%s,%j)', url, attributes || [ '*' ]);
/**
* Inline function handle connection and result errors.
*
* @private
**/
function onClientError(err) {
// Ignore ECONNRESET errors
if ((err || {}).errno !== 'ECONNRESET') {
log.error('An unhandled error occured when searching for the root DSE at "%s". Error: %j', url, err);
if (hasEvents.call(self, 'error')) self.emit('error', err)
}
}
var client = createClient.call(this, url);
client.on('error', onClientError);
// Anonymous bind
client.bind('', '', function(err) {
if (err) {
log.error('Anonymous bind to "%s" failed. Error: %s', url, err);
return(callback(err, false));
}
client.search('', { scope: 'base', attributes: attributes || [ '*' ], filter: '(objectClass=*)' }, function(err, result) {
if (err) {
log.error('Root DSE search failed for "%s". Error: %s', url, err);
return(callback(err));
}
result.on('error', onClientError);
result.on('end', function(result) {
client.unbind();
});
result.on('searchEntry', function(entry) {
callback(null, _.omit(entry.object, 'controls'));
});
});
});
}...
* attributes - The optional list of attributes to retrieve. Returns all if not specified.
* callback - The callback to execute when completed. callback(err: {Object}, result: {Object})
__Example__
```js
var url = 'ldap://yourdomain.com';
ActiveDirectory.prototype.getRootDSE(url, [ 'defaultNamingContext' ], function
(err, result) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log('getRootDSE: '+JSON.stringify(result));
});
...function getUsersForGroup(opts, groupName, callback) {
var self = this;
if (typeof(groupName) === 'function') {
callback = groupName;
groupName = opts;
opts = undefined;
}
log.trace('getUsersForGroup(%j,%s)', opts, groupName);
var users = [];
var groups = [];
self.findGroup(_.defaults({}, _.omit(opts || {}, 'attributes'), {
attributes: joinAttributes((opts || {}).attributes || defaultAttributes.group, [ 'member' ])
}),
groupName, function(err, group) {
if (err) {
if (callback) callback(err);
return;
}
// Group not found
if (! group) {
if (callback) callback(null, group);
return;
}
// If only one result found, encapsulate result into array.
if (typeof(group.member) === 'string') {
group.member = [ group.member ];
}
/**
* Breaks the large array into chucks of the specified size.
* @param {Array} arr The array to break into chunks
* @param {Number} chunkSize The size of each chunk.
* @returns {Array} The resulting array containing each chunk
*/
function chunk(arr, chunkSize) {
var result = [];
for (var index = 0, length = arr.length; index < length; index += chunkSize) {
result.push(arr.slice(index,index + chunkSize));
}
return(result);
}
// We need to break this into the default size queries so
// we can have them running concurrently.
var chunks = chunk(group.member || [], defaultPageSize);
if (chunks.length > 1) {
log.debug('Splitting %d member(s) of "%s" into %d parallel chunks',
(group.member || []).length, groupName, chunks.length);
}
var chunksProcessed = 0;
async.each(chunks, function getUsersForGroup_ChunkItem(members, asyncChunkCallback) {
// We're going to build up a bulk LDAP query so we can reduce
// the number of round trips to the server. We need to get
// additional details about each 'member' to determine if
// it is a group or another user. If it's a group, we need
// to recursively retrieve the members of that group.
var filter = _.reduce(members || [], function(memo, member, index) {
return(memo+'(distinguishedName='+parseDistinguishedName(member)+')');
}, '');
filter = '(&(|(objectCategory=User)(objectCategory=Group))(|'+filter+'))';
var localOpts = {
filter: filter,
scope: 'sub',
attributes: joinAttributes((opts || {}).attributes || defaultAttributes.user || [],
getRequiredLdapAttributesForUser(opts), [ 'groupType' ])
};
search.call(self, localOpts, function onSearch(err, members) {
if (err) {
asyncChunkCallback(err);
return;
}
// Parse the results in parallel.
async.forEach(members, function(member, asyncCallback) {
// If a user, no groupType will be specified.
if (! member.groupType) {
var user = new User(pickAttributes(member, (opts || {}).attributes || defaultAttributes.user));
self.emit(user);
users.push(user);
asyncCallback();
}
else {
// We have a group, recursively get the users belonging to this group.
self.getUsersForGroup(opts, member.cn, function(err, nestedUsers) {
users.push.apply(users, nestedUsers);
asyncCallback();
});
}
}, function(err) {
if (chunks.length > 1) {
log.debug('Finished processing chunk %d/%d', ++chunksProcessed, chunks.length);
}
asyncChunkCallback(err);
});
});
}, function getUsersForGroup_ChunkComplete(err) {
// Remove duplicates
users = _.uniq(users, function(user) {
return(user.dn || user);
});
/*
// Remove the dn that was added for duplicate detection if not requested.
if (! _.any((opts || {}).attributes || defaultAttributes.user, function(attribute) { ......
__Example__
```js
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.getUsersForGroup(groupName, function(err, users) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! users) console.log('Group: ' + groupName + ' not found.');
else {
...function groupExists(opts, groupName, callback) {
var self = this;
if (typeof(groupName) === 'function') {
callback = groupName;
groupName = opts;
opts = undefined;
}
log.trace('groupExists(%j,%s)', opts, groupName);
self.findGroup(opts, groupName, function(err, result) {
if (err) {
callback(err);
return;
}
log.info('"%s" %s exist.', groupName, (result != null) ? 'DOES' : 'DOES NOT');
callback(null, result != null);
});
}...
__Example__
```js
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.groupExists(groupName, function(err, exists) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log(groupName + ' exists: ' + exists);
});
...function isUserMemberOf(opts, username, groupName, callback) {
var self = this;
if (typeof(groupName) === 'function') {
callback = groupName;
groupName = username;
username = opts;
opts = undefined;
}
log.trace('isUserMemberOf(%j,%s,%s)', opts, username, groupName);
opts = _.defaults(_.omit(opts || {}, 'attributes'), {
attributes: [ 'cn', 'dn' ]
});
self.getGroupMembershipForUser(opts, username, function(err, groups) {
if (err) {
callback(err);
return;
}
if ((! groups) || (groups.length === 0)) {
log.info('"%s" IS NOT a member of "%s". No groups found for user.', username, groupName);
callback(null, false);
return;
}
// Check to see if the group.distinguishedName or group.cn matches the list of
// retrieved groups.
var lowerCaseGroupName = (groupName || '').toLowerCase();
var result = _.any(groups, function(item) {
return(((item.dn || '').toLowerCase() === lowerCaseGroupName) ||
((item.cn || '').toLowerCase() === lowerCaseGroupName));
});
log.info('"%s" %s a member of "%s"', username, result ? 'IS' : 'IS NOT', groupName);
callback(null, result);
});
}...
__Example__
```js
var username = 'user@domain.com';
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
var ad.isUserMemberOf(username, groupName, function(err, isMember) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log(username + ' isMemberOf ' + groupName + ': ' + isMember);
});
...function userExists(opts, username, callback) {
var self = this;
if (typeof(username) === 'function') {
callback = username;
username = opts;
opts = undefined;
}
log.trace('userExists(%j,%s)', opts, username);
self.findUser(opts, username, function(err, user) {
if (err) {
callback(err);
return;
}
log.info('"%s" %s exist.', username, (user != null) ? 'DOES' : 'DOES NOT');
callback(null, user != null);
});
}...
__Example__
```js
var username = 'john.smith@domain.com';
var ad = new ActiveDirectory(config);
ad.userExists(username, function(err, exists) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log(username + ' exists: ' + exists);
});
...function AndFilter(options) {
parents.AndFilter.call(this, options);
}n/a
function ApproximateFilter(options) {
parents.ApproximateFilter.call(this, options);
}n/a
function EqualityFilter(options) {
parents.EqualityFilter.call(this, options);
}n/a
function ExtensibleFilter(options) {
parents.ExtensibleFilter.call(this, options);
}n/a
function GreaterThanEqualsFilter(options) {
parents.GreaterThanEqualsFilter.call(this, options);
}n/a
function LessThanEqualsFilter(options) {
parents.LessThanEqualsFilter.call(this, options);
}n/a
function NotFilter(options) {
parents.NotFilter.call(this, options);
}n/a
function OrFilter(options) {
parents.OrFilter.call(this, options);
}n/a
function PresenceFilter(options) {
parents.PresenceFilter.call(this, options);
}n/a
function SubstringFilter(options) {
parents.SubstringFilter.call(this, options);
}n/a
function isFilter(filter) {
if (!filter || typeof (filter) !== 'object') {
return false;
}
// Do our best to duck-type it
if (typeof (filter.toBer) === 'function' &&
typeof (filter.matches) === 'function' &&
TYPES[filter.type] !== undefined) {
return true;
}
return false;
}n/a
parse = function (ber) {
if (!ber || !(ber instanceof BerReader))
throw new TypeError('ber (BerReader) required');
return _parse(ber);
}...
// 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) {
...function parseString(str) {
var generic = parents.parse(str);
// The filter object(s) return from ldap-filter.parse lack the toBer/parse
// decoration that native ldapjs filter possess. cloneFilter adds that back.
return cloneFilter(generic);
}n/a
function AndFilter(options) {
parents.AndFilter.call(this, options);
}n/a
function AndFilter(options) {
if (typeof (options) === 'object') {
assert.arrayOfObject(options.filters, 'options.filters');
} else {
options = {};
}
this.__defineGetter__('type', function () { return 'and'; });
this.filters = options.filters ? options.filters.slice() : [];
var self = this;
this.__defineGetter__('json', function () {
return {
type: 'And',
filters: self.filters
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
this.filters.forEach(function (f) {
ber = f.toBer(ber);
});
return ber;
}n/a
function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
addFilter = function (filter) {
assert.object(filter, 'filter');
this.filters.push(filter);
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
if (this.filters.length === 0) {
/* true per RFC4526 */
return true;
}
for (var i = 0; i < this.filters.length; i++) {
if (!this.filters[i].matches(target, strictAttrCase))
return false;
}
return true;
}n/a
toString = function () {
var str = '(&';
this.filters.forEach(function (f) {
str += f.toString();
});
str += ')';
return str;
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function ApproximateFilter(options) {
parents.ApproximateFilter.call(this, options);
}n/a
function ApproximateFilter(options) {
if (typeof (options) === 'object') {
assert.string(options.attribute, 'options.attribute');
assert.string(options.value, 'options.value');
this.attribute = options.attribute;
this.value = options.value;
}
var self = this;
this.__defineGetter__('type', function () { return 'approx'; });
this.__defineGetter__('json', function () {
return {
type: 'ApproximateMatch',
attribute: self.attribute,
value: self.value
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
ber.writeString(this.attribute);
ber.writeString(this.value);
return ber;
}n/a
parse = function (ber) {
assert.ok(ber);
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function () {
// Consumers must implement this themselves
throw new Error('approx match implementation missing');
}n/a
toString = function () {
return ('(' + helpers.escape(this.attribute) +
'~=' + helpers.escape(this.value) + ')');
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function EqualityFilter(options) {
parents.EqualityFilter.call(this, options);
}n/a
function EqualityFilter(options) {
if (typeof (options) === 'object') {
assert.string(options.attribute, 'options.attribute');
this.attribute = options.attribute;
// Prefer Buffers over strings to make filter cloning easier
if (options.raw) {
this.raw = options.raw;
} else {
this.raw = new Buffer(options.value);
}
} else {
this.raw = new Buffer(0);
}
var self = this;
this.__defineGetter__('type', function () { return 'equal'; });
this.__defineGetter__('value', function () {
return (Buffer.isBuffer(self.raw)) ? self.raw.toString() : self.raw;
});
this.__defineSetter__('value', function (data) {
if (typeof (data) === 'string') {
self.raw = new Buffer(data);
} else if (Buffer.isBuffer(data)) {
self.raw = new Buffer(data.length);
data.copy(self.raw);
} else {
self.raw = data;
}
});
this.__defineGetter__('json', function () {
return {
type: 'EqualityMatch',
attribute: self.attribute,
value: self.value
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
ber.writeString(this.attribute);
ber.writeBuffer(this.raw, ASN1.OctetString);
return ber;
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
var tv = parents.getAttrValue(target, this.attribute, strictAttrCase);
var value = this.value;
if (this.attribute.toLowerCase() === 'objectclass') {
/*
* Perform case-insensitive match for objectClass since nearly every LDAP
* implementation behaves in this manner.
*/
value = value.toLowerCase();
return parents.testValues(function (v) {
return value === v.toLowerCase();
}, tv);
} else {
return parents.testValues(function (v) {
return value === v;
}, tv);
}
}n/a
parse = function (ber) {
assert.ok(ber);
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString(ASN1.OctetString, true);
if (this.attribute === 'objectclass')
this.value = this.value.toLowerCase();
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
var tv = helpers.getAttrValue(target, this.attribute, strictAttrCase);
var value = this.value;
return helpers.testValues(function (v) {
return value === v;
}, tv);
}n/a
toString = function () {
return ('(' + helpers.escape(this.attribute) +
'=' + helpers.escape(this.value) + ')');
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function ExtensibleFilter(options) {
parents.ExtensibleFilter.call(this, options);
}n/a
function ExtensibleFilter(options) {
if (typeof (options) === 'object') {
assert.optionalString(options.rule, 'options.rule');
assert.optionalString(options.matchType, 'options.matchType');
assert.optionalString(options.attribute, 'options.attribute');
assert.optionalString(options.value, 'options.value');
} else {
options = {};
}
if (options.matchType !== undefined) {
this.matchType = options.matchType;
} else {
this.matchType = options.attribute;
}
this.dnAttributes = options.dnAttributes || false;
this.rule = options.rule;
this.value = (options.value !== undefined) ? options.value : '';
var self = this;
this.__defineGetter__('type', function () { return 'ext'; });
this.__defineGetter__('json', function () {
return {
type: 'ExtensibleMatch',
matchRule: self.rule,
matchType: self.matchType,
matchValue: self.value,
dnAttributes: self.dnAttributes
};
});
this.__defineGetter__('matchingRule', function () {
return self.rule;
});
this.__defineGetter__('matchValue', function () {
return self.value;
});
this.__defineGetter__('attribute', function () {
return this.matchType;
});
this.__defineSetter__('attribute', function (value) {
this.matchType = value;
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
if (this.rule)
ber.writeString(this.rule, 0x81);
if (this.matchType)
ber.writeString(this.matchType, 0x82);
ber.writeString(this.value, 0x83);
if (this.dnAttributes)
ber.writeBoolean(this.dnAttributes, 0x84);
return ber;
}n/a
parse = function (ber) {
var end = ber.offset + ber.length;
while (ber.offset < end) {
var tag = ber.peek();
switch (tag) {
case 0x81:
this.rule = ber.readString(tag);
break;
case 0x82:
this.matchType = ber.readString(tag);
break;
case 0x83:
this.value = ber.readString(tag);
break;
case 0x84:
this.dnAttributes = ber.readBoolean(tag);
break;
default:
throw new Error('Invalid ext_match filter type: 0x' + tag.toString(16));
}
}
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function () {
// Consumers must implement this themselves
throw new Error('ext match implementation missing');
}n/a
toString = function () {
var str = '(';
if (this.matchType)
str += this.matchType;
str += ':';
if (this.dnAttributes)
str += 'dn:';
if (this.rule)
str += this.rule + ':';
return (str + '=' + this.value + ')');
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function GreaterThanEqualsFilter(options) {
parents.GreaterThanEqualsFilter.call(this, options);
}n/a
function GreaterThanEqualsFilter(options) {
if (typeof (options) === 'object') {
assert.string(options.attribute, 'options.attribute');
assert.string(options.value, 'options.value');
this.attribute = options.attribute;
this.value = options.value;
}
var self = this;
this.__defineGetter__('type', function () { return 'ge'; });
this.__defineGetter__('json', function () {
return {
type: 'GreaterThanEqualsMatch',
attribute: self.attribute,
value: self.value
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
ber.writeString(this.attribute);
ber.writeString(this.value);
return ber;
}n/a
parse = function (ber) {
assert.ok(ber);
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
var tv = helpers.getAttrValue(target, this.attribute, strictAttrCase);
var value = this.value;
return helpers.testValues(function (v) {
return value <= v;
}, tv);
}n/a
toString = function () {
return ('(' + helpers.escape(this.attribute) +
'>=' + helpers.escape(this.value) + ')');
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function LessThanEqualsFilter(options) {
parents.LessThanEqualsFilter.call(this, options);
}n/a
function LessThanEqualsFilter(options) {
if (typeof (options) === 'object') {
assert.string(options.attribute, 'options.attribute');
assert.string(options.value, 'options.attribute');
this.attribute = options.attribute;
this.value = options.value;
}
var self = this;
this.__defineGetter__('type', function () { return 'le'; });
this.__defineGetter__('json', function () {
return {
type: 'LessThanEqualsMatch',
attribute: self.attribute,
value: self.value
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
ber.writeString(this.attribute);
ber.writeString(this.value);
return ber;
}n/a
parse = function (ber) {
assert.ok(ber);
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
var tv = helpers.getAttrValue(target, this.attribute, strictAttrCase);
var value = this.value;
return helpers.testValues(function (v) {
return value >= v;
}, tv);
}n/a
toString = function () {
return ('(' + helpers.escape(this.attribute) +
'<=' + helpers.escape(this.value) + ')');
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function NotFilter(options) {
parents.NotFilter.call(this, options);
}n/a
function NotFilter(options) {
if (typeof (options) === 'object') {
assert.object(options.filter, 'options.filter');
} else {
options = {};
}
this.filter = options.filter || {};
var self = this;
this.__defineGetter__('type', function () { return 'not'; });
this.__defineGetter__('json', function () {
return {
type: 'Not',
filter: self.filter
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
return this.filter.toBer(ber);
}n/a
function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
addFilter = function (filter) {
assert.object(filter, 'filter');
this.filter = filter;
}n/a
matches = function (target, strictAttrCase) {
return !this.filter.matches(target, strictAttrCase);
}n/a
toString = function () {
return '(!' + this.filter.toString() + ')';
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function OrFilter(options) {
parents.OrFilter.call(this, options);
}n/a
function OrFilter(options) {
if (typeof (options) === 'object') {
assert.arrayOfObject(options.filters, 'options.filters');
} else {
options = {};
}
this.filters = options.filters ? options.filters.slice() : [];
var self = this;
this.__defineGetter__('type', function () { return 'or'; });
this.__defineGetter__('json', function () {
return {
type: 'Or',
filters: self.filters
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
this.filters.forEach(function (f) {
ber = f.toBer(ber);
});
return ber;
}n/a
function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
addFilter = function (filter) {
assert.object(filter, 'filter');
this.filters.push(filter);
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
for (var i = 0; i < this.filters.length; i++) {
if (this.filters[i].matches(target, strictAttrCase))
return true;
}
return false;
}n/a
toString = function () {
var str = '(|';
this.filters.forEach(function (f) {
str += f.toString();
});
str += ')';
return str;
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function PresenceFilter(options) {
parents.PresenceFilter.call(this, options);
}n/a
function PresenceFilter(options) {
if (typeof (options) === 'object') {
assert.string(options.attribute, 'options.attribute');
this.attribute = options.attribute;
}
var self = this;
this.__defineGetter__('type', function () { return 'present'; });
this.__defineGetter__('json', function () {
return {
type: 'PresenceMatch',
attribute: self.attribute
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
for (var i = 0; i < this.attribute.length; i++)
ber.writeByte(this.attribute.charCodeAt(i));
return ber;
}n/a
parse = function (ber) {
assert.ok(ber);
this.attribute =
ber.buffer.slice(0, ber.length).toString('utf8').toLowerCase();
ber._offset += ber.length;
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
var value = helpers.getAttrValue(target, this.attribute, strictAttrCase);
return (value !== undefined && value !== null);
}n/a
toString = function () {
return '(' + helpers.escape(this.attribute) + '=*)';
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...function SubstringFilter(options) {
parents.SubstringFilter.call(this, options);
}n/a
function SubstringFilter(options) {
if (typeof (options) === 'object') {
assert.string(options.attribute, 'options.attribute');
this.attribute = options.attribute;
this.initial = options.initial;
this.any = options.any ? options.any.slice(0) : [];
this.final = options.final;
} else {
this.any = [];
}
var self = this;
this.__defineGetter__('type', function () { return 'substring'; });
this.__defineGetter__('json', function () {
return {
type: 'SubstringMatch',
initial: self.initial,
any: self.any,
final: self.final
};
});
}n/a
_toBer = function (ber) {
assert.ok(ber);
ber.writeString(this.attribute);
ber.startSequence();
if (this.initial)
ber.writeString(this.initial, 0x80);
if (this.any && this.any.length)
this.any.forEach(function (s) {
ber.writeString(s, 0x81);
});
if (this.final)
ber.writeString(this.final, 0x82);
ber.endSequence();
return ber;
}n/a
parse = function (ber) {
assert.ok(ber);
this.attribute = ber.readString().toLowerCase();
ber.readSequence();
var end = ber.offset + ber.length;
while (ber.offset < end) {
var tag = ber.peek();
switch (tag) {
case 0x80: // Initial
this.initial = ber.readString(tag);
if (this.attribute === 'objectclass')
this.initial = this.initial.toLowerCase();
break;
case 0x81: // Any
var anyVal = ber.readString(tag);
if (this.attribute === 'objectclass')
anyVal = anyVal.toLowerCase();
this.any.push(anyVal);
break;
case 0x82: // Final
this.final = ber.readString(tag);
if (this.attribute === 'objectclass')
this.final = this.final.toLowerCase();
break;
default:
throw new Error('Invalid substrings filter type: 0x' + tag.toString(16));
}
}
return true;
}...
// 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) {
...function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
}n/a
matches = function (target, strictAttrCase) {
assert.object(target, 'target');
var tv = helpers.getAttrValue(target, this.attribute, strictAttrCase);
if (tv !== undefined && tv !== null) {
var re = '';
if (this.initial)
re += '^' + escapeRegExp(this.initial) + '.*';
this.any.forEach(function (s) {
re += escapeRegExp(s) + '.*';
});
if (this.final)
re += escapeRegExp(this.final) + '$';
var matcher = new RegExp(re);
return helpers.testValues(function (v) {
return matcher.test(v);
}, tv);
}
return false;
}n/a
toString = function () {
var str = '(' + helpers.escape(this.attribute) + '=';
if (this.initial)
str += helpers.escape(this.initial);
str += '*';
this.any.forEach(function (s) {
str += helpers.escape(s) + '*';
});
if (this.final)
str += helpers.escape(this.final);
str += ')';
return str;
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...rangeretrievalspecifierattribute = function (attribute) {
if (this instanceof RangeRetrievalSpecifierAttribute) {
if (! attribute) throw new Error('No attribute provided to create a range retrieval specifier.');
if (typeof(attribute) === 'string') {
attribute = parseRangeRetrievalSpecifierAttribute(attribute);
}
for(var property in attribute) {
if (Array.prototype.hasOwnProperty.call(attribute, property)) {
this[property] = attribute[property];
}
}
}
else {
return(new RangeRetrievalSpecifierAttribute(attribute));
}
}n/a
function getRangeAttributes(item) {
var attributes = [];
for(var attribute in (item || {})) {
if (RangeRetrievalSpecifierAttribute.prototype.isRangeAttribute(attribute)) {
var range = new RangeRetrievalSpecifierAttribute(attribute);
attributes.push(range);
}
}
return(attributes.length > 0 ? attributes : null);
}...
if (! RangeRetrievalSpecifierAttribute.prototype.hasRangeAttributes(result)) {
callback(null, result);
return;
}
// Parse the range attributes that were provided. If the range attributes are null
// or indicate that the range is complete, return the result.
var rangeAttributes = RangeRetrievalSpecifierAttribute.prototype.getRangeAttributes(result
);
if ((! rangeAttributes) || (rangeAttributes.length <= 0)) {
callback(null, result);
return;
}
// Parse each of the range attributes. Merge the range attributes into
// the properly named property.
...function hasRangeAttributes(item) {
return(_.any(_.keys(item || {}), function(attribute) {
return(RangeRetrievalSpecifierAttribute.prototype.isRangeAttribute(attribute));
}));
}...
*/
function parseRangeAttributes(result, opts, callback) {
log.trace('parseRangeAttributes(%j,%j)', result, opts);
var self = this;
// Check to see if any of the result attributes have range= attributes.
// If not, return immediately.
if (! RangeRetrievalSpecifierAttribute.prototype.hasRangeAttributes(result)) {
callback(null, result);
return;
}
// Parse the range attributes that were provided. If the range attributes are null
// or indicate that the range is complete, return the result.
var rangeAttributes = RangeRetrievalSpecifierAttribute.prototype.getRangeAttributes(result);
...function isComplete() {
var self = this;
return((self.high == null) || (typeof(self.high) === 'undefined'));
}...
if (! result[rangeAttribute.attributeName]) result[rangeAttribute.attributeName] = [];
Array.prototype.push.apply(result[rangeAttribute.attributeName], result[rangeAttribute.toString()]);
delete(result[rangeAttribute.toString()]);
// Build our ldap query attributes with the proper attribute;range= tags to
// get the next sequence of data.
var queryAttribute = rangeAttribute.next();
if ((queryAttribute) && (! queryAttribute.isComplete())) {
queryAttributes.push(queryAttribute.toString());
}
});
// If we're at the end of the range (i.e. all items retrieved), return the result.
if (queryAttributes.length <= 0) {
log.debug('All attribute ranges %j retrieved for %s', rangeAttributes, result.dn);
...function isRangeAttribute(attribute) {
var re = new RegExp(pattern, 'i');
return(re.test(attribute));
}...
* @static
* @param {Object} item The value to extract the range retrieval attributes from.
* @returns {Array[RangeRetrievalSpecifierAttribute]}
*/
RangeRetrievalSpecifierAttribute.prototype.getRangeAttributes = function getRangeAttributes(item) {
var attributes = [];
for(var attribute in (item || {})) {
if (RangeRetrievalSpecifierAttribute.prototype.isRangeAttribute(attribute)) {
var range = new RangeRetrievalSpecifierAttribute(attribute);
attributes.push(range);
}
}
return(attributes.length > 0 ? attributes : null);
};
...function next() {
var self = this;
if ((self.high != null) && (self.high != self.low)) {
var low = self.low;
var high = self.high;
self.low = high + 1;
self.high = high + (high - low) + 1;
return(this);
}
return(null);
}...
// Merge existing range into the properly named property.
if (! result[rangeAttribute.attributeName]) result[rangeAttribute.attributeName] = [];
Array.prototype.push.apply(result[rangeAttribute.attributeName], result[rangeAttribute.toString()]);
delete(result[rangeAttribute.toString()]);
// Build our ldap query attributes with the proper attribute;range= tags to
// get the next sequence of data.
var queryAttribute = rangeAttribute.next();
if ((queryAttribute) && (! queryAttribute.isComplete())) {
queryAttributes.push(queryAttribute.toString());
}
});
// If we're at the end of the range (i.e. all items retrieved), return the result.
if (queryAttributes.length <= 0) {
...function toString() {
var self = this;
return(self.attributeName + ';range=' + self.low + '-' + (self.high ? self.high : '*'));
}...
* @param {String} output The output to truncate if too long
* @param {Number} [maxLength] The maximum length. If not specified, then the global value maxOutputLength is used.
*/
function truncateLogOutput(output, maxLength) {
if (typeof(maxLength) === 'undefined') maxLength = maxOutputLength;
if (! output) return(output);
if (typeof(output) !== 'string') output = output.toString();
var length = output.length;
if ((! length) || (length < (maxLength + 3))) return(output);
var prefix = Math.ceil((maxLength - 3)/2);
var suffix = Math.floor((maxLength - 3)/2);
return(output.slice(0, prefix)+ '...' +
output.slice(length-suffix));
...user = function (properties) {
if (this instanceof User) {
for (var property in (properties || {})) {
if (Array.prototype.hasOwnProperty.call(properties, property)) {
this[property] = properties[property];
}
}
}
else {
return(new User(properties));
}
}n/a
function isMemberOf(group) {
if (! group) return(false);
group = (group || '').toLowerCase();
return(_.any(this.groups || [], function(item) {
return (((item || {}).cn || '').toLowerCase() === group);
}));
}n/a