All files / node-activedirectory/lib/services service.getGroupMembershipForDn.js

11.76% Statements 8/68
0% Branches 0/42
0% Functions 0/10
12.12% Lines 8/66

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 1291x 1x 1x 1x 1x 1x 1x                                                                                                                                                                                                                                                   1x
const _                                 = require('underscore');
const Group                             = require('../models/group');
const joinAttributes                    = require('./internal/service.joinAttributes');
const parseDistinguishedName            = require('./internal/service.parseDistinguishedName');
const search                            = require('./internal/service.search');
const log                                 = require('./internal/service.log');
const isGroupResult                     = require('./internal/service.isGroupResult');
 
 
/**
 * Gets all of the groups that the specified distinguishedName (DN) belongs to.
 * 
 * @private
 * @param {Object} [opts] Optional LDAP query string parameters to execute. { scope: '', filter: '', attributes: [ '', '', ... ], sizeLimit: 0, timelimit: 0 }
 * @param {String} dn The distinguishedName (DN) to find membership of.
 * @param {Function} callback The callback to execute when completed. callback(err: {Object}, groups: {Array[Group]})
 */
 
 function getGroupMembershipForDN(opts, dn, stack, callback) {
    var self = this;
 
    if (typeof (stack) === 'function') {
        callback = stack;
        stack = undefined;
    }
    if (typeof (dn) === 'function') {
        callback = dn;
        dn = opts;
        opts = undefined;
    }
    if (typeof (opts) === 'string') {
        stack = dn;
        dn = opts;
        opts = undefined;
    }
 
    return new Promise((resolve, reject) => {
        log.trace('getGroupMembershipForDN(%j,%s,stack:%j)', opts, dn, (stack || []).length);
 
        // Ensure that a valid DN was provided. Otherwise abort the search.
        if (!dn) {
            var error = new Error('No distinguishedName (dn) specified for group membership retrieval.');
            log.error(error);
            if (hasEvents('error')) self.emit('error', error);
            if(callback){
                callback(err);
            }
            return reject(err);
        }
 
        //  Note: Microsoft provides a 'Transitive Filter' for querying nested groups.
        //        i.e. (member:1.2.840.113556.1.4.1941:=<userDistinguishedName>)
        //        However this filter is EXTREMELY slow. Recursively querying ActiveDirectory
        //        is typically 10x faster.
        opts = _.defaults(_.omit(opts || {}, 'filter', 'scope', 'attributes'), {
            filter: '(member=' + parseDistinguishedName(dn) + ')',
            scope: 'sub',
            attributes: joinAttributes((opts || {}).attributes || defaultAttributes.group, ['groupType'])
        });
        search.call(self, opts, function (err, results) {
            if (err) {
                if(callback){
                    callback(err);
                }
                return reject(err);
            }
 
            var groups = [];
            for(ind in results){
                let group = results[ind];
 
                // accumulates discovered groups
                if (typeof (stack) !== 'undefined') {
                    if (!_.findWhere(stack, { cn: group.cn })) {
                        stack.push(new Group(group));
                    } 
                    _.each(stack, function (s) {
                        if (!_.findWhere(groups, { cn: s.cn })) {
                            groups.push(s);
                        }
                    });
                }
 
                if (isGroupResult(group)) {
                    log.debug('Adding group "%s" to %s"', group.dn, dn);
                    groups.push(new Group(group));
 
                    // Get the groups that this group may be a member of.
                    log.debug('Retrieving nested group membership for group "%s"', group.dn);
                    getGroupMembershipForDN.call(self, opts, group.dn, groups, function (err, nestedGroups) {
                        if (err) {
                            if(callback){
                                callback(err);
                            }
                            return reject(err);
                        }
 
                        nestedGroups = _.map(nestedGroups, function (nestedGroup) {
                            if (isGroupResult(nestedGroup)) {
                                return (new Group(nestedGroup));
                            }
                        });
                        log.debug('Group "%s" which is a member of group "%s" has %d nested group(s). Nested: %j',
                            group.dn, dn, nestedGroups.length, _.map(nestedGroups, function (group) {
                                return (group.dn);
                            }));
                        Array.prototype.push.apply(groups, nestedGroups);
                        
                    });
                }
 
                // Remove the duplicates from the list.
                groups = _.uniq(_.sortBy(groups, function (group) { return (group.cn || group.dn); }), false, function (group) {
                    return (group.dn);
                });
 
                log.info('Group "%s" has %d group(s). Groups: %j', dn, groups.length, _.map(groups, function (group) {
                    return (group.dn);
                }));
                if(callback){
                    callback(null, groups);
                }
                return resolve(groups);  
            }
        });
    });    
}
 
module.exports = getGroupMembershipForDN;