diff --git a/src/test/directoryserver-test.js b/src/test/directoryserver-test.js index 7e3d6165e..571c5b111 100644 --- a/src/test/directoryserver-test.js +++ b/src/test/directoryserver-test.js @@ -13,7 +13,9 @@ const async = require('async'), expect = require('expect.js'), groups = require('../groups.js'), ldap = require('ldapjs'), - safe = require('safetydance'); + safe = require('safetydance'), + speakeasy = require('speakeasy'), + users = require('../users.js'); async function ldapBind(dn, password) { return new Promise((resolve, reject) => { @@ -68,7 +70,7 @@ async function ldapSearch(dn, opts, auth) { } describe('Directory Server (LDAP)', function () { - const { setup, cleanup, admin, user, app, domain } = common; + const { setup, cleanup, admin, user, app, domain, auditSource } = common; let group, group2; const mockApp = Object.assign({}, app); const auth = { @@ -100,6 +102,8 @@ describe('Directory Server (LDAP)', function () { }); describe('user bind', function () { + let twofa; + it('cn= fails for nonexisting user', async function () { const [error] = await safe(ldapBind('cn=doesnotexist,ou=users,dc=cloudron', 'password')); expect(error).to.be.a(ldap.NoSuchObjectError); @@ -130,6 +134,29 @@ describe('Directory Server (LDAP)', function () { it('mail= succeeds with email', async function () { await ldapBind(`mail=${admin.email},ou=users,dc=cloudron`, admin.password); }); + + it('enable 2fa', async function () { + twofa = await users.setTwoFactorAuthenticationSecret(admin.id, auditSource); + const totpToken = speakeasy.totp({ secret: twofa.secret, encoding: 'base32' }); + await users.enableTwoFactorAuthentication(admin.id, totpToken, auditSource); + }); + + it('fails without 2fa', async function () { + const [error] = await safe(ldapBind(`cn=${admin.id},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 () { + 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('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); + }); }); describe('search users', function () { diff --git a/src/test/users-test.js b/src/test/users-test.js index 406315fe5..219d3cfb0 100644 --- a/src/test/users-test.js +++ b/src/test/users-test.js @@ -436,6 +436,12 @@ describe('User', function () { expect(error.reason).to.equal(BoxError.INVALID_CREDENTIALS); expect(error.message).to.be('Invalid totpToken'); }); + + it('verify succeeds with valid 2fa', async function () { + const totpToken = speakeasy.totp({ secret: twofa.secret, encoding: 'base32' }); + const user = await users.verifyWithUsername(admin.username, admin.password, users.AP_WEBADMIN, { totpToken }); + expect(user.id).to.be(admin.id); + }); }); describe('active', function () {