123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- #!/usr/bin/env node
- // -*- mode: js -*-
- // Copyright 2011 Mark Cavage. All rights reserved.
-
- var path = require('path');
-
- var dashdash = require('dashdash');
-
- var ldap = require('../lib/index');
- var Logger = require('bunyan');
-
-
- ///--- Globals
-
- dashdash.addOptionType({
- name: 'ldap.Filter',
- takesArg: true,
- helpArg: 'LDAP_FILTER',
- parseArg: function (option, optstr, arg) {
- return ldap.parseFilter(arg);
- }
- });
-
- dashdash.addOptionType({
- name: 'ldap.scope',
- takesArg: true,
- helpArg: 'SCOPE',
- parseArg: function (option, optstr, arg) {
- if (!/^base|one|sub$/.test(arg)) {
- throw new TypeError('Scope must be <base|one|sub>');
- }
- return arg;
- }
- });
-
- dashdash.addOptionType({
- name: 'ldap.outputFormat',
- takesArg: true,
- helpArg: 'FORMAT',
- parseArg: function (option, optstr, arg) {
- var formats = ['json', 'jsonl', 'jsona'];
- if (formats.indexOf(arg) === -1) {
- throw new TypeError('Must be valid format type');
- }
- return arg;
- }
- });
-
-
- var opts = [
- {
- names: ['base', 'b'],
- type: 'string',
- help: 'Base DN of search',
- helpArg: 'BASE_DN',
- default: ''
- },
- {
- names: ['scope', 's'],
- type: 'ldap.scope',
- help: 'Search scope <base|sub|one>',
- helpArg: 'SCOPE',
- default: 'sub'
- },
- {
- names: ['timeout', 't'],
- type: 'integer',
- help: 'Search timeout',
- helpArg: 'SECS'
- },
- {
- names: ['persistent', 'p'],
- type: 'bool',
- help: 'Enable persistent search control',
- default: false
- },
- {
- names: ['paged', 'g'],
- type: 'number',
- help: 'Enable paged search result control',
- helpArg: 'PAGE_SIZE'
- },
- {
- names: ['control', 'c'],
- type: 'arrayOfString',
- help: 'Send addition control OID',
- helpArg: 'OID',
- default: []
- },
- { group: 'General Options' },
- {
- names: ['help', 'h'],
- type: 'bool',
- help: 'Print this help and exit.'
- },
- {
- names: ['debug', 'd'],
- type: 'integer',
- help: 'Set debug level <0-2>',
- helpArg: 'LEVEL'
- },
- { group: 'Output Options' },
- {
- names: ['format', 'o'],
- type: 'ldap.outputFormat',
- helpWrap: false,
- help: ('Specify and output format. One of:\n' +
- ' json: JSON objects (default)\n' +
- ' jsonl: Line-delimited JSON\n' +
- ' jsona: Array of JSON objects\n'),
- default: 'json'
- },
- { group: 'Connection Options' },
- {
- names: ['url', 'u'],
- type: 'string',
- help: 'LDAP server URL',
- helpArg: 'URL',
- default: 'ldap://127.0.0.1:389'
- },
- {
- names: ['binddn', 'D'],
- type: 'string',
- help: 'Bind DN',
- helpArg: 'BIND_DN',
- default: ''
- },
- {
- names: ['password', 'w'],
- type: 'string',
- help: 'Bind password',
- helpArg: 'PASSWD',
- default: ''
- },
- {
- names: ['insecure', 'i'],
- type: 'bool',
- env: 'LDAPJS_TLS_INSECURE',
- help: 'Disable SSL certificate verification',
- default: false
- }
- ];
- var parser = dashdash.createParser({options: opts});
-
-
-
- ///--- Helpers
-
- function usage(code, message) {
- var msg = (message ? message + '\n' : '') +
- 'Usage: ' + path.basename(process.argv[1]) +
- ' [OPTIONS] FILTER [ATTRIBUTES...]\n\n' +
- parser.help({includeEnv: true});
-
- process.stderr.write(msg + '\n');
- process.exit(code);
- }
-
-
- function perror(err) {
- if (parsed.debug) {
- process.stderr.write(err.stack + '\n');
- } else {
- process.stderr.write(err.message + '\n');
- }
- process.exit(1);
- }
-
-
- function EntryFormatter(fp, format) {
- this.format = format;
- this.started = false;
- this.ended = false;
- this.fp = fp;
- }
-
- EntryFormatter.prototype.write = function write(entry) {
- switch (this.format) {
- case 'json':
- this.fp.write(JSON.stringify(entry.object, null, 2) + '\n');
- break;
- case 'jsonl':
- this.fp.write(JSON.stringify(entry.object) + '\n');
- break;
- case 'jsona':
- this.fp.write((this.started) ? ',\n' : '[\n');
- this.started = true;
- // pretty-print with indent
- this.fp.write(
- JSON.stringify(entry.object, null, 2)
- .split('\n')
- .map(function (line) { return ' ' + line; })
- .join('\n'));
- break;
- default:
- throw new Error('invalid output format');
- }
- };
-
- EntryFormatter.prototype.end = function end() {
- if (this.ended) {
- return;
- }
- this.ended = true;
- if (this.format === 'jsona') {
- this.fp.write('\n]\n');
- }
- };
-
-
- ///--- Mainline
-
- var parsed;
-
- process.stdout.on('error', function (err) {
- if (err.code === 'EPIPE') {
- process.exit(0);
- } else {
- throw err;
- }
- });
-
- try {
- parsed = parser.parse(process.argv);
- } catch (e) {
- usage(1, e.toString());
- }
-
- if (parsed.help)
- usage(0);
- if (parsed._args.length < 1)
- usage(1, 'filter required');
-
- try {
- ldap.parseFilter(parsed._args[0]);
- } catch (e) {
- usage(1, e.message);
- }
-
- var logLevel = 'info';
-
- if (parsed.debug)
- logLevel = (parsed.debug > 1 ? 'trace' : 'debug');
-
- var formatter = new EntryFormatter(process.stdout, parsed.format);
-
- var log = new Logger({
- name: 'ldapjs',
- component: 'client',
- stream: process.stderr,
- level: logLevel
- });
-
- var client = ldap.createClient({
- url: parsed.url,
- log: log,
- strictDN: false,
- timeout: parsed.timeout || false,
- tlsOptions: {
- rejectUnauthorized: !parsed.insecure
- }
- });
-
- client.on('error', function (err) {
- perror(err);
- });
-
- client.on('timeout', function (req) {
- process.stderr.write('Timeout reached\n');
- process.exit(1);
- });
-
- client.bind(parsed.binddn, parsed.password, function (err, res) {
- if (err)
- perror(err);
-
- var controls = [];
- parsed.control.forEach(function (c) {
- controls.push(new ldap.Control({
- type: c,
- criticality: true
- }));
- });
- if (parsed.persistent) {
- var pCtrl = new ldap.PersistentSearchControl({
- type: '2.16.840.1.113730.3.4.3',
- value: {
- changeTypes: 15,
- changesOnly: false,
- returnECs: true
- }
- });
- controls.push(pCtrl);
- }
- var req = {
- scope: parsed.scope || 'sub',
- filter: parsed._args[0],
- attributes: parsed._args.length > 1 ? parsed._args.slice(1) : []
- };
- if (parsed.paged) {
- req.paged = {
- pageSize: parsed.paged
- };
- }
- client.search(parsed.base, req, controls, function (err, res) {
- if (err)
- perror(err);
-
- res.on('searchEntry', function (entry) {
- formatter.write(entry);
- });
- res.on('error', function (err) {
- formatter.end();
- perror(err);
- });
- res.on('end', function (res) {
- formatter.end();
- if (res.status !== 0) {
- process.stderr.write(ldap.getMessage(res.status) + '\n');
- }
- client.unbind(function () {
- return;
- });
- });
- });
- });
|