diff --git a/src/test/directoryserver-test.js b/src/test/directoryserver-test.js index a6446b84e..8327b6bf9 100644 --- a/src/test/directoryserver-test.js +++ b/src/test/directoryserver-test.js @@ -135,29 +135,59 @@ describe('Directory Server (LDAP)', function () { await ldapBind(`mail=${admin.email},ou=users,dc=cloudron`, admin.password); }); - it('enable 2fa', async function () { + // directory server cannot know the source of the requesting client. + // there are 3 sources - external app, cloudron app, cloudron dashboard. + // the 2fa is requested by client by passing `+totpToken=xxx` . totpToken + // is ignored if the user has no 2fa setup. If present, it is validated. + it('enable 2fa for admin', async function () { twofa = await users.setTwoFactorAuthenticationSecret(admin, auditSource); const totpToken = speakeasy.totp({ secret: twofa.secret, encoding: 'base32' }); await users.enableTwoFactorAuthentication(await users.get(admin.id), totpToken, auditSource); }); - it('fails with empty 2fa', async function () { + it('totp check not requested - fails with bad password', async function () { + const [error] = await safe(ldapBind(`cn=${admin.id},ou=users,dc=cloudron`, admin.password + 'random')); + expect(error).to.be.a(ldap.InvalidCredentialsError); + expect(error.lde_message).to.be('Username and password does not match'); + }); + + it('totp check not requested - succeeds with good password', async function () { + await ldapBind(`cn=${admin.id},ou=users,dc=cloudron`, admin.password); + }); + + it('totp check requested - fails with empty 2fa if user has 2fa', async function () { const [error] = await safe(ldapBind(`cn=${admin.id}+totptoken=,ou=users,dc=cloudron`, admin.password)); expect(error).to.be.a(ldap.InvalidCredentialsError); expect(error.lde_message).to.be('A totpToken must be provided'); }); - it('fails with invalid 2fa', async function () { + it('totp check requested - succeeds with empty 2fa if user has no 2fa', async function () { + await ldapBind(`cn=${user.id}+totptoken=,ou=users,dc=cloudron`, user.password); + }); + + it('totp check requested - fails with invalid 2fa', async function () { const [error] = await safe(ldapBind(`cn=${admin.id}+totptoken=schlecht,ou=users,dc=cloudron`, admin.password)); expect(error).to.be.a(ldap.InvalidCredentialsError); expect(error.lde_message).to.be('Invalid totpToken'); }); - it('fails with no 2fa', async function () { - await ldapBind(`cn=${admin.id},ou=users,dc=cloudron`, admin.password); + it('totp check requested - succeeds with invalid 2fa if user has no 2fa', async function () { + await ldapBind(`cn=${user.id}+totptoken=schlecht,ou=users,dc=cloudron`, user.password); }); - it('succeeds with valid 2fa', async function () { + it('totp check requested - fails with bad password if user has 2fa', async function () { + const totpToken = speakeasy.totp({ secret: twofa.secret, encoding: 'base32' }); + const [error] = await safe(ldapBind(`cn=${admin.email}+totpToken=${totpToken},ou=users,dc=cloudron`, admin.password + 'random')); + expect(error.lde_message).to.be('Username and password does not match'); + }); + + it('totp check requested - fails with bad password if user has no 2fa', async function () { + const totpToken = speakeasy.totp({ secret: twofa.secret, encoding: 'base32' }); + const [error] = await safe(ldapBind(`cn=${admin.email}+totpToken=${totpToken},ou=users,dc=cloudron`, admin.password + 'random')); + expect(error.lde_message).to.be('Username and password does not match'); + }); + + it('totp check requested - succeeds with valid 2fa', async function () { const totpToken = speakeasy.totp({ secret: twofa.secret, encoding: 'base32' }); await ldapBind(`cn=${admin.email}+totpToken=${totpToken},ou=users,dc=cloudron`, admin.password); });