diff --git a/CHANGES b/CHANGES index ee9ac15a6..1bddd229f 100644 --- a/CHANGES +++ b/CHANGES @@ -2919,4 +2919,5 @@ * docker: update to 27.5.1 * s3: automatically abort old multipart uploads * notifications: validate domains configs +* ldap: automatically detect pagination support diff --git a/src/externalldap.js b/src/externalldap.js index a391cf82e..c55dbe5d2 100644 --- a/src/externalldap.js +++ b/src/externalldap.js @@ -170,33 +170,60 @@ async function clientSearch(client, dn, searchOptions) { }); } +async function supportsPagination(client) { + assert.strictEqual(typeof client, 'object'); + + const searchOptions = { + scope: 'base', + filter: '(objectClass=*)', + attributes: ['supportedControl', 'supportedExtension', 'supportedFeature'] + }; + + const result = await clientSearch(client, '', searchOptions); + client.unbind(); + const controls = result.supportedControl; + if (!controls || !Array.isArray(controls)) { + debug('supportsPagination: no supportedControl attribute returned'); + return false; + } + + if (!controls.includes(ldap.PagedResultsControl.OID)) { + debug('supportsPagination: server does not support pagination. Available controls:', controls); + return false; + } + + debug('supportsPagination: server supports pagination'); + return true; +} + async function ldapGetByDN(config, dn) { assert.strictEqual(typeof config, 'object'); assert.strictEqual(typeof dn, 'string'); - const searchOptions = { - paged: true, - scope: 'sub' // We may have to make this configurable - }; - debug(`ldapGetByDN: Get object at ${dn}`); const client = await getClient(config, { bind: true }); + const paged = await supportsPagination(client); + const searchOptions = { + paged, + scope: 'sub' + }; const result = await clientSearch(client, dn, searchOptions); client.unbind(); if (result.length === 0) throw new BoxError(BoxError.NOT_FOUND, `dn ${dn} not found`); return result[0]; } -// TODO support search by email async function ldapUserSearch(config, options) { assert.strictEqual(typeof config, 'object'); assert.strictEqual(typeof options, 'object'); + const client = await getClient(config, { bind: true }); + const paged = await supportsPagination(client); const searchOptions = { - paged: true, + paged, filter: ldap.parseFilter(config.filter), - scope: 'sub' // We may have to make this configurable + scope: 'sub' }; if (options.filter) { // https://github.com/ldapjs/node-ldapjs/blob/master/docs/filters.md @@ -204,7 +231,6 @@ async function ldapUserSearch(config, options) { searchOptions.filter = new ldap.AndFilter({ filters: [ extraFilter, searchOptions.filter ] }); } - const client = await getClient(config, { bind: true }); const result = await clientSearch(client, config.baseDn, searchOptions); client.unbind(); return result;