'use strict'; exports = module.exports = { ExternalLdapError: ExternalLdapError, testConfig: testConfig, sync: sync }; var assert = require('assert'), debug = require('debug')('box:ldapclient'), ldap = require('ldapjs'), settings = require('./settings.js'), util = require('util'); function ExternalLdapError(reason, errorOrMessage) { assert.strictEqual(typeof reason, 'string'); assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined'); Error.call(this); Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; this.reason = reason; if (typeof errorOrMessage === 'undefined') { this.message = reason; } else if (typeof errorOrMessage === 'string') { this.message = errorOrMessage; } else { this.message = 'Internal error'; this.nestedError = errorOrMessage; } } util.inherits(ExternalLdapError, Error); ExternalLdapError.EXTERNAL_ERROR = 'external error'; ExternalLdapError.INTERNAL_ERROR = 'internal error'; ExternalLdapError.INVALID_CREDENTIALS = 'invalid credentials'; ExternalLdapError.BAD_STATE = 'bad state'; ExternalLdapError.BAD_FIELD = 'bad field'; ExternalLdapError.NOT_FOUND = 'not found'; // performs service bind if required function getClientAndConfig(callback) { assert.strictEqual(typeof callback, 'function'); settings.getExternalLdapConfig(function (error, externalLdapConfig) { if (error) return callback(new ExternalLdapError(ExternalLdapError.INTERNAL_ERROR, error)); var client = ldap.createClient({ url: externalLdapConfig.url }); if (!externalLdapConfig.bindDn) return callback(null, client); client.bind(externalLdapConfig.bindDn, externalLdapConfig.bindPassword, function (error) { if (error instanceof ldap.InvalidCredentialsError) return callback(new ExternalLdapError(ExternalLdapError.INVALID_CREDENTIALS)); if (error) return callback(new ExternalLdapError(ExternalLdapError.EXTERNAL_ERROR, error)); debug('getClient: successful'); callback(null, client, externalLdapConfig); }); }); } function testConfig(config, callback) { assert.strictEqual(typeof config, 'object'); assert.strictEqual(typeof callback, 'function'); if (!config.url) return callback(new ExternalLdapError(ExternalLdapError.BAD_FIELD, 'url must not be empty')); if (!config.baseDn) return callback(new ExternalLdapError(ExternalLdapError.BAD_FIELD, 'basedn must not be empty')); if (!config.filter) return callback(new ExternalLdapError(ExternalLdapError.BAD_FIELD, 'filter must not be empty')); var client = ldap.createClient({ url: config.url }); if (!config.bindDn) return callback(null, client); client.bind(config.bindDn, config.bindPassword, function (error) { if (error instanceof ldap.InvalidCredentialsError) return callback(new ExternalLdapError(ExternalLdapError.INVALID_CREDENTIALS)); if (error) return callback(new ExternalLdapError(ExternalLdapError.EXTERNAL_ERROR, error)); var opts = { filter: config.filter, scope: 'sub' }; client.search(config.baseDn, opts, function (error, result) { if (error) return callback(new ExternalLdapError(ExternalLdapError.EXTERNAL_ERROR, error)); result.on('searchEntry', function (entry) {}); result.on('error', function (error) { callback(new ExternalLdapError(ExternalLdapError.EXTERNAL_ERROR, error)); }); result.on('end', function (result) { callback(); }); }); }); } function sync(callback) { assert.strictEqual(typeof callback, 'function'); getClientAndConfig(function (error, client, externalLdapConfig) { if (error) return callback(error); var opts = { filter: externalLdapConfig.filter, scope: 'sub' }; client.search(externalLdapConfig.baseDn, opts, function(err, res) { assert.ifError(err); res.on('searchEntry', function(entry) { console.log('entry: ' + JSON.stringify(entry.object)); }); res.on('searchReference', function(referral) { console.log('referral: ' + referral.uris.join()); }); res.on('error', function(err) { console.error('error: ' + err.message); }); res.on('end', function(result) { console.log('status: ' + result.status); }); }); }); }