Move autocreation logic into external ldap

This commit is contained in:
Johannes Zellner
2019-11-19 09:53:00 +01:00
parent 8fd0461c62
commit e3cee37527
2 changed files with 74 additions and 65 deletions

View File

@@ -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();
}