UNPKG

simple-ad

Version:

Basic ldapjs wrapper for reading and writing AD objects. Currently only searching and editing of group members is implemented.

257 lines (256 loc) 10.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _ActiveDirectory_password; Object.defineProperty(exports, "__esModule", { value: true }); const ldapjs_1 = __importDefault(require("ldapjs")); /** * Creates a new LDAP client * @class ActiveDirectory */ class ActiveDirectory { constructor(options) { _ActiveDirectory_password.set(this, void 0); this.url = options.url; this.tlsOptions = options.tlsOptions; this.username = options.username; __classPrivateFieldSet(this, _ActiveDirectory_password, options.password, "f"); this.clientOptions = options.clientOptions; } /** * Bind to the LDAP Server */ bind() { return new Promise((resolve, reject) => { this.client = ldapjs_1.default.createClient({ url: this.url, tlsOptions: this.tlsOptions }); this.client.on('error', (err) => { reject(err); }); this.client.bind(this.username, __classPrivateFieldGet(this, _ActiveDirectory_password, "f"), (err, res) => { if (err) return reject(err); resolve(); }); }); } /** * Unbind the connection */ unbind() { return new Promise((resolve, reject) => { this.client.unbind((err) => { if (err) return reject(err); resolve(); }); }); } /** * Perform a LDAP search: http://ldapjs.org/client.html#search * @param dn * @param options */ search(dn, options) { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const x = yield this.bind(); } catch (e) { return reject(e); } this.client.search(dn, options, (err, res) => { if (err) { return reject(err); } var entries = []; res.on('searchEntry', (entry) => { entries.push(entry); }); const done = () => __awaiter(this, void 0, void 0, function* () { try { yield this.unbind(); } catch (e) { return reject(e); } if (entries.length === 0) return resolve([]); var result = entries.map(function (e) { return e.object; }); resolve(result); }); res.on('error', (err) => __awaiter(this, void 0, void 0, function* () { if (err.message === 'Size Limit Exceeded') return done(); try { yield this.unbind(); } catch (e) { reject(e); } reject(err); })); res.on('end', done); }); })); } /** * Find Group objects * @param dn * @param attributes ['cn', 'dn', 'member'] */ findGroup(groupDN, attributes) { return __awaiter(this, void 0, void 0, function* () { const options = { scope: 'sub', filter: '(&(objectclass=group))', attributes: attributes }; const groups = yield this.search(groupDN, options); // if attribute 'member' is requested, the function always will return an member array if (attributes.indexOf('member') !== -1) { for (let i = 0; i < groups.length; i++) { if (typeof groups[i].member === 'undefined') { groups[i].member = []; } else if (!Array.isArray(groups[i].member)) { groups[i].member = [groups[i].member]; } } } // If only one group found, retrun the group object not an array return (groups.length === 1) ? groups[0] : groups; }); } /** * Check if entry is member in group * @param groupDN * @param memberDN */ isGroupMember(groupDN, memberDN) { return __awaiter(this, void 0, void 0, function* () { const options = { scope: 'sub', filter: `(&(objectclass=group)(member=${memberDN}))`, attributes: ['cn'] }; const results = yield this.search(groupDN, options); return (results.length > 0); }); } /** * Add or delete group members * @param groupDN * @param members * @param operation */ modifyGroupMember(groupDN, members, operation) { return __awaiter(this, void 0, void 0, function* () { members = (!Array.isArray(members)) ? [members] : members; const change = new ldapjs_1.default.Change({ operation: operation, modification: { member: members } }); return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { yield this.bind(); } catch (e) { return reject(e); } this.client.modify(groupDN, change, (err) => __awaiter(this, void 0, void 0, function* () { try { yield this.unbind(); } catch (e) { reject(e); } if (err && err.name !== 'EntryAlreadyExistsError') { return reject(err); } resolve(); })); })); }); } /** * Delete one group member * @param groupDN * @param memberDN */ addGroupMember(groupDN, memberDN) { return __awaiter(this, void 0, void 0, function* () { return this.modifyGroupMember(groupDN, memberDN, 'add'); }); } /** * Remove one group member * @param groupDN * @param memberDN */ deleteGroupMember(groupDN, memberDN) { return __awaiter(this, void 0, void 0, function* () { // Check is is member in group if (yield this.isGroupMember(groupDN, memberDN)) { return this.modifyGroupMember(groupDN, memberDN, 'delete'); } else { return null; } }); } /** * Find a user objects * @param dn * @param attributes ['cn', 'dn', 'memberOf'] */ findUser(userDN, attributes) { return __awaiter(this, void 0, void 0, function* () { const options = { scope: 'sub', filter: '(&(objectclass=user))', attributes: attributes }; const user = yield this.search(userDN, options); // if attribute 'member' is requested, the function always will return an member array // if (attributes.indexOf('member') !== -1) { // for (let i = 0; i < groups.length; i++) { // if(typeof groups[i].member === 'undefined') { // groups[i].member = [] // } else if(!Array.isArray(groups[i].member)) { // groups[i].member = [groups[i].member] // } // } // } // If only one group found, retrun the group object not an array return (user.length === 1) ? user[0] : user; }); } } exports.default = ActiveDirectory; _ActiveDirectory_password = new WeakMap();