Move autocreation logic into external ldap
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
exports = module.exports = {
|
||||
search: search,
|
||||
verifyPassword: verifyPassword,
|
||||
createAndVerifyUserIfNotExist: createAndVerifyUserIfNotExist,
|
||||
|
||||
testConfig: testConfig,
|
||||
startSyncer: startSyncer,
|
||||
@@ -34,6 +35,25 @@ function removePrivateFields(ldapConfig) {
|
||||
return ldapConfig;
|
||||
}
|
||||
|
||||
function translateUser(ldapConfig, ldapUser) {
|
||||
assert.strictEqual(typeof ldapConfig, 'object');
|
||||
|
||||
return {
|
||||
username: ldapUser[ldapConfig.usernameField],
|
||||
email: ldapUser.mail,
|
||||
displayName: ldapUser.cn // user.giveName + ' ' + user.sn
|
||||
};
|
||||
}
|
||||
|
||||
function validUserRequirements(user) {
|
||||
if (!user.username || !user.email || !user.displayName) {
|
||||
debug(`[LDAP user empty username/email/displayName] username=${user.username} email=${user.email} displayName=${user.displayName}`);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// performs service bind if required
|
||||
function getClient(externalLdapConfig, callback) {
|
||||
assert.strictEqual(typeof externalLdapConfig, 'object');
|
||||
@@ -151,19 +171,46 @@ function search(identifier, callback) {
|
||||
if (error) return callback(error);
|
||||
|
||||
// translate ldap properties to ours
|
||||
let users = ldapUsers.map(function (u) {
|
||||
return {
|
||||
username: u[externalLdapConfig.usernameField],
|
||||
email: u.mail,
|
||||
displayName: u.cn // user.giveName + ' ' + user.sn
|
||||
};
|
||||
});
|
||||
let users = ldapUsers.map(function (u) { return translateUser(externalLdapConfig, u); });
|
||||
|
||||
callback(null, users);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createAndVerifyUserIfNotExist(identifier, password, callback) {
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
settings.getExternalLdapConfig(function (error, externalLdapConfig) {
|
||||
if (error) return callback(error);
|
||||
if (externalLdapConfig.provider === 'noop') return callback(new BoxError(BoxError.BAD_STATE, 'not enabled'));
|
||||
if (!externalLdapConfig.autoCreate) return callback(new BoxError(BoxError.BAD_STATE, 'auto create not enabled'));
|
||||
|
||||
ldapSearch(externalLdapConfig, { filter: `${externalLdapConfig.usernameField}=${identifier}` }, function (error, users) {
|
||||
if (error) return callback(error);
|
||||
if (users.length === 0) return callback(new BoxError(BoxError.NOT_FOUND));
|
||||
if (users.length > 1) return callback(new BoxError(BoxError.CONFLICT));
|
||||
|
||||
let user = translateUser(externalLdapConfig, users[0]);
|
||||
if (!validUserRequirements(user)) return callback(new BoxError(BoxError.BAD_FIELD));
|
||||
|
||||
users.create(user.username, null /* password */, user.email, user.displayName, { source: 'ldap' }, auditSource.EXTERNAL_LDAP_AUTO_CREATE, function (error, user) {
|
||||
if (error) {
|
||||
console.error('Failed to auto create user', user.username, error);
|
||||
return callback(new BoxError(BoxError.INTERNAL_ERROR));
|
||||
}
|
||||
|
||||
verifyPassword(user, password, function (error) {
|
||||
if (error) return callback(error);
|
||||
callback(null, user);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function verifyPassword(user, password, callback) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
@@ -178,18 +225,12 @@ function verifyPassword(user, password, callback) {
|
||||
if (ldapUsers.length === 0) return callback(new BoxError(BoxError.NOT_FOUND));
|
||||
if (ldapUsers.length > 1) return callback(new BoxError(BoxError.CONFLICT));
|
||||
|
||||
const userDn = ldapUsers[0].dn;
|
||||
let client = ldap.createClient({ url: externalLdapConfig.url });
|
||||
|
||||
client.bind(userDn, password, function (error) {
|
||||
client.bind(ldapUsers[0].dn, password, function (error) {
|
||||
if (error instanceof ldap.InvalidCredentialsError) return callback(new BoxError(BoxError.INVALID_CREDENTIALS));
|
||||
if (error) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error));
|
||||
|
||||
callback(null, {
|
||||
username: ldapUsers[0][externalLdapConfig.usernameField],
|
||||
email: ldapUsers[0].mail,
|
||||
displayName: ldapUsers[0].cn // user.giveName + ' ' + user.sn
|
||||
});
|
||||
callback(null, translateUser(externalLdapConfig, ldapUsers[0]));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -233,46 +274,41 @@ function sync(progressCallback, callback) {
|
||||
|
||||
// we ignore all errors here and just log them for now
|
||||
async.eachSeries(ldapUsers, function (user, iteratorCallback) {
|
||||
const username = user[externalLdapConfig.usernameField];
|
||||
const email = user.mail;
|
||||
const displayName = user.cn; // user.giveName + ' ' + user.sn
|
||||
user = translateUser(externalLdapConfig, user);
|
||||
|
||||
if (!username || !email || !displayName) {
|
||||
debug(`[empty username/email/displayName] username=${username} email=${email} displayName=${displayName} usernameField=${externalLdapConfig.usernameField}`);
|
||||
return iteratorCallback();
|
||||
}
|
||||
if (!validUserRequirements(user)) return iteratorCallback();
|
||||
|
||||
percent += step;
|
||||
progressCallback({ percent, message: `Syncing... ${username}` });
|
||||
progressCallback({ percent, message: `Syncing... ${user.username}` });
|
||||
|
||||
users.getByUsername(username, function (error, result) {
|
||||
users.getByUsername(user.username, function (error, result) {
|
||||
if (error && error.reason !== BoxError.NOT_FOUND) {
|
||||
debug(`Could not find user with username ${username}: ${error.message}`);
|
||||
debug(`Could not find user with username ${user.username}: ${error.message}`);
|
||||
return iteratorCallback();
|
||||
}
|
||||
|
||||
if (error) {
|
||||
debug(`[adding user] username=${username} email=${email} displayName=${displayName}`);
|
||||
debug(`[adding user] username=${user.username} email=${user.email} displayName=${user.displayName}`);
|
||||
|
||||
users.create(username, null /* password */, email, displayName, { source: 'ldap' }, auditSource.EXTERNAL_LDAP_TASK, function (error) {
|
||||
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=${username} email=${email} displayName=${displayName}`);
|
||||
debug(`[conflicting user] username=${user.username} email=${user.email} displayName=${user.displayName}`);
|
||||
|
||||
iteratorCallback();
|
||||
} else if (result.email !== email || result.displayName !== displayName) {
|
||||
debug(`[updating user] username=${username} email=${email} displayName=${displayName}`);
|
||||
} 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.id, { email: email, fallbackEmail: email, displayName: displayName }, auditSource.EXTERNAL_LDAP_TASK, function (error) {
|
||||
users.update(result.id, { 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=${username} email=${email} displayName=${displayName}`);
|
||||
debug(`[up-to-date user] username=${user.username} email=${user.email} displayName=${user.displayName}`);
|
||||
|
||||
iteratorCallback();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user