fix(ldap): allowing usage of searchStreaming function in no-paged
Signed-off-by: Antonio Musolino <antoniomusolino007@gmail.com>
This commit is contained in:
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
import { ForwardedError, stringifyError } from '@backstage/errors';
|
||||
import ldap, { Client, SearchEntry, SearchOptions } from 'ldapjs';
|
||||
import { cloneDeep, merge } from 'lodash';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { Logger } from 'winston';
|
||||
import { BindConfig, TLSConfig } from './config';
|
||||
import { errorString } from './util';
|
||||
import { createOptions, errorString } from './util';
|
||||
import {
|
||||
ActiveDirectoryVendor,
|
||||
DefaultLdapVendor,
|
||||
@@ -150,54 +150,60 @@ export class LdapClient {
|
||||
f: (entry: SearchEntry) => Promise<void> | void,
|
||||
): Promise<void> {
|
||||
try {
|
||||
let awaitList: Array<Promise<void> | void> = [];
|
||||
return await new Promise<void>((resolve, reject) => {
|
||||
// Note that we clone the (frozen) options, since ldapjs rudely tries to
|
||||
// overwrite parts of them
|
||||
this.client.search(
|
||||
dn,
|
||||
merge(cloneDeep(options), { paged: { pagePause: true } }),
|
||||
(err, res) => {
|
||||
if (err) {
|
||||
reject(new Error(errorString(err)));
|
||||
}
|
||||
this.client.search(dn, createOptions(options), (err, res) => {
|
||||
if (err) {
|
||||
reject(new Error(errorString(err)));
|
||||
}
|
||||
let awaitList: Array<Promise<void> | void> = [];
|
||||
let transformError = false;
|
||||
|
||||
res.on('searchReference', () => {
|
||||
this.logger.warn('Received unsupported search referral');
|
||||
});
|
||||
const transformReject = (e: Error) => {
|
||||
transformError = true;
|
||||
reject(
|
||||
new Error(
|
||||
`Transform function threw an exception, ${stringifyError(e)}`,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
res.on('searchEntry', entry => {
|
||||
awaitList.push(f(entry));
|
||||
});
|
||||
res.on('searchReference', () => {
|
||||
this.logger.warn('Received unsupported search referral');
|
||||
});
|
||||
|
||||
res.on('page', (_, cb) => {
|
||||
// awaits completion before fetching next page
|
||||
res.on('searchEntry', entry => {
|
||||
if (!transformError) awaitList.push(f(entry));
|
||||
});
|
||||
|
||||
res.on('page', (_, cb) => {
|
||||
// awaits completion before fetching next page
|
||||
Promise.all(awaitList)
|
||||
.then(() => {
|
||||
// flush list
|
||||
awaitList = [];
|
||||
if (cb) cb();
|
||||
})
|
||||
.catch(transformReject);
|
||||
});
|
||||
|
||||
res.on('error', e => {
|
||||
reject(new Error(errorString(e)));
|
||||
});
|
||||
|
||||
res.on('end', r => {
|
||||
if (!r) {
|
||||
throw new Error('Null response');
|
||||
} else if (r.status !== 0) {
|
||||
throw new Error(`Got status ${r.status}: ${r.errorMessage}`);
|
||||
} else {
|
||||
Promise.all(awaitList)
|
||||
.then(() => {
|
||||
// flush list
|
||||
awaitList = [];
|
||||
if (cb) cb();
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
res.on('error', e => {
|
||||
reject(new Error(errorString(e)));
|
||||
});
|
||||
|
||||
res.on('end', r => {
|
||||
if (!r) {
|
||||
throw new Error('Null response');
|
||||
} else if (r.status !== 0) {
|
||||
throw new Error(`Got status ${r.status}: ${r.errorMessage}`);
|
||||
} else {
|
||||
Promise.all(awaitList)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
.then(() => resolve())
|
||||
.catch(transformReject);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
throw new ForwardedError(`LDAP search at DN "${dn}" failed`, e);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { errorString } from './util';
|
||||
import { errorString, createOptions } from './util';
|
||||
|
||||
describe('errorString', () => {
|
||||
it('formats', () => {
|
||||
@@ -22,3 +22,52 @@ describe('errorString', () => {
|
||||
expect(errorString(e)).toEqual('1 n: m');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createOptions', () => {
|
||||
it('should add pagePause', () => {
|
||||
const options = {
|
||||
filter: 'f',
|
||||
paged: true,
|
||||
timeLimit: 42,
|
||||
sizeLimit: 100,
|
||||
derefAliases: 0,
|
||||
typesOnly: false,
|
||||
};
|
||||
expect(createOptions(options)).toEqual({
|
||||
filter: 'f',
|
||||
paged: { pagePause: true },
|
||||
timeLimit: 42,
|
||||
sizeLimit: 100,
|
||||
derefAliases: 0,
|
||||
typesOnly: false,
|
||||
});
|
||||
const options2 = {
|
||||
filter: 'f',
|
||||
paged: {},
|
||||
timeLimit: 42,
|
||||
sizeLimit: 100,
|
||||
derefAliases: 0,
|
||||
typesOnly: false,
|
||||
};
|
||||
expect(createOptions(options2)).toEqual({
|
||||
filter: 'f',
|
||||
paged: { pagePause: true },
|
||||
timeLimit: 42,
|
||||
sizeLimit: 100,
|
||||
derefAliases: 0,
|
||||
typesOnly: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not add pagePause', () => {
|
||||
const options = {
|
||||
filter: 'f',
|
||||
paged: false,
|
||||
timeLimit: 42,
|
||||
sizeLimit: 100,
|
||||
derefAliases: 0,
|
||||
typesOnly: false,
|
||||
};
|
||||
expect(createOptions(options)).toEqual(options);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Error as LDAPError, SearchEntry } from 'ldapjs';
|
||||
import { Error as LDAPError, SearchEntry, SearchOptions } from 'ldapjs';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { LdapVendor } from './vendors';
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,18 @@ export function mapStringAttr(
|
||||
}
|
||||
}
|
||||
|
||||
export function createOptions(inputOptions: SearchOptions): SearchOptions {
|
||||
const result = cloneDeep(inputOptions);
|
||||
|
||||
if (result.paged === true) {
|
||||
result.paged = { pagePause: true };
|
||||
} else if (typeof result.paged === 'object') {
|
||||
result.paged.pagePause = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export type RecursivePartial<T> = {
|
||||
[P in keyof T]?: T[P] extends (infer U)[]
|
||||
? RecursivePartial<U>[]
|
||||
|
||||
Reference in New Issue
Block a user