diff --git a/src/ldap.js b/src/ldap.js index 40c810a78..783bea51f 100644 --- a/src/ldap.js +++ b/src/ldap.js @@ -636,10 +636,12 @@ async function authenticateMail(req, res, next) { } // https://ldapwiki.com/wiki/RootDSE / RFC 4512 - ldapsearch -x -h "${CLOUDRON_LDAP_SERVER}" -p "${CLOUDRON_LDAP_PORT}" -b "" -s base -async function rootDSE(req, res, next) { - debug(`rootDSE: requested with scope ${req.scope}`); +// ldapjs seems to call this handler for everything when search === '' +async function maybeRootDSE(req, res, next) { + debug(`maybeRootDSE: requested with scope:${req.scope} dn:${req.dn.toString()}`); if (req.scope !== 'base') return next(new ldap.NoSuchObjectError()); // per the spec, rootDSE search require base scope + if (!req.dn || req.dn.toString() !== '') return next(new ldap.NoSuchObjectError()); res.send({ dn: '', @@ -669,7 +671,6 @@ async function start() { debug('start: server error ', error); }); - gServer.search('', rootDSE); gServer.search('ou=users,dc=cloudron', authenticateApp, userSearch); gServer.search('ou=groups,dc=cloudron', authenticateApp, groupSearch); gServer.bind('ou=users,dc=cloudron', authenticateApp, authenticateUser, authorizeUserForApp); @@ -714,6 +715,8 @@ async function start() { finalSend([obj], req, res, next); }); + gServer.search('', maybeRootDSE); // when '', it seems the callback is called for everything else + // just log that an attempt was made to unknown route, this helps a lot during app packaging gServer.use(function(req, res, next) { debug('not handled: dn %s, scope %s, filter %s (from %s)', req.dn ? req.dn.toString() : '-', req.scope, req.filter ? req.filter.toString() : '-', req.connection.ldap.id); diff --git a/src/test/ldap-test.js b/src/test/ldap-test.js index ca9b42531..315b728e0 100644 --- a/src/test/ldap-test.js +++ b/src/test/ldap-test.js @@ -94,6 +94,17 @@ describe('Ldap', function () { ], done); }); + describe('root DSE', function () { + it('can get root DSE', async function () { + const entries = await ldapSearch('', { filter: 'objectcategory=person' }); + expect(entries.length).to.be(1); + expect(entries[0].dn).to.be(''); + expect(entries[0].supportedLDAPVersion).to.be('3'); + expect(entries[0].vendorName).to.be('Cloudron LDAP'); + expect(entries[0].vendorVersion).to.be('1.0.0'); + }); + }); + describe('admin bind', function () { it('cn= fails for nonexisting user', async function () { const [error] = await safe(ldapBind('cn=doesnotexist,ou=users,dc=cloudron', 'password'));