function AbandonRequest(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.abandonID); options.protocolOp = Protocol.LDAP_REQ_ABANDON; LDAPMessage.call(this, options); this.abandonID = options.abandonID || 0; }
n/a
function AbandonResponse(options) { options = options || {}; assert.object(options); options.protocolOp = 0; LDAPMessage.call(this, options); }
n/a
function AbandonedError(message) { LDAPError.call(this, message, null, AbandonedError); }
n/a
function AddRequest(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.entry); lassert.optionalArrayOfAttribute(options.attributes); options.protocolOp = Protocol.LDAP_REQ_ADD; LDAPMessage.call(this, options); this.entry = options.entry || null; this.attributes = options.attributes ? options.attributes.slice(0) : []; }
n/a
function AddResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_ADD; LDAPResult.call(this, options); }
n/a
AdminLimitExceededError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
AffectsMultipleDsasError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
AliasDerefProblemError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
AliasProblemError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
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
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
function Attribute(options) { if (options) { if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.type && typeof (options.type) !== 'string') throw new TypeError('options.type must be a string'); } else { options = {}; } this.type = options.type || ''; this._vals = []; if (options.vals !== undefined && options.vals !== null) this.vals = options.vals; }
n/a
AttributeOrValueExistsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
AuthMethodNotSupportedError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function BindRequest(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REQ_BIND; LDAPMessage.call(this, options); this.version = options.version || 0x03; this.name = options.name || null; this.authentication = options.authentication || LDAP_BIND_SIMPLE; this.credentials = options.credentials || ''; }
n/a
function BindResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_BIND; LDAPResult.call(this, options); }
n/a
BusyError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function Change(options) { if (options) { assert.object(options); assert.optionalString(options.operation); } else { options = {}; } this._modification = false; this.operation = options.operation || options.type || 'add'; this.modification = options.modification || {}; }
n/a
function Client(options) { assert.ok(options); EventEmitter.call(this, options); var self = this; var _url; if (options.url) _url = url.parse(options.url); this.host = _url ? _url.hostname : undefined; this.port = _url ? _url.port : false; this.secure = _url ? _url.secure : false; this.url = _url; this.tlsOptions = options.tlsOptions; this.socketPath = options.socketPath || false; this.log = options.log.child({clazz: 'Client'}, true); this.timeout = parseInt((options.timeout || 0), 10); this.connectTimeout = parseInt((options.connectTimeout || 0), 10); this.idleTimeout = parseInt((options.idleTimeout || 0), 10); if (options.reconnect) { // Fall back to defaults if options.reconnect === true var rOpts = (typeof (options.reconnect) === 'object') ? options.reconnect : {}; this.reconnect = { initialDelay: parseInt(rOpts.initialDelay || 100, 10), maxDelay: parseInt(rOpts.maxDelay || 10000, 10), failAfter: parseInt(rOpts.failAfter, 10) || Infinity }; } this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true; this.queue = new RequestQueue({ size: parseInt((options.queueSize || 0), 10), timeout: parseInt((options.queueTimeout || 0), 10) }); if (options.queueDisable) { this.queue.freeze(); } // Implicitly configure setup action to bind the client if bindDN and // bindCredentials are passed in. This will more closely mimic PooledClient // auto-login behavior. if (options.bindDN !== undefined && options.bindCredentials !== undefined) { this.on('setup', function (clt, cb) { clt.bind(options.bindDN, options.bindCredentials, function (err) { if (err) { self.emit('error', err); } cb(err); }); }); } this._socket = null; this.connected = false; this.connect(); }
n/a
CompareFalseError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function CompareRequest(options) { options = options || {}; assert.object(options); assert.optionalString(options.attribute); assert.optionalString(options.value); lassert.optionalStringDN(options.entry); options.protocolOp = Protocol.LDAP_REQ_COMPARE; LDAPMessage.call(this, options); this.entry = options.entry || null; this.attribute = options.attribute || ''; this.value = options.value || ''; }
n/a
function CompareResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_COMPARE; LDAPResult.call(this, options); }
n/a
CompareTrueError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
ConfidentialityRequiredError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function ConnectionError(message) { LDAPError.call(this, message, null, ConnectionError); }
n/a
ConstraintViolationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
function DN(rdns) { assert.optionalArrayOfObject(rdns, '[object] required'); this.rdns = rdns ? rdns.slice() : []; this._format = {}; }
n/a
function DeleteRequest(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.entry); options.protocolOp = Protocol.LDAP_REQ_DELETE; LDAPMessage.call(this, options); this.entry = options.entry || null; }
n/a
function DeleteResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_DELETE; LDAPResult.call(this, options); }
n/a
EntryAlreadyExistsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function EntryChangeNotificationControl(options) { assert.optionalObject(options); options = options || {}; options.type = EntryChangeNotificationControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
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
function ExtendedRequest(options) { options = options || {}; assert.object(options); assert.optionalString(options.requestName); if (options.requestValue && !(Buffer.isBuffer(options.requestValue) || typeof (options.requestValue) === 'string')) { throw new TypeError('options.requestValue must be a buffer or a string'); } options.protocolOp = Protocol.LDAP_REQ_EXTENSION; LDAPMessage.call(this, options); this.requestName = options.requestName || ''; this.requestValue = options.requestValue; }
n/a
function ExtendedResponse(options) { options = options || {}; assert.object(options); assert.optionalString(options.responseName); assert.optionalString(options.responsevalue); this.responseName = options.responseName || undefined; this.responseValue = options.responseValue || undefined; options.protocolOp = Protocol.LDAP_REP_EXTENSION; LDAPResult.call(this, options); }
n/a
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
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
InappropriateAuthenticationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
InappropriateMatchingError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
InsufficientAccessRightsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
InvalidAttributeSyntaxError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
InvalidCredentialsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
InvalidDnSyntaxError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function Error() { [native code] }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
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
LoopDetectError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function ModifyDNRequest(options) { options = options || {}; assert.object(options); assert.optionalBool(options.deleteOldRdn); lassert.optionalStringDN(options.entry); lassert.optionalDN(options.newRdn); lassert.optionalDN(options.newSuperior); options.protocolOp = Protocol.LDAP_REQ_MODRDN; LDAPMessage.call(this, options); this.entry = options.entry || null; this.newRdn = options.newRdn || null; this.deleteOldRdn = options.deleteOldRdn || true; this.newSuperior = options.newSuperior || null; }
n/a
function ModifyDNResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_MODRDN; LDAPResult.call(this, options); }
n/a
function ModifyRequest(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.object); lassert.optionalArrayOfAttribute(options.attributes); options.protocolOp = Protocol.LDAP_REQ_MODIFY; LDAPMessage.call(this, options); this.object = options.object || null; this.changes = options.changes ? options.changes.slice(0) : []; }
n/a
function ModifyResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_MODIFY; LDAPResult.call(this, options); }
n/a
NamingViolationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
NoSuchAttributeError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
NoSuchObjectError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
NotAllowedOnNonLeafError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
NotAllowedOnRdnError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
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
ObjectclassModsProhibitedError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
ObjectclassViolationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
OperationsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
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
OtherError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function PagedResultsControl(options) { assert.optionalObject(options); options = options || {}; options.type = PagedResultsControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
function Parser(options) { assert.object(options); assert.object(options.log); EventEmitter.call(this); this.buffer = null; this.log = options.log; }
n/a
function PersistentSearch() { this.clientList = []; }
n/a
function PersistentSearchControl(options) { assert.optionalObject(options); options = options || {}; options.type = PersistentSearchControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
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
ProtocolError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
ProxiedAuthorizationDeniedError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function RDN(obj) { var self = this; this.attrs = {}; if (obj) { Object.keys(obj).forEach(function (k) { self.set(k, obj[k]); }); } }
n/a
ReferralError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
SaslBindInProgressError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function SearchEntry(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.objectName); options.protocolOp = Protocol.LDAP_REP_SEARCH_ENTRY; LDAPMessage.call(this, options); this.objectName = options.objectName || null; this.setAttributes(options.attributes || []); }
n/a
function SearchReference(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_SEARCH_REF; LDAPMessage.call(this, options); this.uris = options.uris || []; }
n/a
function SearchRequest(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REQ_SEARCH; LDAPMessage.call(this, options); if (options.baseObject !== undefined) { this.baseObject = options.baseObject; } else { this.baseObject = dn.parse(''); } this.scope = options.scope || 'base'; this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES; this.sizeLimit = options.sizeLimit || 0; this.timeLimit = options.timeLimit || 0; this.typesOnly = options.typesOnly || false; this.filter = options.filter || null; this.attributes = options.attributes ? options.attributes.slice(0) : []; }
n/a
function SearchResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_SEARCH; LDAPResult.call(this, options); this.attributes = options.attributes ? options.attributes.slice() : []; this.notAttributes = []; this.sentEntries = 0; }
n/a
function Server(options) { if (options) { if (typeof (options) !== 'object') throw new TypeError('options (object) required'); if (typeof (options.log) !== 'object') throw new TypeError('options.log must be an object'); if (options.certificate || options.key) { if (!(options.certificate && options.key) || (typeof (options.certificate) !== 'string' && !Buffer.isBuffer(options.certificate)) || (typeof (options.key) !== 'string' && !Buffer.isBuffer(options.key))) { throw new TypeError('options.certificate and options.key ' + '(string or buffer) are both required for TLS'); } } } else { options = {}; } var self = this; EventEmitter.call(this, options); this._chain = []; this.log = options.log; this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true; var log = this.log; function setupConnection(c) { assert.ok(c); if (c.type === 'unix') { c.remoteAddress = self.server.path; c.remotePort = c.fd; } else if (c.socket) { // TLS c.remoteAddress = c.socket.remoteAddress; c.remotePort = c.socket.remotePort; } var rdn = new dn.RDN({cn: 'anonymous'}); c.ldap = { id: c.remoteAddress + ':' + c.remotePort, config: options, _bindDN: new DN([rdn]) }; c.addListener('timeout', function () { log.trace('%s timed out', c.ldap.id); c.destroy(); }); c.addListener('end', function () { log.trace('%s shutdown', c.ldap.id); }); c.addListener('error', function (err) { log.warn('%s unexpected connection error', c.ldap.id, err); self.emit('clientError', err); c.destroy(); }); c.addListener('close', function (had_err) { log.trace('%s close; had_err=%j', c.ldap.id, had_err); c.end(); }); c.ldap.__defineGetter__('bindDN', function () { return c.ldap._bindDN; }); c.ldap.__defineSetter__('bindDN', function (val) { if (!(val instanceof DN)) throw new TypeError('DN required'); c.ldap._bindDN = val; return val; }); return c; } function newConnection(c) { setupConnection(c); log.trace('new connection from %s', c.ldap.id); dtrace.fire('server-connection', function () { return [c.remoteAddress]; }); c.parser = new Parser({ log: options.log }); c.parser.on('message', function (req) { req.connection = c; req.logId = c.ldap.id + '::' + req.messageID; req.startTime = new Date().getTime(); if (log.debug()) log.debug('%s: message received: req=%j', c.ldap.id, req.json); var res = getResponse(req); if (!res) { log.warn('Unimplemented server method: %s', req.type); c.destroy(); return false; } // parse string DNs for routing/etc try { switch (req.protocolOp) { case Protocol.LDAP_REQ_BIND: req.name = dn.parse(req.name); break; case Protocol.LDAP_REQ_ADD: case Protocol.LDAP_REQ_COMPARE: case Protocol.LDAP_REQ_DELETE: req.entry = dn.parse(req.entry); break; case Protocol.LDAP_REQ_MODIFY: req.object = dn.parse(req.object); break; case Protocol.LDAP_REQ_MODRDN: req.entry = dn.parse(req.entry); // TODO: handle newRdn/Superior break; case Protocol.LDAP_REQ_SEARCH: req.baseObject = dn.parse(req.baseObject); break; default: break; } } catch (e) { if (self.strictDN) { return res.end(errors.LDAP_INVALID_DN_SYNTAX); } } res.connection = c; res.logId = req.logId; res.requestDN = req.dn; var chain = self._getHandlerChain(req, res); var i = 0; return function (err) { function sendError(err) { res.status = err.code || errors.LDAP_OPERATIONS_ERROR; res.matchedDN = req.suffix ? req.suffi ...
n/a
function ServerSideSortingRequestControl(options) { assert.optionalObject(options); options = options || {}; options.type = ServerSideSortingRequestControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (Array.isArray(options.value)) { assert.arrayOfObject(options.value, 'options.value must be Objects'); for (var i = 0; i < options.value.length; i++) { if (!options.value[i].hasOwnProperty('attributeType')) { throw new Error('Missing required key: attributeType'); } } this._value = options.value; } else if (typeof (options.value) === 'object') { if (!options.value.hasOwnProperty('attributeType')) { throw new Error('Missing required key: attributeType'); } this._value = [options.value]; } else { throw new TypeError('options.value must be a Buffer, Array or Object'); } options.value = null; } Control.call(this, options); }
n/a
function ServerSideSortingResponseControl(options) { assert.optionalObject(options); options = options || {}; options.type = ServerSideSortingResponseControl.OID; options.criticality = false; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { if (VALID_CODES.indexOf(options.value.result) === -1) { throw new Error('Invalid result code'); } if (options.value.failedAttribute && typeof (options.value.failedAttribute) !== 'string') { throw new Error('failedAttribute must be String'); } this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
SizeLimitExceededError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
StrongAuthRequiredError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
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
TimeLimitExceededError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function TimeoutError(message) { LDAPError.call(this, message, null, TimeoutError); }
n/a
UnavailableCriticalExtensionError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
UnavailableError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function UnbindRequest(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REQ_UNBIND; LDAPMessage.call(this, options); }
n/a
function UnbindResponse(options) { options = options || {}; assert.object(options); options.protocolOp = 0; LDAPMessage.call(this, options); }
n/a
UndefinedAttributeTypeError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
UnwillingToPerformError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function createClient(options) { if (typeof (options) !== 'object') throw new TypeError('options (object) required'); if (options.url && typeof (options.url) !== 'string') throw new TypeError('options.url (string) required'); if (options.socketPath && typeof (options.socketPath) !== 'string') throw new TypeError('options.socketPath must be a string'); if (!xor(options.url, options.socketPath)) throw new TypeError('options.url ^ options.socketPath (String) required'); if (!options.log) options.log = DEF_LOG; if (typeof (options.log) !== 'object') throw new TypeError('options.log must be an object'); return new Client(options); }
n/a
createServer = function (options) { if (options === undefined) options = {}; if (typeof (options) !== 'object') throw new TypeError('options (object) required'); if (!options.log) { options.log = new Logger({ name: 'ldapjs', component: 'client', stream: process.stderr }); } return new Server(options); }
...
## Usage
For full docs, head on over to <http://ldapjs.org>.
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
...
function getControl(ber) { assert.ok(ber); if (ber.readSequence() === null) return null; var type; var opts = { criticality: false, value: null }; if (ber.length) { var end = ber.offset + ber.length; type = ber.readString(); if (ber.offset < end) { if (ber.peek() === Ber.Boolean) opts.criticality = ber.readBoolean(); } if (ber.offset < end) opts.value = ber.readString(Ber.OctetString, true); } var control; switch (type) { case PersistentSearchControl.OID: control = new PersistentSearchControl(opts); break; case EntryChangeNotificationControl.OID: control = new EntryChangeNotificationControl(opts); break; case PagedResultsControl.OID: control = new PagedResultsControl(opts); break; case ServerSideSortingRequestControl.OID: control = new ServerSideSortingRequestControl(opts); break; case ServerSideSortingResponseControl.OID: control = new ServerSideSortingResponseControl(opts); break; default: opts.type = type; control = new Control(opts); break; } return control; }
n/a
getError = function (res) { assert.ok(res instanceof LDAPResult, 'res (LDAPResult) required'); var errObj = ERRORS[res.status]; var E = module.exports[errObj.err]; return new E(res.errorMessage || errObj.message, res.matchedDN || null, module.exports.getError); }
n/a
getMessage = function (code) { assert.number(code, 'code (number) required'); var errObj = ERRORS[code]; return (errObj && errObj.message ? errObj.message : ''); }
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
function parse(name) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); var cur = 0; var len = name.length; function parseRdn() { var rdn = new RDN(); var order = 0; rdn.spLead = trim(); while (cur < len) { var opts = { order: order }; var attr = parseAttrType(); trim(); if (cur >= len || name[cur++] !== '=') throw invalidDN(name); trim(); // Parameters about RDN value are set in 'opts' by parseAttrValue var value = parseAttrValue(opts); rdn.set(attr, value, opts); rdn.spTrail = trim(); if (cur >= len || name[cur] !== '+') break; ++cur; ++order; } return rdn; } function trim() { var count = 0; while ((cur < len) && isWhitespace(name[cur])) { ++cur; count++; } return count; } function parseAttrType() { var beg = cur; while (cur < len) { var c = name[cur]; if (isAlphaNumeric(c) || c == '.' || c == '-' || c == ' ') { ++cur; } else { break; } } // Back out any trailing spaces. while ((cur > beg) && (name[cur - 1] == ' ')) --cur; if (beg == cur) throw invalidDN(name); return name.slice(beg, cur); } function parseAttrValue(opts) { if (cur < len && name[cur] == '#') { opts.binary = true; return parseBinaryAttrValue(); } else if (cur < len && name[cur] == '"') { opts.quoted = true; return parseQuotedAttrValue(); } else { return parseStringAttrValue(); } } function parseBinaryAttrValue() { var beg = cur++; while (cur < len && isAlphaNumeric(name[cur])) ++cur; return name.slice(beg, cur); } function parseQuotedAttrValue() { var str = ''; ++cur; // Consume the first quote while ((cur < len) && name[cur] != '"') { if (name[cur] === '\\') cur++; str += name[cur++]; } if (cur++ >= len) // no closing quote throw invalidDN(name); return str; } function parseStringAttrValue() { var beg = cur; var str = ''; var esc = -1; while ((cur < len) && !atTerminator()) { if (name[cur] === '\\') { // Consume the backslash and mark its place just in case it's escaping // whitespace which needs to be preserved. esc = cur++; } if (cur === len) // backslash followed by nothing throw invalidDN(name); str += name[cur++]; } // Trim off (unescaped) trailing whitespace and rewind cursor to the end of // the AttrValue to record whitespace length. for (; cur > beg; cur--) { if (!isWhitespace(name[cur - 1]) || (esc === (cur - 1))) break; } return str.slice(0, cur - beg); } function atTerminator() { return (cur < len && (name[cur] === ',' || name[cur] === ';' || name[cur] === '+')); } var rdns = []; // Short-circuit for empty DNs if (len === 0) return new DN(rdns); rdns.push(parseRdn()); while (cur < len) { if (name[cur] === ',' || name[cur] === ';') { ++cur; rdns.push(parseRdn()); } else { throw invalidDN(name); } } return new DN(rdns); }
n/a
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
parseURL = function (urlStr, parseDN) { var u = url.parse(urlStr); if (!u.protocol || !(u.protocol === 'ldap:' || u.protocol === 'ldaps:')) throw new TypeError(urlStr + ' is an invalid LDAP url (protocol)'); u.secure = (u.protocol === 'ldaps:'); if (!u.hostname) u.hostname = 'localhost'; if (!u.port) { u.port = (u.secure ? 636 : 389); } else { u.port = parseInt(u.port, 10); } if (u.pathname) { u.pathname = querystring.unescape(u.pathname.substr(1)); u.DN = parseDN ? dn.parse(u.pathname) : u.pathname; } if (u.search) { u.attributes = []; var tmp = u.search.substr(1).split('?'); if (tmp && tmp.length) { if (tmp[0]) { tmp[0].split(',').forEach(function (a) { u.attributes.push(querystring.unescape(a.trim())); }); } } if (tmp[1]) { if (tmp[1] !== 'base' && tmp[1] !== 'one' && tmp[1] !== 'sub') throw new TypeError(urlStr + ' is an invalid LDAP url (scope)'); u.scope = tmp[1]; } if (tmp[2]) { u.filter = querystring.unescape(tmp[2]); } if (tmp[3]) { u.extensions = querystring.unescape(tmp[3]); } if (!u.scope) u.scope = 'base'; if (!u.filter) u.filter = filter.parseString('(objectclass=*)'); else u.filter = filter.parseString(u.filter); } return u; }
n/a
function SearchPager(opts) { assert.object(opts); assert.func(opts.callback); assert.number(opts.pageSize); EventEmitter.call(this, {}); this.callback = opts.callback; this.controls = opts.controls; this.pageSize = opts.pageSize; this.pagePause = opts.pagePause; this.controls.forEach(function (control) { if (control.type === PagedControl.OID) { // The point of using SearchPager is not having to do this. // Toss an error if the pagedResultsControl is present throw new Error('redundant pagedResultControl'); } }); this.finished = false; this.started = false; var emitter = new EventEmitter(); emitter.on('searchEntry', this.emit.bind(this, 'searchEntry')); emitter.on('end', this._onEnd.bind(this)); emitter.on('error', this._onError.bind(this)); this.childEmitter = emitter; }
n/a
function AbandonRequest(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.abandonID); options.protocolOp = Protocol.LDAP_REQ_ABANDON; LDAPMessage.call(this, options); this.abandonID = options.abandonID || 0; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.abandonID = this.abandonID; return j; }
n/a
_parse = function (ber, length) { assert.ok(ber); assert.ok(length); // What a PITA - have to replicate ASN.1 integer logic to work around the // way abandon is encoded and the way ldapjs framework handles "normal" // messages var buf = ber.buffer; var offset = 0; var value = 0; var fb = buf[offset++]; value = fb & 0x7F; for (var i = 1; i < length; i++) { value <<= 8; value |= (buf[offset++] & 0xff); } if ((fb & 0x80) == 0x80) value = -value; ber._offset += length; this.abandonID = value; return true; }
n/a
_toBer = function (ber) { assert.ok(ber); var i = this.abandonID; var sz = 4; while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000)) && (sz > 1)) { sz--; i <<= 8; } assert.ok(sz <= 4); while (sz-- > 0) { ber.writeByte((i & 0xff000000) >> 24); i <<= 8; } return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function AbandonResponse(options) { options = options || {}; assert.object(options); options.protocolOp = 0; LDAPMessage.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
_json = function (j) { return j; }
n/a
end = function (status) {}
...
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
});
```
...
function AbandonedError(message) { LDAPError.call(this, message, null, AbandonedError); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function AddRequest(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.entry); lassert.optionalArrayOfAttribute(options.attributes); options.protocolOp = Protocol.LDAP_REQ_ADD; LDAPMessage.call(this, options); this.entry = options.entry || null; this.attributes = options.attributes ? options.attributes.slice(0) : []; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.entry = this.entry.toString(); j.attributes = []; this.attributes.forEach(function (a) { j.attributes.push(a.json); }); return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.entry = ber.readString(); ber.readSequence(); var end = ber.offset + ber.length; while (ber.offset < end) { var a = new Attribute(); a.parse(ber); a.type = a.type.toLowerCase(); if (a.type === 'objectclass') { for (var i = 0; i < a.vals.length; i++) a.vals[i] = a.vals[i].toLowerCase(); } this.attributes.push(a); } this.attributes.sort(Attribute.compare); return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeString(this.entry.toString()); ber.startSequence(); this.attributes.forEach(function (a) { a.toBer(ber); }); ber.endSequence(); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
addAttribute = function (attr) { if (!(attr instanceof Attribute)) throw new TypeError('attribute (Attribute) required'); return this.attributes.push(attr); }
n/a
attributeNames = function () { var attrs = []; for (var i = 0; i < this.attributes.length; i++) attrs.push(this.attributes[i].type.toLowerCase()); return attrs; }
n/a
getAttribute = function (name) { if (!name || typeof (name) !== 'string') throw new TypeError('attribute name (string) required'); name = name.toLowerCase(); for (var i = 0; i < this.attributes.length; i++) { if (this.attributes[i].type === name) return this.attributes[i]; } return null; }
n/a
indexOf = function (attr) { if (!attr || typeof (attr) !== 'string') throw new TypeError('attr (string) required'); for (var i = 0; i < this.attributes.length; i++) { if (this.attributes[i].type === attr) return i; } return -1; }
n/a
toObject = function () { var self = this; var obj = { dn: self.entry ? self.entry.toString() : '', attributes: {} }; if (!this.attributes || !this.attributes.length) return obj; this.attributes.forEach(function (a) { if (!obj.attributes[a.type]) obj.attributes[a.type] = []; a.vals.forEach(function (v) { if (obj.attributes[a.type].indexOf(v) === -1) obj.attributes[a.type].push(v); }); }); return obj; }
n/a
function AddResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_ADD; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
AdminLimitExceededError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
AffectsMultipleDsasError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
AliasDerefProblemError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
AliasProblemError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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
function Filter() { }
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;
}
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { var str = '(&'; this.filters.forEach(function (f) { str += f.toString(); }); str += ')'; return str; }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
function forEach(cb) { if (this.filter) { // not this.filter.forEach(cb); } else if (this.filters) { // and/or this.filters.forEach(function (item) { item.forEach(cb); }); } cb(this); }
...
module.exports = function () {
if (!SERVER_PROVIDER) {
try {
var dtrace = require('dtrace-provider');
SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs');
Object.keys(SERVER_PROBES).forEach(function (p) {
var args = SERVER_PROBES[p].splice(0);
args.unshift(p);
dtrace.DTraceProvider.prototype.addProbe.apply(SERVER_PROVIDER, args);
});
} catch (e) {
SERVER_PROVIDER = {
...
function map(cb) { var child; if (this.filter) { child = this.filter.map(cb); if (child === null) { // empty NOT not allowed return null; } else { this.filter = child; } } else if (this.filters) { child = this.filters.map(function (item) { return item.map(cb); }).filter(function (item) { return (item !== null); }); if (child.length === 0) { // empty and/or not allowed return null; } else { this.filters = child; } } return cb(this); }
n/a
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); this.value = ber.readString(); return true; }
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
function Filter() { }
n/a
matches = function () { // Consumers must implement this themselves throw new Error('approx match implementation missing'); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { return ('(' + helpers.escape(this.attribute) + '~=' + helpers.escape(this.value) + ')'); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
function Attribute(options) { if (options) { if (typeof (options) !== 'object') throw new TypeError('options must be an object'); if (options.type && typeof (options.type) !== 'string') throw new TypeError('options.type must be a string'); } else { options = {}; } this.type = options.type || ''; this._vals = []; if (options.vals !== undefined && options.vals !== null) this.vals = options.vals; }
n/a
function compare(a, b) { if (!(Attribute.isAttribute(a)) || !(Attribute.isAttribute(b))) { throw new TypeError('can only compare Attributes'); } if (a.type < b.type) return -1; if (a.type > b.type) return 1; if (a.vals.length < b.vals.length) return -1; if (a.vals.length > b.vals.length) return 1; for (var i = 0; i < a.vals.length; i++) { if (a.vals[i] < b.vals[i]) return -1; if (a.vals[i] > b.vals[i]) return 1; } return 0; }
n/a
function isAttribute(attr) { if (!attr || typeof (attr) !== 'object') { return false; } if (attr instanceof Attribute) { return true; } if ((typeof (attr.toBer) === 'function') && (typeof (attr.type) === 'string') && (Array.isArray(attr.vals)) && (attr.vals.filter(function (item) { return (typeof (item) === 'string' || Buffer.isBuffer(item)); }).length === attr.vals.length)) { return true; } return false; }
n/a
toBer = function (attr, ber) { return Attribute.prototype.toBer.call(attr, ber); }
n/a
function addValue(val) { if (Buffer.isBuffer(val)) { this._vals.push(val); } else { this._vals.push(new Buffer(val + '', _bufferEncoding(this.type))); } }
n/a
function parse(ber) { assert.ok(ber); ber.readSequence(); this.type = ber.readString(); if (ber.peek() === Protocol.LBER_SET) { if (ber.readSequence(Protocol.LBER_SET)) { var end = ber.offset + ber.length; while (ber.offset < end) this._vals.push(ber.readString(asn1.Ber.OctetString, true)); } } return true; }
n/a
function toBer(ber) { assert.ok(ber); ber.startSequence(); ber.writeString(this.type); ber.startSequence(Protocol.LBER_SET); if (this._vals.length) { this._vals.forEach(function (b) { ber.writeByte(asn1.Ber.OctetString); ber.writeLength(b.length); for (var i = 0; i < b.length; i++) ber.writeByte(b[i]); }); } else { ber.writeStringArray([]); } ber.endSequence(); ber.endSequence(); return ber; }
n/a
toString = function () { return JSON.stringify(this.json); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
AttributeOrValueExistsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
AuthMethodNotSupportedError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function BindRequest(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REQ_BIND; LDAPMessage.call(this, options); this.version = options.version || 0x03; this.name = options.name || null; this.authentication = options.authentication || LDAP_BIND_SIMPLE; this.credentials = options.credentials || ''; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.version = this.version; j.name = this.name; j.authenticationType = this.authentication; j.credentials = this.credentials; return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.version = ber.readInt(); this.name = ber.readString(); var t = ber.peek(); // TODO add support for SASL et al if (t !== Ber.Context) throw new Error('authentication 0x' + t.toString(16) + ' not supported'); this.authentication = LDAP_BIND_SIMPLE; this.credentials = ber.readString(Ber.Context); return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeInt(this.version); ber.writeString((this.name || '').toString()); // TODO add support for SASL et al ber.writeString((this.credentials || ''), Ber.Context); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function BindResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_BIND; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
BusyError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function Change(options) { if (options) { assert.object(options); assert.optionalString(options.operation); } else { options = {}; } this._modification = false; this.operation = options.operation || options.type || 'add'; this.modification = options.modification || {}; }
n/a
function apply(change, obj, scalar) { assert.string(change.operation); assert.string(change.modification.type); assert.ok(Array.isArray(change.modification.vals)); assert.object(obj); var type = change.modification.type; var vals = change.modification.vals; var data = obj[type]; if (data !== undefined) { if (!Array.isArray(data)) { data = [data]; } } else { data = []; } switch (change.operation) { case 'replace': if (vals.length === 0) { // replace empty is a delete delete obj[type]; return obj; } else { data = vals; } break; case 'add': // add only new unique entries var newValues = vals.filter(function (entry) { return (data.indexOf(entry) === -1); }); data = data.concat(newValues); break; case 'delete': data = data.filter(function (entry) { return (vals.indexOf(entry) === -1); }); if (data.length === 0) { // Erase the attribute if empty delete obj[type]; return obj; } break; default: break; } if (scalar && data.length === 1) { // store single-value outputs as scalars, if requested obj[type] = data[0]; } else { obj[type] = data; } return obj; }
...
var dtrace = require('dtrace-provider');
SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs');
Object.keys(SERVER_PROBES).forEach(function (p) {
var args = SERVER_PROBES[p].splice(0);
args.unshift(p);
dtrace.DTraceProvider.prototype.addProbe.apply(SERVER_PROVIDER, args);
});
} catch (e) {
SERVER_PROVIDER = {
fire: function () {
},
enable: function () {
},
...
compare = function (a, b) { if (!Change.isChange(a) || !Change.isChange(b)) throw new TypeError('can only compare Changes'); if (a.operation < b.operation) return -1; if (a.operation > b.operation) return 1; return Attribute.compare(a.modification, b.modification); }
n/a
function isChange(change) { if (!change || typeof (change) !== 'object') { return false; } if ((change instanceof Change) || ((typeof (change.toBer) === 'function') && (change.modification !== undefined) && (change.operation !== undefined))) { return true; } return false; }
n/a
parse = function (ber) { assert.ok(ber); ber.readSequence(); this._operation = ber.readEnumeration(); this._modification = new Attribute(); this._modification.parse(ber); return true; }
n/a
toBer = function (ber) { assert.ok(ber); ber.startSequence(); ber.writeEnumeration(this._operation); ber = this._modification.toBer(ber); ber.endSequence(); return ber; }
n/a
function Client(options) { assert.ok(options); EventEmitter.call(this, options); var self = this; var _url; if (options.url) _url = url.parse(options.url); this.host = _url ? _url.hostname : undefined; this.port = _url ? _url.port : false; this.secure = _url ? _url.secure : false; this.url = _url; this.tlsOptions = options.tlsOptions; this.socketPath = options.socketPath || false; this.log = options.log.child({clazz: 'Client'}, true); this.timeout = parseInt((options.timeout || 0), 10); this.connectTimeout = parseInt((options.connectTimeout || 0), 10); this.idleTimeout = parseInt((options.idleTimeout || 0), 10); if (options.reconnect) { // Fall back to defaults if options.reconnect === true var rOpts = (typeof (options.reconnect) === 'object') ? options.reconnect : {}; this.reconnect = { initialDelay: parseInt(rOpts.initialDelay || 100, 10), maxDelay: parseInt(rOpts.maxDelay || 10000, 10), failAfter: parseInt(rOpts.failAfter, 10) || Infinity }; } this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true; this.queue = new RequestQueue({ size: parseInt((options.queueSize || 0), 10), timeout: parseInt((options.queueTimeout || 0), 10) }); if (options.queueDisable) { this.queue.freeze(); } // Implicitly configure setup action to bind the client if bindDN and // bindCredentials are passed in. This will more closely mimic PooledClient // auto-login behavior. if (options.bindDN !== undefined && options.bindCredentials !== undefined) { this.on('setup', function (clt, cb) { clt.bind(options.bindDN, options.bindCredentials, function (err) { if (err) { self.emit('error', err); } cb(err); }); }); } this._socket = null; this.connected = false; this.connect(); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function _flushQueue() { // Pull items we're about to process out of the queue. this.queue.flush(this._send.bind(this)); }
n/a
function _onClose(had_err) { var socket = this._socket; var tracker = this._tracker; socket.removeAllListeners('connect') .removeAllListeners('data') .removeAllListeners('drain') .removeAllListeners('end') .removeAllListeners('error') .removeAllListeners('timeout'); this._socket = null; this.connected = false; ((socket.socket) ? socket.socket : socket).removeAllListeners('close'); if (this.log.trace()) this.log.trace('close event had_err=%s', had_err ? 'yes' : 'no'); this.emit('close', had_err); // On close we have to walk the outstanding messages and go invoke their // callback with an error. tracker.pending.forEach(function (msgid) { var cb = tracker.fetch(msgid); tracker.remove(msgid); if (socket.unbindMessageID !== parseInt(msgid, 10)) { return cb(new ConnectionError(tracker.id + ' closed')); } else { // Unbinds will be communicated as a success since we're closed var unbind = new UnbindResponse({messageID: msgid}); unbind.status = 'unbind'; return cb(unbind); } }); // Trash any parser or starttls state this._tracker = null; delete this._starttls; // Automatically fire reconnect logic if the socket was closed for any reason // other than a user-initiated unbind. if (this.reconnect && !this.unbound) { this.connect(); } this.unbound = false; return false; }
n/a
function _send(message, expect, emitter, callback, _bypass) { assert.ok(message); assert.ok(expect); assert.optionalObject(emitter); assert.ok(callback); // Allow connect setup traffic to bypass checks if (_bypass && this._socket && this._socket.writable) { return this._sendSocket(message, expect, emitter, callback); } if (!this._socket || !this.connected) { if (!this.queue.enqueue(message, expect, emitter, callback)) { callback(new ConnectionError('connection unavailable')); } // Initiate reconnect if needed if (this.reconnect) { this.connect(); } return false; } else { this._flushQueue(); return this._sendSocket(message, expect, emitter, callback); } }
n/a
function _sendSocket(message, expect, emitter, callback) { var conn = this._socket; var tracker = this._tracker; var log = this.log; var self = this; var timer = false; var sentEmitter = false; function sendResult(event, obj) { if (event === 'error' && self.listeners('resultError')) { self.emit('resultError', obj); } if (emitter) { if (event === 'error') { // Error will go unhandled if emitter hasn't been sent via callback. // Execute callback with the error instead. if (!sentEmitter) return callback(obj); } return emitter.emit(event, obj); } if (event === 'error') return callback(obj); return callback(null, obj); } function messageCallback(msg) { if (timer) clearTimeout(timer); if (log.trace()) log.trace({msg: msg ? msg.json : null}, 'response received'); if (expect === 'abandon') return sendResult('end', null); if (msg instanceof SearchEntry || msg instanceof SearchReference) { var event = msg.constructor.name; event = event[0].toLowerCase() + event.slice(1); return sendResult(event, msg); } else { tracker.remove(message.messageID); // Potentially mark client as idle self._updateIdle(); if (msg instanceof LDAPResult) { if (expect.indexOf(msg.status) === -1) { return sendResult('error', errors.getError(msg)); } return sendResult('end', msg); } else if (msg instanceof Error) { return sendResult('error', msg); } else { return sendResult('error', new errors.ProtocolError(msg.type)); } } } function onRequestTimeout() { self.emit('timeout', message); var cb = tracker.fetch(message.messageID); if (cb) { //FIXME: the timed-out request should be abandoned cb(new errors.TimeoutError('request timeout (client interrupt)')); } } function writeCallback() { if (expect === 'abandon') { // Mark the messageID specified as abandoned tracker.abandon(message.abandonID); // No need to track the abandon request itself tracker.remove(message.id); return callback(null); } else if (expect === 'unbind') { conn.unbindMessageID = message.id; // Mark client as disconnected once unbind clears the socket self.connected = false; // Some servers will RST the connection after receiving an unbind. // Socket errors are blackholed since the connection is being closed. conn.removeAllListeners('error'); conn.on('error', function () {}); conn.end(); } else if (emitter) { sentEmitter = true; return callback(null, emitter); } return false; } // Start actually doing something... tracker.track(message, messageCallback); // Mark client as active this._updateIdle(true); if (self.timeout) { log.trace('Setting timeout to %d', self.timeout); timer = setTimeout(onRequestTimeout, self.timeout); } if (log.trace()) log.trace('sending request %j', message.json); try { return conn.write(message.toBer(), writeCallback); } catch (e) { if (timer) clearTimeout(timer); log.trace({err: e}, 'Error writing message to socket'); return callback(e); } }
n/a
function _updateIdle(override) { if (this.idleTimeout === 0) { return; } // Client must be connected but not waiting on any request data var self = this; function isIdle(disable) { return ((disable !== true) && (self._socket && self.connected) && (self._tracker.pending.length === 0)); } if (isIdle(override)) { if (!this._idleTimer) { this._idleTimer = setTimeout(function () { // Double-check idleness in case socket was torn down if (isIdle()) { self.emit('idle'); } }, this.idleTimeout); } } else { if (this._idleTimer) { clearTimeout(this._idleTimer); this._idleTimer = null; } } }
n/a
function abandon(messageID, controls, callback) { assert.number(messageID, 'messageID'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); var req = new AbandonRequest({ abandonID: messageID, controls: controls }); return this._send(req, 'abandon', null, callback); }
n/a
function add(name, entry, controls, callback) { assert.ok(name !== undefined, 'name'); assert.object(entry, 'entry'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); if (Array.isArray(entry)) { entry.forEach(function (a) { if (!Attribute.isAttribute(a)) throw new TypeError('entry must be an Array of Attributes'); }); } else { var save = entry; entry = []; Object.keys(save).forEach(function (k) { var attr = new Attribute({type: k}); if (Array.isArray(save[k])) { save[k].forEach(function (v) { attr.addValue(v.toString()); }); } else { attr.addValue(save[k].toString()); } entry.push(attr); }); } var req = new AddRequest({ entry: ensureDN(name, this.strictDN), attributes: entry, controls: controls }); return this._send(req, [errors.LDAP_SUCCESS], null, callback); }
n/a
function bind(name, credentials, controls, callback, _bypass) { if (typeof (name) !== 'string' && !(name instanceof dn.DN)) throw new TypeError('name (string) required'); assert.optionalString(credentials, 'credentials'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); var req = new BindRequest({ name: name || '', authentication: 'Simple', credentials: credentials || '', controls: controls }); return this._send(req, [errors.LDAP_SUCCESS], null, callback, _bypass); }
...
}
});
this.finished = false;
this.started = false;
var emitter = new EventEmitter();
emitter.on('searchEntry', this.emit.bind(this, 'searchEntry'));
emitter.on('end', this._onEnd.bind(this));
emitter.on('error', this._onError.bind(this));
this.childEmitter = emitter;
}
util.inherits(SearchPager, EventEmitter);
module.exports = SearchPager;
...
function compare(name, attr, value, controls, callback) { assert.ok(name !== undefined, 'name'); assert.string(attr, 'attr'); assert.string(value, 'value'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); var req = new CompareRequest({ entry: ensureDN(name, this.strictDN), attribute: attr, value: value, controls: controls }); return this._send(req, CMP_EXPECT, null, function (err, res) { if (err) return callback(err); return callback(null, (res.status === errors.LDAP_COMPARE_TRUE), res); }); }
n/a
function connect() { if (this.connecting || this.connected) { return; } var self = this; var log = this.log; var socket; var tracker; // Establish basic socket connection function connectSocket(cb) { cb = once(cb); function onResult(err, res) { if (err) { if (self.connectTimer) { clearTimeout(self.connectTimer); self.connectTimer = null; } self.emit('connectError', err); } cb(err, res); } function onConnect() { if (self.connectTimer) { clearTimeout(self.connectTimer); self.connectTimer = null; } socket.removeAllListeners('error') .removeAllListeners('connect') .removeAllListeners('secureConnect'); tracker.id = nextClientId() + '__' + tracker.id; self.log = self.log.child({ldap_id: tracker.id}, true); // Move on to client setup setupClient(cb); } var port = (self.port || self.socketPath); if (self.secure) { socket = tls.connect(port, self.host, self.tlsOptions); socket.once('secureConnect', onConnect); } else { socket = net.connect(port, self.host); socket.once('connect', onConnect); } socket.once('error', onResult); initSocket(); // Setup connection timeout handling, if desired if (self.connectTimeout) { self.connectTimer = setTimeout(function onConnectTimeout() { if (!socket || !socket.readable || !socket.writeable) { socket.destroy(); self._socket = null; onResult(new ConnectionError('connection timeout')); } }, self.connectTimeout); } } // Initialize socket events and LDAP parser. function initSocket() { tracker = new MessageTracker({ id: self.url ? self.url.href : self.socketPath, parser: new Parser({log: log}) }); // This won't be set on TLS. So. Very. Annoying. if (typeof (socket.setKeepAlive) !== 'function') { socket.setKeepAlive = function setKeepAlive(enable, delay) { return socket.socket ? socket.socket.setKeepAlive(enable, delay) : false; }; } socket.on('data', function onData(data) { if (log.trace()) log.trace('data event: %s', util.inspect(data)); tracker.parser.write(data); }); // The "router" tracker.parser.on('message', function onMessage(message) { message.connection = self._socket; var callback = tracker.fetch(message.messageID); if (!callback) { log.error({message: message.json}, 'unsolicited message'); return false; } return callback(message); }); tracker.parser.on('error', function onParseError(err) { self.emit('error', new VError(err, 'Parser error for %s', tracker.id)); self.connected = false; socket.end(); }); } // After connect, register socket event handlers and run any setup actions function setupClient(cb) { cb = once(cb); // Indicate failure if anything goes awry during setup function bail(err) { socket.destroy(); cb(err || new Error('client error during setup')); } // Work around lack of close event on tls.socket in node < 0.11 ((socket.socket) ? socket.socket : socket).once('close', bail); socket.once('error', bail); socket.once('end', bail); socket.once('timeout', bail); self._socket = socket; self._tracker = tracker; // Run any requested setup (such as automatically performing a bind) on // socket before signalling successful connection. // This setup needs to bypass the request queue since all other activity is // blocked until the connection is considered fully established post-setup. // Only allow bind/search/starttls for now. var basicClient = { bind: function bindBypass(name, credentials, controls, callback) { return self.bind(name, credentials, controls, callback, true); }, search: function searchBypass(base, options, controls, callback) { return self.search(base, option ...
n/a
function del(name, controls, callback) { assert.ok(name !== undefined, 'name'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); var req = new DeleteRequest({ entry: ensureDN(name, this.strictDN), controls: controls }); return this._send(req, [errors.LDAP_SUCCESS], null, callback); }
n/a
function destroy(err) { this.destroyed = true; this.queue.freeze(); // Purge any queued requests which are now meaningless this.queue.flush(function (msg, expect, emitter, cb) { if (typeof (cb) === 'function') { cb(new Error('client destroyed')); } }); if (this.connected) { this.unbind(); } else if (this._socket) { this._socket.destroy(); } this.emit('destroy', err); }
n/a
function exop(name, value, controls, callback) { assert.string(name, 'name'); if (typeof (value) === 'function') { callback = value; controls = []; value = ''; } if (!(Buffer.isBuffer(value) || typeof (value) === 'string')) throw new TypeError('value (Buffer || string) required'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); var req = new ExtendedRequest({ requestName: name, requestValue: value, controls: controls }); return this._send(req, [errors.LDAP_SUCCESS], null, function (err, res) { if (err) return callback(err); return callback(null, res.responseValue || '', res); }); }
n/a
function modify(name, change, controls, callback) { assert.ok(name !== undefined, 'name'); assert.object(change, 'change'); var changes = []; function changeFromObject(change) { if (!change.operation && !change.type) throw new Error('change.operation required'); if (typeof (change.modification) !== 'object') throw new Error('change.modification (object) required'); if (Object.keys(change.modification).length == 2 && typeof (change.modification.type) === 'string' && Array.isArray(change.modification.vals)) { // Use modification directly if it's already normalized: changes.push(new Change({ operation: change.operation || change.type, modification: change.modification })); } else { // Normalize the modification object Object.keys(change.modification).forEach(function (k) { var mod = {}; mod[k] = change.modification[k]; changes.push(new Change({ operation: change.operation || change.type, modification: mod })); }); } } if (Change.isChange(change)) { changes.push(change); } else if (Array.isArray(change)) { change.forEach(function (c) { if (Change.isChange(c)) { changes.push(c); } else { changeFromObject(c); } }); } else { changeFromObject(change); } if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); var req = new ModifyRequest({ object: ensureDN(name, this.strictDN), changes: changes, controls: controls }); return this._send(req, [errors.LDAP_SUCCESS], null, callback); }
n/a
function modifyDN(name, newName, controls, callback) { assert.ok(name !== undefined, 'name'); assert.string(newName, 'newName'); if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback); var DN = ensureDN(name); // TODO: is non-strict handling desired here? var newDN = dn.parse(newName); var req = new ModifyDNRequest({ entry: DN, deleteOldRdn: true, controls: controls }); if (newDN.length !== 1) { req.newRdn = dn.parse(newDN.rdns.shift().toString()); req.newSuperior = newDN; } else { req.newRdn = newDN; } return this._send(req, [errors.LDAP_SUCCESS], null, callback); }
n/a
function search(base, options, controls, callback, _bypass) { assert.ok(base !== undefined, 'search base'); if (Array.isArray(options) || (options instanceof Control)) { controls = options; options = {}; } else if (typeof (options) === 'function') { callback = options; controls = []; options = { filter: new PresenceFilter({attribute: 'objectclass'}) }; } else if (typeof (options) === 'string') { options = {filter: filters.parseString(options)}; } else if (typeof (options) !== 'object') { throw new TypeError('options (object) required'); } if (typeof (options.filter) === 'string') { options.filter = filters.parseString(options.filter); } else if (!options.filter) { options.filter = new PresenceFilter({attribute: 'objectclass'}); } else if (!filters.isFilter(options.filter)) { throw new TypeError('options.filter (Filter) required'); } if (typeof (controls) === 'function') { callback = controls; controls = []; } else { controls = validateControls(controls); } assert.func(callback, 'callback'); if (options.attributes) { if (!Array.isArray(options.attributes)) { if (typeof (options.attributes) === 'string') { options.attributes = [options.attributes]; } else { throw new TypeError('options.attributes must be an Array of Strings'); } } } var self = this; var baseDN = ensureDN(base, this.strictDN); function sendRequest(ctrls, emitter, cb) { var req = new SearchRequest({ baseObject: baseDN, scope: options.scope || 'base', filter: options.filter, derefAliases: options.derefAliases || Protocol.NEVER_DEREF_ALIASES, sizeLimit: options.sizeLimit || 0, timeLimit: options.timeLimit || 10, typesOnly: options.typesOnly || false, attributes: options.attributes || [], controls: ctrls }); return self._send(req, [errors.LDAP_SUCCESS], emitter, cb, _bypass); } if (options.paged) { // Perform automated search paging var pageOpts = typeof (options.paged) === 'object' ? options.paged : {}; var size = 100; // Default page size if (pageOpts.pageSize > 0) { size = pageOpts.pageSize; } else if (options.sizeLimit > 1) { // According to the RFC, servers should ignore the paging control if // pageSize >= sizelimit. Some might still send results, but it's safer // to stay under that figure when assigning a default value. size = options.sizeLimit - 1; } var pager = new SearchPager({ callback: callback, controls: controls, pageSize: size, pagePause: pageOpts.pagePause }); pager.on('search', sendRequest); pager.begin(); } else { sendRequest(controls, new EventEmitter(), callback); } }
...
For full docs, head on over to <http://ldapjs.org>.
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
...
function starttls(options, controls, callback, _bypass) {
assert.optionalObject(options);
options = options || {};
callback = once(callback);
var self = this;
if (this._starttls) {
return callback(new Error('STARTTLS already in progress or active'));
}
function onSend(err, emitter) {
if (err) {
callback(err);
return;
}
/*
* Now that the request has been sent, block all outgoing messages
* until an error is received or we successfully complete the setup.
*/
// TODO: block traffic
self._starttls = {
started: true
};
emitter.on('error', function (err) {
self._starttls = null;
callback(err);
});
emitter.on('end', function (res) {
var sock = self._socket;
/*
* Unplumb socket data during SSL negotiation.
* This will prevent the LDAP parser from stumbling over the TLS
* handshake and raising a ruckus.
*/
sock.removeAllListeners('data');
options.socket = sock;
var secure = tls.connect(options);
secure.once('secureConnect', function () {
/*
* Wire up 'data' and 'error' handlers like the normal socket.
* Handling 'end' events isn't necessary since the underlying socket
* will handle those.
*/
secure.removeAllListeners('error');
secure.on('data', function onData(data) {
if (self.log.trace())
self.log.trace('data event: %s', util.inspect(data));
self._tracker.parser.write(data);
});
secure.on('error', function (err) {
if (self.log.trace())
self.log.trace({err: err}, 'error event: %s', new Error().stack);
self.emit('error', err);
sock.destroy();
});
callback(null);
});
secure.once('error', function (err) {
// If the SSL negotiation failed, to back to plain mode.
self._starttls = null;
secure.removeAllListeners();
callback(err);
});
self._starttls.success = true;
self._socket = secure;
});
}
var req = new ExtendedRequest({
requestName: '1.3.6.1.4.1.1466.20037',
requestValue: null,
controls: controls
});
return this._send(req,
[errors.LDAP_SUCCESS],
new EventEmitter(),
onSend,
_bypass);
}
n/a
function unbind(callback) { if (!callback) callback = function () {}; if (typeof (callback) !== 'function') throw new TypeError('callback must be a function'); // When the socket closes, it is useful to know whether it was due to a // user-initiated unbind or something else. this.unbound = true; if (!this._socket) return callback(); var req = new UnbindRequest(); return this._send(req, 'unbind', null, callback); }
n/a
CompareFalseError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function CompareRequest(options) { options = options || {}; assert.object(options); assert.optionalString(options.attribute); assert.optionalString(options.value); lassert.optionalStringDN(options.entry); options.protocolOp = Protocol.LDAP_REQ_COMPARE; LDAPMessage.call(this, options); this.entry = options.entry || null; this.attribute = options.attribute || ''; this.value = options.value || ''; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.entry = this.entry.toString(); j.attribute = this.attribute; j.value = this.value; return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.entry = ber.readString(); ber.readSequence(); this.attribute = ber.readString().toLowerCase(); this.value = ber.readString(); return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeString(this.entry.toString()); ber.startSequence(); ber.writeString(this.attribute); ber.writeString(this.value); ber.endSequence(); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function CompareResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_COMPARE; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
end = function (matches) { var status = 0x06; if (typeof (matches) === 'boolean') { if (!matches) status = 0x05; // Compare false } else { status = matches; } return LDAPResult.prototype.end.call(this, status); }
...
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
});
```
...
CompareTrueError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
ConfidentialityRequiredError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function ConnectionError(message) { LDAPError.call(this, message, null, ConnectionError); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
ConstraintViolationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
function toBer(ber) { assert.ok(ber); ber.startSequence(); ber.writeString(this.type || ''); ber.writeBoolean(this.criticality); if (typeof (this._toBer) === 'function') { this._toBer(ber); } else { if (this.value) ber.writeString(this.value); } ber.endSequence(); return; }
n/a
function toString() { return this.json; }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
function DN(rdns) { assert.optionalArrayOfObject(rdns, '[object] required'); this.rdns = rdns ? rdns.slice() : []; this._format = {}; }
n/a
function isDN(dn) { if (!dn || typeof (dn) !== 'object') { return false; } if (dn instanceof DN) { return true; } if (Array.isArray(dn.rdns)) { // Really simple duck-typing for now return true; } return false; }
n/a
function childOf(dn) { if (typeof (dn) !== 'object') dn = parse(dn); return dn.parentOf(this); }
n/a
function dnClone() { var dn = new DN(this.rdns); dn._format = this._format; return dn; }
n/a
function dnEquals(dn) { if (typeof (dn) !== 'object') dn = parse(dn); if (this.rdns.length !== dn.rdns.length) return false; for (var i = 0; i < this.rdns.length; i++) { if (!this.rdns[i].equals(dn.rdns[i])) return false; } return true; }
n/a
function dnFormat(options) { assert.optionalObject(options, 'options must be an object'); options = options || this._format; var str = ''; this.rdns.forEach(function (rdn) { var rdnString = rdn.format(options); if (str.length !== 0) { str += ','; } if (options.keepSpace) { str += (repeatChar(' ', rdn.spLead) + rdnString + repeatChar(' ', rdn.spTrail)); } else if (options.skipSpace === true || str.length === 0) { str += rdnString; } else { str += ' ' + rdnString; } }); return str; }
...
///--- Helpers
// Copied from mcavage/node-assert-plus
function _assert(arg, type, name) {
name = name || type;
throw new assert.AssertionError({
message: util.format('%s (%s) required', name, type),
actual: typeof (arg),
expected: type,
operator: '===',
stackStartFunction: _assert.caller
});
}
...
function isEmpty() { return (this.rdns.length === 0); }
n/a
function dnParent() { if (this.rdns.length !== 0) { var save = this.rdns.shift(); var dn = new DN(this.rdns); this.rdns.unshift(save); return dn; } return null; }
n/a
function parentOf(dn) { if (typeof (dn) !== 'object') dn = parse(dn); if (this.rdns.length >= dn.rdns.length) return false; var diff = dn.rdns.length - this.rdns.length; for (var i = this.rdns.length - 1; i >= 0; i--) { var myRDN = this.rdns[i]; var theirRDN = dn.rdns[i + diff]; if (!myRDN.equals(theirRDN)) return false; } return true; }
n/a
function dnPop() { return this.rdns.pop(); }
n/a
function dnPush(rdn) { assert.object(rdn, 'rdn (RDN) required'); return this.rdns.push(rdn); }
...
};
/**
* Initiate a search for the next page using the returned cookie value.
*/
SearchPager.prototype._nextPage = function _nextPage(cookie) {
var controls = this.controls.slice(0);
controls.push(new PagedControl({
value: {
size: this.pageSize,
cookie: cookie
}
}));
this.emit('search', controls, this.childEmitter,
...
function dnReverse() { this.rdns.reverse(); return this; }
n/a
function setFormat(options) { assert.object(options, 'options must be an object'); this._format = options; }
n/a
function dnShift() { return this.rdns.shift(); }
n/a
function dnToString() { return this.format(); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
function dnUnshift(rdn) { assert.object(rdn, 'rdn (RDN) required'); return this.rdns.unshift(rdn); }
...
if (!SERVER_PROVIDER) {
try {
var dtrace = require('dtrace-provider');
SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs');
Object.keys(SERVER_PROBES).forEach(function (p) {
var args = SERVER_PROBES[p].splice(0);
args.unshift(p);
dtrace.DTraceProvider.prototype.addProbe.apply(SERVER_PROVIDER, args);
});
} catch (e) {
SERVER_PROVIDER = {
fire: function () {
},
...
function DeleteRequest(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.entry); options.protocolOp = Protocol.LDAP_REQ_DELETE; LDAPMessage.call(this, options); this.entry = options.entry || null; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.entry = this.entry; return j; }
n/a
_parse = function (ber, length) { assert.ok(ber); this.entry = ber.buffer.slice(0, length).toString('utf8'); ber._offset += ber.length; return true; }
n/a
_toBer = function (ber) { assert.ok(ber); var buf = new Buffer(this.entry.toString()); for (var i = 0; i < buf.length; i++) ber.writeByte(buf[i]); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function DeleteResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_DELETE; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
EntryAlreadyExistsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function EntryChangeNotificationControl(options) { assert.optionalObject(options); options = options || {}; options.type = EntryChangeNotificationControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
_json = function (obj) { obj.controlValue = this.value; return obj; }
n/a
_toBer = function (ber) { assert.ok(ber); if (!this._value) return; var writer = new BerWriter(); writer.startSequence(); writer.writeInt(this.value.changeType); if (this.value.previousDN) writer.writeString(this.value.previousDN); writer.writeInt(parseInt(this.value.changeNumber, 10)); writer.endSequence(); ber.writeBuffer(writer.buffer, 0x04); }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); if (ber.readSequence()) { this._value = { changeType: ber.readInt() }; // if the operation was moddn, then parse the optional previousDN attr if (this._value.changeType === 8) this._value.previousDN = ber.readString(); this._value.changeNumber = ber.readInt(); return true; } return false; }
n/a
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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);
}
}
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
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; }
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
function Filter() { }
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); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { return ('(' + helpers.escape(this.attribute) + '=' + helpers.escape(this.value) + ')'); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
function ExtendedRequest(options) { options = options || {}; assert.object(options); assert.optionalString(options.requestName); if (options.requestValue && !(Buffer.isBuffer(options.requestValue) || typeof (options.requestValue) === 'string')) { throw new TypeError('options.requestValue must be a buffer or a string'); } options.protocolOp = Protocol.LDAP_REQ_EXTENSION; LDAPMessage.call(this, options); this.requestName = options.requestName || ''; this.requestValue = options.requestValue; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.requestName = this.requestName; j.requestValue = (Buffer.isBuffer(this.requestValue)) ? this.requestValue.toString('hex') : this.requestValue; return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.requestName = ber.readString(0x80); if (ber.peek() === 0x81) try { this.requestValue = ber.readString(0x81); } catch (e) { this.requestValue = ber.readBuffer(0x81); } return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeString(this.requestName, 0x80); if (Buffer.isBuffer(this.requestValue)) { ber.writeBuffer(this.requestValue, 0x81); } else if (typeof (this.requestValue) === 'string') { ber.writeString(this.requestValue, 0x81); } return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function ExtendedResponse(options) { options = options || {}; assert.object(options); assert.optionalString(options.responseName); assert.optionalString(options.responsevalue); this.responseName = options.responseName || undefined; this.responseValue = options.responseValue || undefined; options.protocolOp = Protocol.LDAP_REP_EXTENSION; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
_json = function (j) { assert.ok(j); j = LDAPResult.prototype._json.call(this, j); j.responseName = this.responseName; j.responseValue = this.responseValue; return j; }
n/a
_parse = function (ber) { assert.ok(ber); if (!LDAPResult.prototype._parse.call(this, ber)) return false; if (ber.peek() === 0x8a) this.responseName = ber.readString(0x8a); if (ber.peek() === 0x8b) this.responseValue = ber.readString(0x8b); return true; }
n/a
_toBer = function (ber) { assert.ok(ber); if (!LDAPResult.prototype._toBer.call(this, ber)) return false; if (this.responseName) ber.writeString(this.responseName, 0x8a); if (this.responseValue) ber.writeString(this.responseValue, 0x8b); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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; }
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
function Filter() { }
n/a
matches = function () { // Consumers must implement this themselves throw new Error('ext match implementation missing'); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
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 + ')'); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); this.value = ber.readString(); return true; }
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
function Filter() { }
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); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { return ('(' + helpers.escape(this.attribute) + '>=' + helpers.escape(this.value) + ')'); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
InappropriateAuthenticationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
InappropriateMatchingError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
InsufficientAccessRightsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
InvalidAttributeSyntaxError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
InvalidCredentialsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
InvalidDnSyntaxError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function Error() { [native code] }
n/a
function Error() { [native code] }
n/a
function captureStackTrace() { [native code] }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
parse = function (ber) { assert.ok(ber); if (this.log.trace()) this.log.trace('parse: data=%s', util.inspect(ber.buffer)); // Delegate off to the specific type to parse this._parse(ber, ber.length); // Look for controls if (ber.peek() === 0xa0) { ber.readSequence(); var end = ber.offset + ber.length; while (ber.offset < end) { var c = getControl(ber); if (c) this.controls.push(c); } } if (this.log.trace()) this.log.trace('Parsing done: %j', this.json); return true; }
n/a
toBer = function () { var writer = new BerWriter(); writer.startSequence(); writer.writeInt(this.messageID); writer.startSequence(this.protocolOp); if (this._toBer) writer = this._toBer(writer); writer.endSequence(); if (this.controls && this.controls.length) { writer.startSequence(0xa0); this.controls.forEach(function (c) { c.toBer(writer); }); writer.endSequence(); } writer.endSequence(); return writer.buffer; }
n/a
toString = function () { return JSON.stringify(this.json); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.status = this.status; j.matchedDN = this.matchedDN; j.errorMessage = this.errorMessage; j.referrals = this.referrals; return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.status = ber.readEnumeration(); this.matchedDN = ber.readString(); this.errorMessage = ber.readString(); var t = ber.peek(); if (t === Protocol.LDAP_REP_REFERRAL) { var end = ber.offset + ber.length; while (ber.offset < end) this.referrals.push(ber.readString()); } return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeEnumeration(this.status); ber.writeString(this.matchedDN || ''); ber.writeString(this.errorMessage || ''); if (this.referrals.length) { ber.startSequence(Protocol.LDAP_REP_REFERRAL); ber.writeStringArray(this.referrals); ber.endSequence(); } return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
end = function (status) { assert.ok(this.connection); if (typeof (status) === 'number') this.status = status; var ber = this.toBer(); if (this.log.debug()) this.log.debug('%s: sending: %j', this.connection.ldap.id, this.json); try { var self = this; this.connection.write(ber); if (self._dtraceOp && self._dtraceId) { dtrace.fire('server-' + self._dtraceOp + '-done', function () { var c = self.connection || {ldap: {}}; return [ self._dtraceId || 0, (c.remoteAddress || ''), c.ldap.bindDN ? c.ldap.bindDN.toString() : '', (self.requestDN ? self.requestDN.toString() : ''), status || self.status, self.errorMessage ]; }); } } catch (e) { this.log.warn(e, '%s failure to write message %j', this.connection.ldap.id, this.json); } }
...
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
});
```
...
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
parse = function (ber) { assert.ok(ber); this.attribute = ber.readString().toLowerCase(); this.value = ber.readString(); return true; }
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
function Filter() { }
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); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { return ('(' + helpers.escape(this.attribute) + '<=' + helpers.escape(this.value) + ')'); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
LoopDetectError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function ModifyDNRequest(options) { options = options || {}; assert.object(options); assert.optionalBool(options.deleteOldRdn); lassert.optionalStringDN(options.entry); lassert.optionalDN(options.newRdn); lassert.optionalDN(options.newSuperior); options.protocolOp = Protocol.LDAP_REQ_MODRDN; LDAPMessage.call(this, options); this.entry = options.entry || null; this.newRdn = options.newRdn || null; this.deleteOldRdn = options.deleteOldRdn || true; this.newSuperior = options.newSuperior || null; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.entry = this.entry.toString(); j.newRdn = this.newRdn.toString(); j.deleteOldRdn = this.deleteOldRdn; j.newSuperior = this.newSuperior ? this.newSuperior.toString() : ''; return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.entry = ber.readString(); this.newRdn = dn.parse(ber.readString()); this.deleteOldRdn = ber.readBoolean(); if (ber.peek() === 0x80) this.newSuperior = dn.parse(ber.readString(0x80)); return true; }
n/a
_toBer = function (ber) { //assert.ok(ber); ber.writeString(this.entry.toString()); ber.writeString(this.newRdn.toString()); ber.writeBoolean(this.deleteOldRdn); if (this.newSuperior) { var s = this.newSuperior.toString(); var len = Buffer.byteLength(s); ber.writeByte(0x80); // MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG ber.writeByte(len); ber._ensure(len); ber._buf.write(s, ber._offset); ber._offset += len; } return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function ModifyDNResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_MODRDN; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
function ModifyRequest(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.object); lassert.optionalArrayOfAttribute(options.attributes); options.protocolOp = Protocol.LDAP_REQ_MODIFY; LDAPMessage.call(this, options); this.object = options.object || null; this.changes = options.changes ? options.changes.slice(0) : []; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.object = this.object; j.changes = []; this.changes.forEach(function (c) { j.changes.push(c.json); }); return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.object = ber.readString(); ber.readSequence(); var end = ber.offset + ber.length; while (ber.offset < end) { var c = new Change(); c.parse(ber); c.modification.type = c.modification.type.toLowerCase(); this.changes.push(c); } this.changes.sort(Change.compare); return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeString(this.object.toString()); ber.startSequence(); this.changes.forEach(function (c) { c.toBer(ber); }); ber.endSequence(); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function ModifyResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_MODIFY; LDAPResult.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
NamingViolationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
NoSuchAttributeError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
NoSuchObjectError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
NotAllowedOnNonLeafError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
NotAllowedOnRdnError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
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); }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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
function Filter() { }
n/a
addFilter = function (filter) { assert.object(filter, 'filter'); this.filter = filter; }
n/a
matches = function (target, strictAttrCase) { return !this.filter.matches(target, strictAttrCase); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { return '(!' + this.filter.toString() + ')'; }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
ObjectclassModsProhibitedError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
ObjectclassViolationError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
OperationsError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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
function Filter() { }
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; }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { var str = '(|'; this.filters.forEach(function (f) { str += f.toString(); }); str += ')'; return str; }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
OtherError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function PagedResultsControl(options) { assert.optionalObject(options); options = options || {}; options.type = PagedResultsControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
_json = function (obj) { obj.controlValue = this.value; return obj; }
n/a
_toBer = function (ber) { assert.ok(ber); if (!this._value) return; var writer = new BerWriter(); writer.startSequence(); writer.writeInt(this.value.size); if (this.value.cookie && this.value.cookie.length > 0) { writer.writeBuffer(this.value.cookie, asn1.Ber.OctetString); } else { writer.writeString(''); //writeBuffer rejects zero-length buffers } writer.endSequence(); ber.writeBuffer(writer.buffer, 0x04); }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); if (ber.readSequence()) { this._value = {}; this._value.size = ber.readInt(); this._value.cookie = ber.readString(asn1.Ber.OctetString, true); //readString returns '' instead of a zero-length buffer if (!this._value.cookie) this._value.cookie = new Buffer(0); return true; } return false; }
n/a
function Parser(options) { assert.object(options); assert.object(options.log); EventEmitter.call(this); this.buffer = null; this.log = options.log; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
getMessage = function (ber) { assert.ok(ber); var self = this; var messageID = ber.readInt(); var type = ber.readSequence(); var Message; switch (type) { case Protocol.LDAP_REQ_ABANDON: Message = AbandonRequest; break; case Protocol.LDAP_REQ_ADD: Message = AddRequest; break; case Protocol.LDAP_REP_ADD: Message = AddResponse; break; case Protocol.LDAP_REQ_BIND: Message = BindRequest; break; case Protocol.LDAP_REP_BIND: Message = BindResponse; break; case Protocol.LDAP_REQ_COMPARE: Message = CompareRequest; break; case Protocol.LDAP_REP_COMPARE: Message = CompareResponse; break; case Protocol.LDAP_REQ_DELETE: Message = DeleteRequest; break; case Protocol.LDAP_REP_DELETE: Message = DeleteResponse; break; case Protocol.LDAP_REQ_EXTENSION: Message = ExtendedRequest; break; case Protocol.LDAP_REP_EXTENSION: Message = ExtendedResponse; break; case Protocol.LDAP_REQ_MODIFY: Message = ModifyRequest; break; case Protocol.LDAP_REP_MODIFY: Message = ModifyResponse; break; case Protocol.LDAP_REQ_MODRDN: Message = ModifyDNRequest; break; case Protocol.LDAP_REP_MODRDN: Message = ModifyDNResponse; break; case Protocol.LDAP_REQ_SEARCH: Message = SearchRequest; break; case Protocol.LDAP_REP_SEARCH_ENTRY: Message = SearchEntry; break; case Protocol.LDAP_REP_SEARCH_REF: Message = SearchReference; break; case Protocol.LDAP_REP_SEARCH: Message = SearchResponse; break; case Protocol.LDAP_REQ_UNBIND: Message = UnbindRequest; break; default: this.emit('error', new Error('Op 0x' + (type ? type.toString(16) : '??') + ' not supported'), new LDAPResult({ messageID: messageID, protocolOp: type || Protocol.LDAP_REP_EXTENSION })); return false; } return new Message({ messageID: messageID, log: self.log }); }
n/a
write = function (data) { if (!data || !Buffer.isBuffer(data)) throw new TypeError('data (buffer) required'); var nextMessage = null; var self = this; function end() { if (nextMessage) return self.write(nextMessage); return true; } self.buffer = (self.buffer ? Buffer.concat([self.buffer, data]) : data); var ber = new BerReader(self.buffer); var foundSeq = false; try { foundSeq = ber.readSequence(); } catch (e) { this.emit('error', e); } if (!foundSeq || ber.remain < ber.length) { // ENOTENOUGH return false; } else if (ber.remain > ber.length) { // ETOOMUCH // This is sort of ugly, but allows us to make miminal copies nextMessage = self.buffer.slice(ber.offset + ber.length); ber._size = ber.offset + ber.length; assert.equal(ber.remain, ber.length); } // If we're here, ber holds the message, and nextMessage is temporarily // pointing at the next sequence of data (if it exists) self.buffer = null; var message; try { // Bail here if peer isn't speaking protocol at all message = this.getMessage(ber); if (!message) { return end(); } message.parse(ber); } catch (e) { this.emit('error', e, message); return false; } this.emit('message', message); return end(); }
n/a
function PersistentSearch() { this.clientList = []; }
n/a
addClient = function (req, res, callback) { if (typeof (req) !== 'object') throw new TypeError('req must be an object'); if (typeof (res) !== 'object') throw new TypeError('res must be an object'); if (callback && typeof (callback) !== 'function') throw new TypeError('callback must be a function'); var log = req.log; var client = {}; client.req = req; client.res = res; log.debug('%s storing client', req.logId); this.clientList.push(client); log.debug('%s stored client', req.logId); log.debug('%s total number of clients %s', req.logId, this.clientList.length); if (callback) callback(client); }
n/a
removeClient = function (req, res, callback) { if (typeof (req) !== 'object') throw new TypeError('req must be an object'); if (typeof (res) !== 'object') throw new TypeError('res must be an object'); if (callback && typeof (callback) !== 'function') throw new TypeError('callback must be a function'); var log = req.log; log.debug('%s removing client', req.logId); var client = {}; client.req = req; client.res = res; // remove the client if it exists this.clientList.forEach(function (element, index, array) { if (element.req === client.req) { log.debug('%s removing client from list', req.logId); array.splice(index, 1); } }); log.debug('%s number of persistent search clients %s', req.logId, this.clientList.length); if (callback) callback(client); }
n/a
function PersistentSearchControl(options) { assert.optionalObject(options); options = options || {}; options.type = PersistentSearchControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
_json = function (obj) { obj.controlValue = this.value; return obj; }
n/a
_toBer = function (ber) { assert.ok(ber); if (!this._value) return; var writer = new BerWriter(); writer.startSequence(); writer.writeInt(this.value.changeTypes); writer.writeBoolean(this.value.changesOnly); writer.writeBoolean(this.value.returnECs); writer.endSequence(); ber.writeBuffer(writer.buffer, 0x04); }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); if (ber.readSequence()) { this._value = { changeTypes: ber.readInt(), changesOnly: ber.readBoolean(), returnECs: ber.readBoolean() }; return true; } return false; }
n/a
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
parse = function (ber) { assert.ok(ber); this.attribute = ber.buffer.slice(0, ber.length).toString('utf8').toLowerCase(); ber._offset += ber.length; return true; }
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
function Filter() { }
n/a
matches = function (target, strictAttrCase) { assert.object(target, 'target'); var value = helpers.getAttrValue(target, this.attribute, strictAttrCase); return (value !== undefined && value !== null); }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
toString = function () { return '(' + helpers.escape(this.attribute) + '=*)'; }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
ProtocolError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
ProxiedAuthorizationDeniedError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function RDN(obj) { var self = this; this.attrs = {}; if (obj) { Object.keys(obj).forEach(function (k) { self.set(k, obj[k]); }); } }
n/a
function rdnEquals(rdn) { if (typeof (rdn) !== 'object') return false; var ourKeys = Object.keys(this.attrs); var theirKeys = Object.keys(rdn.attrs); if (ourKeys.length !== theirKeys.length) return false; ourKeys.sort(); theirKeys.sort(); for (var i = 0; i < ourKeys.length; i++) { if (ourKeys[i] !== theirKeys[i]) return false; if (this.attrs[ourKeys[i]].value !== rdn.attrs[ourKeys[i]].value) return false; } return true; }
n/a
function rdnFormat(options) {
assert.optionalObject(options, 'options must be an object');
options = options || {};
var self = this;
var str = '';
function escapeValue(val, forceQuote) {
var out = '';
var cur = 0;
var len = val.length;
var quoted = false;
/* BEGIN JSSTYLED */
var escaped = /[\\\"]/;
var special = /[,=+<>#;]/;
/* END JSSTYLED */
if (len > 0) {
// Wrap strings with trailing or leading spaces in quotes
quoted = forceQuote || (val[0] == ' ' || val[len-1] == ' ');
}
while (cur < len) {
if (escaped.test(val[cur]) || (!quoted && special.test(val[cur]))) {
out += '\\';
}
out += val[cur++];
}
if (quoted)
out = '"' + out + '"';
return out;
}
function sortParsed(a, b) {
return self.attrs[a].order - self.attrs[b].order;
}
function sortStandard(a, b) {
var nameCompare = a.localeCompare(b);
if (nameCompare === 0) {
// TODO: Handle binary values
return self.attrs[a].value.localeCompare(self.attrs[b].value);
} else {
return nameCompare;
}
}
var keys = Object.keys(this.attrs);
if (options.keepOrder) {
keys.sort(sortParsed);
} else {
keys.sort(sortStandard);
}
keys.forEach(function (key) {
var attr = self.attrs[key];
if (str.length)
str += '+';
if (options.keepCase) {
str += attr.name;
} else {
if (options.upperName)
str += key.toUpperCase();
else
str += key;
}
str += '=' + escapeValue(attr.value, (options.keepQuote && attr.quoted));
});
return str;
}
...
///--- Helpers
// Copied from mcavage/node-assert-plus
function _assert(arg, type, name) {
name = name || type;
throw new assert.AssertionError({
message: util.format('%s (%s) required', name, type),
actual: typeof (arg),
expected: type,
operator: '===',
stackStartFunction: _assert.caller
});
}
...
function rdnSet(name, value, opts) { assert.string(name, 'name (string) required'); assert.string(value, 'value (string) required'); var self = this; var lname = name.toLowerCase(); this.attrs[lname] = { value: value, name: name }; if (opts && typeof (opts) === 'object') { Object.keys(opts).forEach(function (k) { if (k !== 'value') self.attrs[lname][k] = opts[k]; }); } }
n/a
function rdnToString() { return this.format(); }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
ReferralError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
SaslBindInProgressError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function SearchEntry(options) { options = options || {}; assert.object(options); lassert.optionalStringDN(options.objectName); options.protocolOp = Protocol.LDAP_REP_SEARCH_ENTRY; LDAPMessage.call(this, options); this.objectName = options.objectName || null; this.setAttributes(options.attributes || []); }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.objectName = this.objectName.toString(); j.attributes = []; this.attributes.forEach(function (a) { j.attributes.push(a.json || a); }); return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.objectName = ber.readString(); assert.ok(ber.readSequence()); var end = ber.offset + ber.length; while (ber.offset < end) { var a = new Attribute(); a.parse(ber); this.attributes.push(a); } return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeString(this.objectName.toString()); ber.startSequence(); this.attributes.forEach(function (a) { // This may or may not be an attribute ber = Attribute.toBer(a, ber); }); ber.endSequence(); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
addAttribute = function (attr) { if (!attr || typeof (attr) !== 'object') throw new TypeError('attr (attribute) required'); this.attributes.push(attr); }
n/a
fromObject = function (obj) { if (typeof (obj) !== 'object') throw new TypeError('object required'); var self = this; if (obj.controls) this.controls = obj.controls; if (obj.attributes) obj = obj.attributes; this.attributes = []; Object.keys(obj).forEach(function (k) { self.attributes.push(new Attribute({type: k, vals: obj[k]})); }); return true; }
n/a
setAttributes = function (obj) { if (typeof (obj) !== 'object') throw new TypeError('object required'); if (Array.isArray(obj)) { obj.forEach(function (a) { if (!Attribute.isAttribute(a)) throw new TypeError('entry must be an Array of Attributes'); }); this.attributes = obj; } else { var self = this; self.attributes = []; Object.keys(obj).forEach(function (k) { var attr = new Attribute({type: k}); if (Array.isArray(obj[k])) { obj[k].forEach(function (v) { attr.addValue(v.toString()); }); } else { attr.addValue(obj[k].toString()); } self.attributes.push(attr); }); } }
n/a
toObject = function () { return this.object; }
n/a
function SearchReference(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_SEARCH_REF; LDAPMessage.call(this, options); this.uris = options.uris || []; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.uris = this.uris.slice(); return j; }
n/a
_parse = function (ber, length) { assert.ok(ber); while (ber.offset < length) { var _url = ber.readString(); parseURL(_url); this.uris.push(_url); } return true; }
n/a
_toBer = function (ber) { assert.ok(ber); this.uris.forEach(function (u) { ber.writeString(u.href || u); }); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
fromObject = function (obj) { if (typeof (obj) !== 'object') throw new TypeError('object required'); this.uris = obj.uris ? obj.uris.slice() : []; return true; }
n/a
toObject = function () { return this.object; }
n/a
function SearchRequest(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REQ_SEARCH; LDAPMessage.call(this, options); if (options.baseObject !== undefined) { this.baseObject = options.baseObject; } else { this.baseObject = dn.parse(''); } this.scope = options.scope || 'base'; this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES; this.sizeLimit = options.sizeLimit || 0; this.timeLimit = options.timeLimit || 0; this.typesOnly = options.typesOnly || false; this.filter = options.filter || null; this.attributes = options.attributes ? options.attributes.slice(0) : []; }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); j.baseObject = this.baseObject; j.scope = this.scope; j.derefAliases = this.derefAliases; j.sizeLimit = this.sizeLimit; j.timeLimit = this.timeLimit; j.typesOnly = this.typesOnly; j.filter = this.filter.toString(); j.attributes = this.attributes; return j; }
n/a
_parse = function (ber) { assert.ok(ber); this.baseObject = ber.readString(); this.scope = ber.readEnumeration(); this.derefAliases = ber.readEnumeration(); this.sizeLimit = ber.readInt(); this.timeLimit = ber.readInt(); this.typesOnly = ber.readBoolean(); this.filter = filters.parse(ber); // look for attributes if (ber.peek() === 0x30) { ber.readSequence(); var end = ber.offset + ber.length; while (ber.offset < end) this.attributes.push(ber.readString().toLowerCase()); } return true; }
n/a
_toBer = function (ber) { assert.ok(ber); ber.writeString(this.baseObject.toString()); ber.writeEnumeration(this._scope); ber.writeEnumeration(this.derefAliases); ber.writeInt(this.sizeLimit); ber.writeInt(this.timeLimit); ber.writeBoolean(this.typesOnly); var f = this.filter || new filters.PresenceFilter({attribute: 'objectclass'}); ber = f.toBer(ber); ber.startSequence(Ber.Sequence | Ber.Constructor); if (this.attributes && this.attributes.length) { this.attributes.forEach(function (a) { ber.writeString(a); }); } ber.endSequence(); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function SearchResponse(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REP_SEARCH; LDAPResult.call(this, options); this.attributes = options.attributes ? options.attributes.slice() : []; this.notAttributes = []; this.sentEntries = 0; }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
createSearchEntry = function (object) { assert.object(object); var entry = new SearchEntry({ messageID: this.messageID, log: this.log, objectName: object.objectName || object.dn }); entry.fromObject((object.attributes || object)); return entry; }
n/a
createSearchReference = function (uris) { if (!uris) throw new TypeError('uris ([string]) required'); if (!Array.isArray(uris)) uris = [uris]; for (var i = 0; i < uris.length; i++) { if (typeof (uris[i]) == 'string') uris[i] = parseURL(uris[i]); } var self = this; return new SearchReference({ messageID: self.messageID, log: self.log, uris: uris }); }
n/a
send = function (entry, nofiltering) { if (!entry || typeof (entry) !== 'object') throw new TypeError('entry (SearchEntry) required'); if (nofiltering === undefined) nofiltering = false; if (typeof (nofiltering) !== 'boolean') throw new TypeError('noFiltering must be a boolean'); var self = this; if (entry instanceof SearchEntry || entry instanceof SearchReference) { if (!entry.messageID) entry.messageID = this.messageID; if (entry.messageID !== this.messageID) throw new Error('SearchEntry messageID mismatch'); } else { if (!entry.attributes) throw new Error('entry.attributes required'); var savedAttrs = {}; var all = (self.attributes.indexOf('*') !== -1); Object.keys(entry.attributes).forEach(function (a) { var _a = a.toLowerCase(); if (!nofiltering && _a.length && _a[0] === '_') { savedAttrs[a] = entry.attributes[a]; delete entry.attributes[a]; } else if (!nofiltering && self.notAttributes.indexOf(_a) !== -1) { savedAttrs[a] = entry.attributes[a]; delete entry.attributes[a]; } else if (all) { return; } else if (self.attributes.length && self.attributes.indexOf(_a) === -1) { savedAttrs[a] = entry.attributes[a]; delete entry.attributes[a]; } }); var save = entry; entry = new SearchEntry({ objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn, messageID: self.messageID, log: self.log }); entry.fromObject(save); } try { if (this.log.debug()) this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.json); this.connection.write(entry.toBer()); this.sentEntries++; if (self._dtraceOp && self._dtraceId) { dtrace.fire('server-search-entry', function () { var c = self.connection || {ldap: {}}; return [ self._dtraceId || 0, (c.remoteAddress || ''), c.ldap.bindDN ? c.ldap.bindDN.toString() : '', (self.requestDN ? self.requestDN.toString() : ''), entry.objectName.toString(), entry.attributes.length ]; }); } // Restore attributes Object.keys(savedAttrs || {}).forEach(function (k) { save.attributes[k] = savedAttrs[k]; }); } catch (e) { this.log.warn(e, '%s failure to write message %j', this.connection.ldap.id, this.json); } }
...
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
});
...
function Server(options) { if (options) { if (typeof (options) !== 'object') throw new TypeError('options (object) required'); if (typeof (options.log) !== 'object') throw new TypeError('options.log must be an object'); if (options.certificate || options.key) { if (!(options.certificate && options.key) || (typeof (options.certificate) !== 'string' && !Buffer.isBuffer(options.certificate)) || (typeof (options.key) !== 'string' && !Buffer.isBuffer(options.key))) { throw new TypeError('options.certificate and options.key ' + '(string or buffer) are both required for TLS'); } } } else { options = {}; } var self = this; EventEmitter.call(this, options); this._chain = []; this.log = options.log; this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true; var log = this.log; function setupConnection(c) { assert.ok(c); if (c.type === 'unix') { c.remoteAddress = self.server.path; c.remotePort = c.fd; } else if (c.socket) { // TLS c.remoteAddress = c.socket.remoteAddress; c.remotePort = c.socket.remotePort; } var rdn = new dn.RDN({cn: 'anonymous'}); c.ldap = { id: c.remoteAddress + ':' + c.remotePort, config: options, _bindDN: new DN([rdn]) }; c.addListener('timeout', function () { log.trace('%s timed out', c.ldap.id); c.destroy(); }); c.addListener('end', function () { log.trace('%s shutdown', c.ldap.id); }); c.addListener('error', function (err) { log.warn('%s unexpected connection error', c.ldap.id, err); self.emit('clientError', err); c.destroy(); }); c.addListener('close', function (had_err) { log.trace('%s close; had_err=%j', c.ldap.id, had_err); c.end(); }); c.ldap.__defineGetter__('bindDN', function () { return c.ldap._bindDN; }); c.ldap.__defineSetter__('bindDN', function (val) { if (!(val instanceof DN)) throw new TypeError('DN required'); c.ldap._bindDN = val; return val; }); return c; } function newConnection(c) { setupConnection(c); log.trace('new connection from %s', c.ldap.id); dtrace.fire('server-connection', function () { return [c.remoteAddress]; }); c.parser = new Parser({ log: options.log }); c.parser.on('message', function (req) { req.connection = c; req.logId = c.ldap.id + '::' + req.messageID; req.startTime = new Date().getTime(); if (log.debug()) log.debug('%s: message received: req=%j', c.ldap.id, req.json); var res = getResponse(req); if (!res) { log.warn('Unimplemented server method: %s', req.type); c.destroy(); return false; } // parse string DNs for routing/etc try { switch (req.protocolOp) { case Protocol.LDAP_REQ_BIND: req.name = dn.parse(req.name); break; case Protocol.LDAP_REQ_ADD: case Protocol.LDAP_REQ_COMPARE: case Protocol.LDAP_REQ_DELETE: req.entry = dn.parse(req.entry); break; case Protocol.LDAP_REQ_MODIFY: req.object = dn.parse(req.object); break; case Protocol.LDAP_REQ_MODRDN: req.entry = dn.parse(req.entry); // TODO: handle newRdn/Superior break; case Protocol.LDAP_REQ_SEARCH: req.baseObject = dn.parse(req.baseObject); break; default: break; } } catch (e) { if (self.strictDN) { return res.end(errors.LDAP_INVALID_DN_SYNTAX); } } res.connection = c; res.logId = req.logId; res.requestDN = req.dn; var chain = self._getHandlerChain(req, res); var i = 0; return function (err) { function sendError(err) { res.status = err.code || errors.LDAP_OPERATIONS_ERROR; res.matchedDN = req.suffix ? req.suffi ...
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function _getHandlerChain(req, res) { assert.ok(req); fireDTraceProbe(req, res); // check anonymous bind if (req.protocolOp === Protocol.LDAP_REQ_BIND && req.dn.toString() === '' && req.credentials === '') { return { backend: self, handlers: [defaultNoOpHandler] }; } var op = '0x' + req.protocolOp.toString(16); var self = this; var routes = this.routes; var route; // Special cases are exops, unbinds and abandons. Handle those first. if (req.protocolOp === Protocol.LDAP_REQ_EXTENSION) { route = routes[req.requestName]; if (route) { return { backend: route.backend, handlers: (route[op] ? route[op] : [noExOpHandler]) }; } else { return { backend: self, handlers: [noExOpHandler] }; } } else if (req.protocolOp === Protocol.LDAP_REQ_UNBIND) { route = routes['unbind']; if (route) { return { backend: route.backend, handlers: route[op] }; } else { return { backend: self, handlers: [defaultNoOpHandler] }; } } else if (req.protocolOp === Protocol.LDAP_REQ_ABANDON) { return { backend: self, handlers: [defaultNoOpHandler] }; } // Otherwise, match via DN rules assert.ok(req.dn); var keys = this._sortedRouteKeys(); var fallbackHandler = [noSuffixHandler]; // invalid DNs in non-strict mode are routed to the default handler var testDN = (typeof (req.dn) === 'string') ? '' : req.dn; for (var i = 0; i < keys.length; i++) { var suffix = keys[i]; route = routes[suffix]; assert.ok(route.dn); // Match a valid route or the route wildcard ('') if (route.dn.equals(testDN) || route.dn.parentOf(testDN) || suffix === '') { if (route[op]) { // We should be good to go. req.suffix = route.dn; return { backend: route.backend, handlers: route[op] }; } else { if (suffix === '') { break; } else { // We found a valid suffix but not a valid operation. // There might be a more generic suffix with a legitimate operation. fallbackHandler = [defaultHandler]; } } } } return { backend: self, handlers: fallbackHandler }; }
n/a
_getRoute = function (_dn, backend) { assert.ok(dn); if (!backend) backend = this; var name; if (_dn instanceof dn.DN) { name = _dn.toString(); } else { name = _dn; } if (!this.routes[name]) { this.routes[name] = {}; this.routes[name].backend = backend; this.routes[name].dn = _dn; // Force regeneration of the route key cache on next request this._routeKeyCache = null; } return this.routes[name]; }
n/a
_mount = function (op, name, argv, notDN) { assert.ok(op); assert.ok(name !== undefined); assert.ok(argv); if (typeof (name) !== 'string') throw new TypeError('name (string) required'); if (!argv.length) throw new Error('at least one handler required'); var backend = this; var index = 0; if (typeof (argv[0]) === 'object' && !Array.isArray(argv[0])) { backend = argv[0]; index = 1; } var route = this._getRoute(notDN ? name : dn.parse(name), backend); var chain = this._chain.slice(); argv.slice(index).forEach(function (a) { chain.push(a); }); route['0x' + op.toString(16)] = mergeFunctionArgs(chain); return this; }
n/a
function _sortedRouteKeys() { // The filtered/sorted route keys are cached to prevent needlessly // regenerating the list for every incoming request. if (!this._routeKeyCache) { var self = this; var reversedRDNsToKeys = {}; // Generate mapping of reversedRDNs(DN) -> routeKey Object.keys(this.routes).forEach(function (key) { var _dn = self.routes[key].dn; // Ignore non-DN routes such as exop or unbind if (_dn instanceof dn.DN) { var reversed = _dn.clone(); reversed.rdns.reverse(); reversedRDNsToKeys[reversed.format()] = key; } }); var output = []; // Reverse-sort on reversedRDS(DN) in order to output routeKey list. // This will place more specific DNs in front of their parents: // 1. dc=test, dc=domain, dc=sub // 2. dc=test, dc=domain // 3. dc=other, dc=foobar Object.keys(reversedRDNsToKeys).sort().reverse().forEach(function (_dn) { output.push(reversedRDNsToKeys[_dn]); }); this._routeKeyCache = output; } return this._routeKeyCache; }
n/a
add = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_ADD, name, args); }
n/a
address = function () { return this.server.address(); }
n/a
after = function () { if (!this._postChain) this._postChain = []; var self = this; mergeFunctionArgs(arguments).forEach(function (h) { self._postChain.push(h); }); }
n/a
bind = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_BIND, name, args); }
...
}
});
this.finished = false;
this.started = false;
var emitter = new EventEmitter();
emitter.on('searchEntry', this.emit.bind(this, 'searchEntry'));
emitter.on('end', this._onEnd.bind(this));
emitter.on('error', this._onError.bind(this));
this.childEmitter = emitter;
}
util.inherits(SearchPager, EventEmitter);
module.exports = SearchPager;
...
close = function () { return this.server.close(); }
n/a
compare = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_COMPARE, name, args); }
n/a
del = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_DELETE, name, args); }
n/a
exop = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_EXTENSION, name, args, true); }
n/a
listen = function (port, host, callback) { if (typeof (port) !== 'number' && typeof (port) !== 'string') throw new TypeError('port (number or path) required'); if (typeof (host) === 'function') { callback = host; host = '0.0.0.0'; } if (typeof (port) === 'string' && /^[0-9]+$/.test(port)) { // Disambiguate between string ports and file paths port = parseInt(port, 10); } var self = this; function cbListen() { if (typeof (port) === 'number') { self.host = self.address().address; self.port = self.address().port; } else { self.host = port; self.port = self.server.fd; } if (typeof (callback) === 'function') callback(); } if (typeof (port) === 'number') { return this.server.listen(port, host, cbListen); } else { return this.server.listen(port, cbListen); } }
...
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
});
```
To run that, assuming you've got the [OpenLDAP](http://www.openldap.org/)
client on your system:
...
listenFD = function (fd) { this.host = 'unix-domain-socket'; this.port = fd; return this.server.listenFD(fd); }
n/a
modify = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_MODIFY, name, args); }
n/a
modifyDN = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_MODRDN, name, args); }
n/a
search = function (name) { var args = Array.prototype.slice.call(arguments, 1); return this._mount(Protocol.LDAP_REQ_SEARCH, name, args); }
...
For full docs, head on over to <http://ldapjs.org>.
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
...
unbind = function () { var args = Array.prototype.slice.call(arguments, 0); return this._mount(Protocol.LDAP_REQ_UNBIND, 'unbind', args, true); }
n/a
function use() { var args = Array.prototype.slice.call(arguments); var chain = mergeFunctionArgs(args, 0, args.length); var self = this; chain.forEach(function (c) { self._chain.push(c); }); }
n/a
function ServerSideSortingRequestControl(options) { assert.optionalObject(options); options = options || {}; options.type = ServerSideSortingRequestControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (Array.isArray(options.value)) { assert.arrayOfObject(options.value, 'options.value must be Objects'); for (var i = 0; i < options.value.length; i++) { if (!options.value[i].hasOwnProperty('attributeType')) { throw new Error('Missing required key: attributeType'); } } this._value = options.value; } else if (typeof (options.value) === 'object') { if (!options.value.hasOwnProperty('attributeType')) { throw new Error('Missing required key: attributeType'); } this._value = [options.value]; } else { throw new TypeError('options.value must be a Buffer, Array or Object'); } options.value = null; } Control.call(this, options); }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
_json = function (obj) { obj.controlValue = this.value; return obj; }
n/a
_toBer = function (ber) { assert.ok(ber); if (!this._value || this.value.length === 0) return; var writer = new BerWriter(); writer.startSequence(0x30); for (var i = 0; i < this.value.length; i++) { var item = this.value[i]; writer.startSequence(0x30); if (item.attributeType) { writer.writeString(item.attributeType, asn1.Ber.OctetString); } if (item.orderingRule) { writer.writeString(item.orderingRule, 0x80); } if (item.reverseOrder) { writer.writeBoolean(item.reverseOrder, 0x81); } writer.endSequence(); } writer.endSequence(); ber.writeBuffer(writer.buffer, 0x04); }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); var item; if (ber.readSequence(0x30)) { this._value = []; while (ber.readSequence(0x30)) { item = {}; item.attributeType = ber.readString(asn1.Ber.OctetString); if (ber.peek() == 0x80) { item.orderingRule = ber.readString(0x80); } if (ber.peek() == 0x81) { item.reverseOrder = (ber._readTag(0x81) === 0 ? false : true); } this._value.push(item); } return true; } return false; }
n/a
function ServerSideSortingResponseControl(options) { assert.optionalObject(options); options = options || {}; options.type = ServerSideSortingResponseControl.OID; options.criticality = false; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); } else if (typeof (options.value) === 'object') { if (VALID_CODES.indexOf(options.value.result) === -1) { throw new Error('Invalid result code'); } if (options.value.failedAttribute && typeof (options.value.failedAttribute) !== 'string') { throw new Error('failedAttribute must be String'); } this._value = options.value; } else { throw new TypeError('options.value must be a Buffer or Object'); } options.value = null; } Control.call(this, options); }
n/a
function Control(options) { assert.optionalObject(options); options = options || {}; assert.optionalString(options.type); assert.optionalBool(options.criticality); if (options.value) { assert.buffer(options.value); } this.type = options.type || ''; this.criticality = options.critical || options.criticality || false; this.value = options.value || null; }
n/a
_json = function (obj) { obj.controlValue = this.value; return obj; }
n/a
_toBer = function (ber) { assert.ok(ber); if (!this._value || this.value.length === 0) return; var writer = new BerWriter(); writer.startSequence(0x30); writer.writeEnumeration(this.value.result); if (this.value.result !== CODES.LDAP_SUCCESS && this.value.failedAttribute) { writer.writeString(this.value.failedAttribute, 0x80); } writer.endSequence(); ber.writeBuffer(writer.buffer, 0x04); }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); if (ber.readSequence(0x30)) { this._value = {}; this._value.result = ber.readEnumeration(); if (ber.peek() == 0x80) { this._value.failedAttribute = ber.readString(0x80); } return true; } return false; }
n/a
SizeLimitExceededError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
StrongAuthRequiredError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
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; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
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; }
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
function Filter() { }
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; }
...
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
...
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; }
...
```javascript
var ldap = require('ldapjs');
var server = ldap.createServer();
server.search('dc=example', function(req, res, next) {
var obj = {
dn: req.dn.toString(),
attributes: {
objectclass: ['organization', 'top'],
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
...
TimeLimitExceededError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function TimeoutError(message) { LDAPError.call(this, message, null, TimeoutError); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
UnavailableCriticalExtensionError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
UnavailableError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function UnbindRequest(options) { options = options || {}; assert.object(options); options.protocolOp = Protocol.LDAP_REQ_UNBIND; LDAPMessage.call(this, options); }
n/a
function LDAPMessage(options) { assert.object(options); this.messageID = options.messageID || 0; this.protocolOp = options.protocolOp || undefined; this.controls = options.controls ? options.controls.slice(0) : []; this.log = options.log; }
n/a
_json = function (j) { assert.ok(j); return j; }
n/a
_parse = function (ber) { assert.ok(ber); return true; }
n/a
_toBer = function (ber) { assert.ok(ber); return ber; }
...
function mixin(target) {
target.prototype.toBer = 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;
};
}
module.exports = {
isFilter: isFilter,
...
function UnbindResponse(options) { options = options || {}; assert.object(options); options.protocolOp = 0; LDAPMessage.call(this, options); }
n/a
function LDAPResult(options) { options = options || {}; assert.object(options); assert.optionalNumber(options.status); assert.optionalString(options.matchedDN); assert.optionalString(options.errorMessage); assert.optionalArrayOfString(options.referrals); LDAPMessage.call(this, options); this.status = options.status || 0; // LDAP SUCCESS this.matchedDN = options.matchedDN || ''; this.errorMessage = options.errorMessage || ''; this.referrals = options.referrals || []; this.connection = options.connection || null; }
n/a
_json = function (j) { return j; }
n/a
end = function (status) { assert.ok(this.connection); this.log.trace('%s: unbinding!', this.connection.ldap.id); this.connection.end(); var self = this; if (self._dtraceOp && self._dtraceId) { dtrace.fire('server-' + self._dtraceOp + '-done', function () { var c = self.connection || {ldap: {}}; return [ self._dtraceId || 0, (c.remoteAddress || ''), c.ldap.bindDN ? c.ldap.bindDN.toString() : '', (self.requestDN ? self.requestDN.toString() : ''), 0, '' ]; }); } }
...
o: 'example'
}
};
if (req.filter.matches(obj.attributes))
res.send(obj);
res.end();
});
server.listen(1389, function() {
console.log('ldapjs listening at ' + server.url);
});
```
...
UndefinedAttributeTypeError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
UnwillingToPerformError = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
constructor = function (message, dn, caller) { LDAPError.call(this, message, dn, caller || module.exports[err]); }
n/a
function LDAPError(message, dn, caller) { if (Error.captureStackTrace) Error.captureStackTrace(this, caller || LDAPError); this.lde_message = message; this.lde_dn = dn; }
n/a
function optionalArrayOfAttribute(input, name) { if (input === undefined) return; if (!Array.isArray(input) || input.some(function (v) { return !isAttribute(v); })) { _assert(input, 'array of Attribute', name); } }
n/a
function optionalDN(input, name) { if (input !== undefined && !isDN(input)) _assert(input, 'DN', name); }
n/a
function optionalStringDN(input, name) { if (input === undefined || isDN(input) || typeof (input) === 'string') return; _assert(input, 'DN or string', name); }
n/a
function stringDN(input, name) { if (isDN(input) || typeof (input) === 'string') return; _assert(input, 'DN or string', name); }
n/a
function DN(rdns) { assert.optionalArrayOfObject(rdns, '[object] required'); this.rdns = rdns ? rdns.slice() : []; this._format = {}; }
n/a
function RDN(obj) { var self = this; this.attrs = {}; if (obj) { Object.keys(obj).forEach(function (k) { self.set(k, obj[k]); }); } }
n/a
function parse(name) { if (typeof (name) !== 'string') throw new TypeError('name (string) required'); var cur = 0; var len = name.length; function parseRdn() { var rdn = new RDN(); var order = 0; rdn.spLead = trim(); while (cur < len) { var opts = { order: order }; var attr = parseAttrType(); trim(); if (cur >= len || name[cur++] !== '=') throw invalidDN(name); trim(); // Parameters about RDN value are set in 'opts' by parseAttrValue var value = parseAttrValue(opts); rdn.set(attr, value, opts); rdn.spTrail = trim(); if (cur >= len || name[cur] !== '+') break; ++cur; ++order; } return rdn; } function trim() { var count = 0; while ((cur < len) && isWhitespace(name[cur])) { ++cur; count++; } return count; } function parseAttrType() { var beg = cur; while (cur < len) { var c = name[cur]; if (isAlphaNumeric(c) || c == '.' || c == '-' || c == ' ') { ++cur; } else { break; } } // Back out any trailing spaces. while ((cur > beg) && (name[cur - 1] == ' ')) --cur; if (beg == cur) throw invalidDN(name); return name.slice(beg, cur); } function parseAttrValue(opts) { if (cur < len && name[cur] == '#') { opts.binary = true; return parseBinaryAttrValue(); } else if (cur < len && name[cur] == '"') { opts.quoted = true; return parseQuotedAttrValue(); } else { return parseStringAttrValue(); } } function parseBinaryAttrValue() { var beg = cur++; while (cur < len && isAlphaNumeric(name[cur])) ++cur; return name.slice(beg, cur); } function parseQuotedAttrValue() { var str = ''; ++cur; // Consume the first quote while ((cur < len) && name[cur] != '"') { if (name[cur] === '\\') cur++; str += name[cur++]; } if (cur++ >= len) // no closing quote throw invalidDN(name); return str; } function parseStringAttrValue() { var beg = cur; var str = ''; var esc = -1; while ((cur < len) && !atTerminator()) { if (name[cur] === '\\') { // Consume the backslash and mark its place just in case it's escaping // whitespace which needs to be preserved. esc = cur++; } if (cur === len) // backslash followed by nothing throw invalidDN(name); str += name[cur++]; } // Trim off (unescaped) trailing whitespace and rewind cursor to the end of // the AttrValue to record whitespace length. for (; cur > beg; cur--) { if (!isWhitespace(name[cur - 1]) || (esc === (cur - 1))) break; } return str.slice(0, cur - beg); } function atTerminator() { return (cur < len && (name[cur] === ',' || name[cur] === ';' || name[cur] === '+')); } var rdns = []; // Short-circuit for empty DNs if (len === 0) return new DN(rdns); rdns.push(parseRdn()); while (cur < len) { if (name[cur] === ',' || name[cur] === ';') { ++cur; rdns.push(parseRdn()); } else { throw invalidDN(name); } } return new DN(rdns); }
n/a
_nextId = function () { if (DTRACE_ID === MAX_INT) DTRACE_ID = 0; return ++DTRACE_ID; }
n/a
escape = function (inp) { if (typeof (inp) === 'string') { var esc = ''; for (var i = 0; i < inp.length; i++) { switch (inp[i]) { case '*': esc += '\\2a'; break; case '(': esc += '\\28'; break; case ')': esc += '\\29'; break; case '\\': esc += '\\5c'; break; case '\0': esc += '\\00'; break; default: esc += inp[i]; break; } } return esc; } else { return inp; } }
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
function mixin(target) { target.prototype.toBer = 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
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); }
n/a
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 PersistentSearch() { this.clientList = []; }
n/a
function checkChangeType(req, requestType) { return (req.persistentSearch.value.changeTypes & getOperationType(requestType)); }
n/a
function getEntryChangeNotificationControl(req, obj, callback) { // if we want to return a ECNC if (req.persistentSearch.value.returnECs) { var attrs = obj.attributes; var value = {}; value.changeType = getOperationType(attrs.changetype); // if it's a modDN request, fill in the previous DN if (value.changeType === 8 && attrs.previousDN) { value.previousDN = attrs.previousDN; } value.changeNumber = attrs.changenumber; return new EntryChangeNotificationControl({ value: value }); } else { return false; } }
n/a
function SearchPager(opts) { assert.object(opts); assert.func(opts.callback); assert.number(opts.pageSize); EventEmitter.call(this, {}); this.callback = opts.callback; this.controls = opts.controls; this.pageSize = opts.pageSize; this.pagePause = opts.pagePause; this.controls.forEach(function (control) { if (control.type === PagedControl.OID) { // The point of using SearchPager is not having to do this. // Toss an error if the pagedResultsControl is present throw new Error('redundant pagedResultControl'); } }); this.finished = false; this.started = false; var emitter = new EventEmitter(); emitter.on('searchEntry', this.emit.bind(this, 'searchEntry')); emitter.on('end', this._onEnd.bind(this)); emitter.on('error', this._onError.bind(this)); this.childEmitter = emitter; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function _nextPage(cookie) { var controls = this.controls.slice(0); controls.push(new PagedControl({ value: { size: this.pageSize, cookie: cookie } })); this.emit('search', controls, this.childEmitter, this._sendCallback.bind(this)); }
...
module.exports = SearchPager;
/**
* Start the paged search.
*/
SearchPager.prototype.begin = function begin() {
// Starting first page
this._nextPage(null);
};
SearchPager.prototype._onEnd = function _onEnd(res) {
var self = this;
var cookie = null;
res.controls.forEach(function (control) {
if (control.type === PagedControl.OID) {
...
function _onEnd(res) { var self = this; var cookie = null; res.controls.forEach(function (control) { if (control.type === PagedControl.OID) { cookie = control.value.cookie; } }); // Pass a noop callback by default for page events var nullCb = function () { }; if (cookie === null) { // paged search not supported this.finished = true; this.emit('page', res, nullCb); var err = new Error('missing paged control'); err.name = 'PagedError'; if (this.listeners('pageError').length > 0) { this.emit('pageError', err); // If the consumer as subscribed to pageError, SearchPager is absolved // from deliverying the fault via the 'error' event. Emitting an 'end' // event after 'error' breaks the contract that the standard client // provides, so it's only a possibility if 'pageError' is used instead. this.emit('end', res); } else { this.emit('error', err); // No end event possible per explaination above. } return; } if (cookie.length === 0) { // end of paged results this.finished = true; this.emit('page', nullCb); this.emit('end', res); } else { if (this.pagePause) { // Wait to fetch next page until callback is invoked // Halt page fetching if called with error this.emit('page', res, function (err) { if (!err) { self._nextPage(cookie); } else { // the paged search has been canceled so emit an end self.emit('end', res); } }); } else { this.emit('page', res, nullCb); this._nextPage(cookie); } } }
n/a
function _onError(err) { this.finished = true; this.emit('error', err); }
n/a
function _sendCallback(err, res) { if (err) { this.finished = true; if (!this.started) { // EmitSend error during the first page, bail via callback this.callback(err, null); } else { this.emit('error', err); } } else { // search successfully send if (!this.started) { this.started = true; // send self as emitter as the client would this.callback(null, this); } } }
n/a
function begin() { // Starting first page this._nextPage(null); }
n/a
parse = function (urlStr, parseDN) { var u = url.parse(urlStr); if (!u.protocol || !(u.protocol === 'ldap:' || u.protocol === 'ldaps:')) throw new TypeError(urlStr + ' is an invalid LDAP url (protocol)'); u.secure = (u.protocol === 'ldaps:'); if (!u.hostname) u.hostname = 'localhost'; if (!u.port) { u.port = (u.secure ? 636 : 389); } else { u.port = parseInt(u.port, 10); } if (u.pathname) { u.pathname = querystring.unescape(u.pathname.substr(1)); u.DN = parseDN ? dn.parse(u.pathname) : u.pathname; } if (u.search) { u.attributes = []; var tmp = u.search.substr(1).split('?'); if (tmp && tmp.length) { if (tmp[0]) { tmp[0].split(',').forEach(function (a) { u.attributes.push(querystring.unescape(a.trim())); }); } } if (tmp[1]) { if (tmp[1] !== 'base' && tmp[1] !== 'one' && tmp[1] !== 'sub') throw new TypeError(urlStr + ' is an invalid LDAP url (scope)'); u.scope = tmp[1]; } if (tmp[2]) { u.filter = querystring.unescape(tmp[2]); } if (tmp[3]) { u.extensions = querystring.unescape(tmp[3]); } if (!u.scope) u.scope = 'base'; if (!u.filter) u.filter = filter.parseString('(objectclass=*)'); else u.filter = filter.parseString(u.filter); } return u; }
n/a