diff --git a/src/externalldap.js b/src/externalldap.js index b76f43b4b..aaf5d8f1e 100644 --- a/src/externalldap.js +++ b/src/externalldap.js @@ -130,11 +130,6 @@ function ldapGroupSearch(externalLdapConfig, options, callback) { assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); - if (!externalLdapConfig.syncGroups) { - debug('Group sync is disabled'); - return callback(null, []); - } - getClient(externalLdapConfig, function (error, client) { if (error) return callback(error); @@ -303,6 +298,135 @@ function startSyncer(callback) { }); } +function syncUsers(externalLdapConfig, progressCallback, callback) { + assert.strictEqual(typeof externalLdapConfig, 'object'); + assert.strictEqual(typeof progressCallback, 'function'); + assert.strictEqual(typeof callback, 'function'); + + ldapUserSearch(externalLdapConfig, {}, function (error, ldapUsers) { + if (error) return callback(error); + + debug(`Found ${ldapUsers.length} users`); + + let percent = 10; + let step = 30/(ldapUsers.length+1); // ensure no divide by 0 + + // we ignore all errors here and just log them for now + async.eachSeries(ldapUsers, function (user, iteratorCallback) { + user = translateUser(externalLdapConfig, user); + + if (!validUserRequirements(user)) return iteratorCallback(); + + percent += step; + progressCallback({ percent, message: `Syncing... ${user.username}` }); + + users.getByUsername(user.username, function (error, result) { + if (error && error.reason !== BoxError.NOT_FOUND) return iteratorCallback(error); + + if (!result) { + debug(`[adding user] username=${user.username} email=${user.email} displayName=${user.displayName}`); + + users.create(user.username, null /* password */, user.email, user.displayName, { source: 'ldap' }, auditSource.EXTERNAL_LDAP_TASK, function (error) { + if (error) console.error('Failed to create user', user, error); + iteratorCallback(); + }); + } else if (result.source !== 'ldap') { + debug(`[conflicting user] username=${user.username} email=${user.email} displayName=${user.displayName}`); + + iteratorCallback(); + } else if (result.email !== user.email || result.displayName !== user.displayName) { + debug(`[updating user] username=${user.username} email=${user.email} displayName=${user.displayName}`); + + users.update(result, { email: user.email, fallbackEmail: user.email, displayName: user.displayName }, auditSource.EXTERNAL_LDAP_TASK, function (error) { + if (error) debug('Failed to update user', user, error); + + iteratorCallback(); + }); + } else { + // user known and up-to-date + debug(`[up-to-date user] username=${user.username} email=${user.email} displayName=${user.displayName}`); + + iteratorCallback(); + } + }); + }, callback); + }); +} + +function syncGroups(externalLdapConfig, progressCallback, callback) { + assert.strictEqual(typeof externalLdapConfig, 'object'); + assert.strictEqual(typeof progressCallback, 'function'); + assert.strictEqual(typeof callback, 'function'); + + if (!externalLdapConfig.syncGroups) { + debug('Group sync is disabled'); + progressCallback({ percent: 70, message: `Skipping group sync...` }); + return callback(null, []); + } + + ldapGroupSearch(externalLdapConfig, {}, function (error, ldapGroups) { + if (error) return callback(error); + + debug(`Found ${ldapGroups.length} groups`); + + let percent = 40; + let step = 30/(ldapGroups.length+1); // ensure no divide by 0 + + // we ignore all non internal errors here and just log them for now + async.eachSeries(ldapGroups, function (ldapGroup, iteratorCallback) { + var groupName = ldapGroup[externalLdapConfig.groupnameField || 'cn']; + if (!groupName) return iteratorCallback(); + + percent += step; + progressCallback({ percent, message: `Syncing... ${groupName}` }); + + groups.getByName(groupName, function (error, result) { + if (error && error.reason !== BoxError.NOT_FOUND) return iteratorCallback(error); + + if (!result) { + debug(`[adding group] groupname=${groupName}`); + + groups.create(groupName, 'ldap', function (error) { + if (error) console.error('Failed to create group', groupName, error); + iteratorCallback(); + }); + } else { + debug(`[up-to-date group] groupname=${groupName}`); + + iteratorCallback(); + } + }); + }, function (error) { + if (error) return callback(error); + + debug('sync: ldap sync is done', error); + + callback(error); + }); + }); +} + +function syncGroupUsers(externalLdapConfig, progressCallback, callback) { + assert.strictEqual(typeof externalLdapConfig, 'object'); + assert.strictEqual(typeof progressCallback, 'function'); + assert.strictEqual(typeof callback, 'function'); + + if (!externalLdapConfig.syncGroups) { + debug('Group users sync is disabled'); + progressCallback({ percent: 99, message: 'Skipping group users sync...' }); + return callback(null, []); + } + + groups.getAllWithMembers(function (error, groups) { + if (error) return callback(error); + + var ldapGroups = groups.filter(function (g) { return g.source === 'ldap'; }); + debug(`Found ${ldapGroups.length} groups to sync users`); + + callback(); + }); +} + function sync(progressCallback, callback) { assert.strictEqual(typeof progressCallback, 'function'); assert.strictEqual(typeof callback, 'function'); @@ -313,91 +437,18 @@ function sync(progressCallback, callback) { if (error) return callback(error); if (externalLdapConfig.provider === 'noop') return callback(new BoxError(BoxError.BAD_STATE, 'not enabled')); - ldapUserSearch(externalLdapConfig, {}, function (error, ldapUsers) { + async.series([ + syncUsers.bind(null, externalLdapConfig, progressCallback), + syncGroups.bind(null, externalLdapConfig, progressCallback), + syncGroupUsers.bind(null, externalLdapConfig, progressCallback) + ], function (error) { if (error) return callback(error); - debug(`Found ${ldapUsers.length} users`); - let percent = 10; - let step = 90/(ldapUsers.length+1); // ensure no divide by 0 + progressCallback({ percent: 100, message: 'Done' }); - // we ignore all errors here and just log them for now - async.eachSeries(ldapUsers, function (user, iteratorCallback) { - user = translateUser(externalLdapConfig, user); + debug('sync: ldap sync is done', error); - if (!validUserRequirements(user)) return iteratorCallback(); - - percent += step; - progressCallback({ percent, message: `Syncing... ${user.username}` }); - - users.getByUsername(user.username, function (error, result) { - if (error && error.reason !== BoxError.NOT_FOUND) return iteratorCallback(error); - - if (!result) { - debug(`[adding user] username=${user.username} email=${user.email} displayName=${user.displayName}`); - - users.create(user.username, null /* password */, user.email, user.displayName, { source: 'ldap' }, auditSource.EXTERNAL_LDAP_TASK, function (error) { - if (error) console.error('Failed to create user', user, error); - iteratorCallback(); - }); - } else if (result.source !== 'ldap') { - debug(`[conflicting user] username=${user.username} email=${user.email} displayName=${user.displayName}`); - - iteratorCallback(); - } else if (result.email !== user.email || result.displayName !== user.displayName) { - debug(`[updating user] username=${user.username} email=${user.email} displayName=${user.displayName}`); - - users.update(result, { email: user.email, fallbackEmail: user.email, displayName: user.displayName }, auditSource.EXTERNAL_LDAP_TASK, function (error) { - if (error) debug('Failed to update user', user, error); - - iteratorCallback(); - }); - } else { - // user known and up-to-date - debug(`[up-to-date user] username=${user.username} email=${user.email} displayName=${user.displayName}`); - - iteratorCallback(); - } - }); - }, function (error) { - if (error) return callback(error); - - ldapGroupSearch(externalLdapConfig, {}, function (error, ldapGroups) { - if (error) return callback(error); - - debug(`Found ${ldapGroups.length} groups`); - - // we ignore all non internal errors here and just log them for now - async.eachSeries(ldapGroups, function (ldapGroup, iteratorCallback) { - console.log(ldapGroup); - - var groupName = ldapGroup[externalLdapConfig.groupnameField || 'cn']; - if (!groupName) return iteratorCallback(); - - groups.getByName(groupName, function (error, result) { - if (error && error.reason !== BoxError.NOT_FOUND) return iteratorCallback(error); - - if (!result) { - debug(`[adding group] groupname=${groupName}`); - - groups.create(groupName, 'ldap', function (error) { - if (error) console.error('Failed to create group', groupName, error); - iteratorCallback(); - }); - } else { - debug(`[up-to-date group] groupname=${groupName}`); - - iteratorCallback(); - } - }); - }, function (error) { - if (error) return callback(error); - - debug('sync: ldap sync is done', error); - - callback(error); - }); - }); - }); + callback(error); }); }); }