externalldap: add tests

This commit is contained in:
Girish Ramakrishnan
2024-01-07 22:01:57 +01:00
parent c842d02d6f
commit 053f81a53e
10 changed files with 93 additions and 32 deletions
+68 -4
View File
@@ -20,6 +20,7 @@ const async = require('async'),
let gLdapServer;
const LDAP_SHARED_PASSWORD = 'validpassword';
const LDAP_SHARED_TOTP_TOKEN = '1234';
const LDAP_PORT = 4321;
const LDAP_BASE_DN = 'ou=Users,dc=cloudron,dc=io';
const LDAP_GROUP_BASE_DN = 'ou=Groups,dc=cloudron,dc=io';
@@ -111,7 +112,7 @@ function startLdapServer(callback) {
const obj = {
dn: dn.toString(),
attributes: {
objectclass: [ 'inetOrgPerson' ],
objectclass: [ 'inetorgperson' ],
mail: entry.email,
cn: entry.displayName
}
@@ -156,11 +157,20 @@ function startLdapServer(callback) {
// extract the common name which might have different attribute names
const attributeName = Object.keys(req.dn.rdns[0].attrs)[0];
const commonName = req.dn.rdns[0].attrs[attributeName].value;
if (!commonName) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (!commonName) return next(new ldap.NoSuchObjectError('Missing CN'));
if (!gLdapUsers.find(function (u) { return u.username === commonName; })) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (req.credentials !== LDAP_SHARED_PASSWORD) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
// this code here is only for completeness. none of the apps send totptoken
const TOTPTOKEN_ATTRIBUTE_NAME = 'totptoken';
const totpToken = TOTPTOKEN_ATTRIBUTE_NAME in req.dn.rdns[0].attrs ? req.dn.rdns[0].attrs[TOTPTOKEN_ATTRIBUTE_NAME].value : null;
const skipTotpCheck = !(TOTPTOKEN_ATTRIBUTE_NAME in req.dn.rdns[0].attrs);
const u = gLdapUsers.find(function (u) { return u.username === commonName; });
if (!u) return next(new ldap.NoSuchObjectError('No such user'));
if (req.credentials !== LDAP_SHARED_PASSWORD) return next(new ldap.InvalidCredentialsError('Bad password'));
if (!skipTotpCheck && u.has2fa) {
if (!totpToken) return next(new ldap.InvalidCredentialsError('totpToken is required'));
if (totpToken !== LDAP_SHARED_TOTP_TOKEN) return next(new ldap.InvalidCredentialsError('Invalid totpToken'));
}
res.end();
});
@@ -309,7 +319,61 @@ describe('External LDAP', function () {
});
});
describe('verifyPassword', function () {
before(async function () {
await externalLdap.setConfig(LDAP_CONFIG);
gLdapUsers = [{
username: 'maximus',
displayName: 'First User',
email: 'first@user.com'
}];
});
it('fails for unknown user', async function () {
const [error] = await safe(externalLdap.verifyPassword('badusername', 'badpassword', null));
expect(error.reason).to.be(BoxError.NOT_FOUND);
});
it('fails for bad password', async function () {
const [error] = await safe(externalLdap.verifyPassword('maximus', 'badpassword', null));
expect(error.reason).to.be(BoxError.INVALID_CREDENTIALS);
});
it('succeeds for valid password', async function () {
const u = await externalLdap.verifyPassword('maximus', LDAP_SHARED_PASSWORD, null);
expect(u.username).to.be('maximus');
});
it('enable totp', () => gLdapUsers[0].has2fa = true);
it('succeeds when totp required and no totp', async function () {
const u = await externalLdap.verifyPassword('maximus', LDAP_SHARED_PASSWORD, null);
expect(u.username).to.be('maximus');
});
it('fails when totp required and empty totp', async function () {
const [error] = await safe(externalLdap.verifyPassword('maximus', LDAP_SHARED_PASSWORD, ''));
expect(error.reason).to.be(BoxError.INVALID_CREDENTIALS);
});
it('fails when totp required and bad totp', async function () {
const [error] = await safe(externalLdap.verifyPassword('maximus', LDAP_SHARED_PASSWORD, 'badtotp'));
expect(error.reason).to.be(BoxError.INVALID_CREDENTIALS);
});
it('succeeds when totp required and good totp', async function () {
const u = await externalLdap.verifyPassword('maximus', LDAP_SHARED_PASSWORD, LDAP_SHARED_TOTP_TOKEN);
expect(u.username).to.be('maximus');
});
});
describe('sync', function () {
before(function () {
gLdapUsers = [];
gLdapGroups = [];
});
it('disable sync', async function () {
await externalLdap.setConfig({ provider: 'noop' });
});