make dnAttributeName and uuidAttributeName for ldap vendors configurable
Signed-off-by: Kashish Mittal <kmittal@redhat.com>
This commit is contained in:
@@ -19,15 +19,9 @@ import { readFile } from 'fs/promises';
|
||||
import ldap, { Client, SearchEntry, SearchOptions } from 'ldapjs';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import tlsLib from 'tls';
|
||||
import { BindConfig, TLSConfig } from './config';
|
||||
import { BindConfig, TLSConfig, VendorConfig } from './config';
|
||||
import { createOptions, errorString } from './util';
|
||||
import {
|
||||
AEDirVendor,
|
||||
ActiveDirectoryVendor,
|
||||
DefaultLdapVendor,
|
||||
FreeIpaVendor,
|
||||
LdapVendor,
|
||||
} from './vendors';
|
||||
import { CreateLdapVendor, LdapVendor } from './vendors';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
@@ -232,20 +226,16 @@ export class LdapClient {
|
||||
*
|
||||
* @see https://ldapwiki.com/wiki/Determine%20LDAP%20Server%20Vendor
|
||||
*/
|
||||
async getVendor(): Promise<LdapVendor> {
|
||||
async getVendor(vendorConfig: VendorConfig): Promise<LdapVendor> {
|
||||
if (this.vendor) {
|
||||
return this.vendor;
|
||||
}
|
||||
this.vendor = this.getRootDSE()
|
||||
.then(root => {
|
||||
if (root && root.raw?.forestFunctionality) {
|
||||
return ActiveDirectoryVendor;
|
||||
} else if (root && root.raw?.ipaDomainLevel) {
|
||||
return FreeIpaVendor;
|
||||
} else if (root && 'aeRoot' in root.raw) {
|
||||
return AEDirVendor;
|
||||
}
|
||||
return DefaultLdapVendor;
|
||||
return CreateLdapVendor(
|
||||
vendorConfig,
|
||||
!!(root && root.raw?.forestFunctionality),
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
this.vendor = undefined;
|
||||
|
||||
@@ -78,6 +78,10 @@ describe('readLdapConfig', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
vendor: {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
},
|
||||
},
|
||||
];
|
||||
expect(actual).toEqual(expected);
|
||||
@@ -151,6 +155,10 @@ describe('readLdapConfig', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
vendor: {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
},
|
||||
},
|
||||
];
|
||||
expect(actual).toEqual(expected);
|
||||
@@ -291,6 +299,10 @@ describe('readLdapConfig', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
vendor: {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
},
|
||||
},
|
||||
];
|
||||
expect(actual).toEqual(expected);
|
||||
|
||||
@@ -47,6 +47,10 @@ export type LdapProviderConfig = {
|
||||
groups: GroupConfig[];
|
||||
// Schedule configuration for refresh tasks.
|
||||
schedule?: SchedulerServiceTaskScheduleDefinition;
|
||||
// Configuration for LDAP vendor-specific attributes. If not specified, the default values will be used:
|
||||
// - `dnAttributeName`: `entryDN`
|
||||
// - `uuidAttributeName`: `entryUUID`
|
||||
vendor: VendorConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -161,6 +165,26 @@ export type GroupConfig = {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration for LDAP vendor-specific attributes.
|
||||
*
|
||||
* Allows custom attribute names for distinguished names (DN) and
|
||||
* universally unique identifiers (UUID) in LDAP directories.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type VendorConfig = {
|
||||
/**
|
||||
* Attribute name for the distinguished name (DN) of an entry,
|
||||
*/
|
||||
dnAttributeName: string;
|
||||
|
||||
/**
|
||||
* Attribute name for the unique identifier (UUID) of an entry,
|
||||
*/
|
||||
uuidAttributeName: string;
|
||||
};
|
||||
|
||||
const defaultUserConfig = {
|
||||
options: {
|
||||
scope: 'one',
|
||||
@@ -225,6 +249,21 @@ function readBindConfig(
|
||||
};
|
||||
}
|
||||
|
||||
function readVendorConfig(
|
||||
c: Config | undefined,
|
||||
): LdapProviderConfig['vendor'] | undefined {
|
||||
if (!c) {
|
||||
return {
|
||||
dnAttributeName: `entryDN`,
|
||||
uuidAttributeName: `entryUUID`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
dnAttributeName: c.getString('dn'),
|
||||
uuidAttributeName: c.getString('uuidAttributeName'),
|
||||
};
|
||||
}
|
||||
|
||||
function readOptionsConfig(c: Config | undefined): SearchOptions {
|
||||
if (!c) {
|
||||
return {};
|
||||
@@ -375,6 +414,7 @@ export function readLdapLegacyConfig(config: Config): LdapProviderConfig[] {
|
||||
groups: readGroupConfig(c.getConfig('groups')).map(it => {
|
||||
return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);
|
||||
}),
|
||||
vendor: readVendorConfig(c.getOptionalConfig('vendor')),
|
||||
};
|
||||
|
||||
return freeze(newConfig) as LdapProviderConfig;
|
||||
@@ -426,6 +466,7 @@ export function readProviderConfigs(config: Config): LdapProviderConfig[] {
|
||||
return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);
|
||||
}),
|
||||
schedule,
|
||||
vendor: readVendorConfig(c.getOptionalConfig('vendor')),
|
||||
};
|
||||
|
||||
return freeze(newConfig) as LdapProviderConfig;
|
||||
|
||||
@@ -18,7 +18,7 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model';
|
||||
import { SearchEntry } from 'ldapjs';
|
||||
import merge from 'lodash/merge';
|
||||
import { LdapClient } from './client';
|
||||
import { GroupConfig, UserConfig } from './config';
|
||||
import { GroupConfig, UserConfig, VendorConfig } from './config';
|
||||
import {
|
||||
LDAP_DN_ANNOTATION,
|
||||
LDAP_RDN_ANNOTATION,
|
||||
@@ -32,11 +32,8 @@ import {
|
||||
resolveRelations,
|
||||
} from './read';
|
||||
import { RecursivePartial } from './util';
|
||||
import {
|
||||
ActiveDirectoryVendor,
|
||||
DefaultLdapVendor,
|
||||
FreeIpaVendor,
|
||||
} from './vendors';
|
||||
|
||||
import { CreateLdapVendor } from './vendors';
|
||||
|
||||
function user(data: RecursivePartial<UserEntity>): UserEntity {
|
||||
return merge(
|
||||
@@ -84,7 +81,11 @@ describe('readLdapUsers', () => {
|
||||
afterEach(() => jest.resetAllMocks());
|
||||
|
||||
it('transfers all attributes from a default ldap vendor', async () => {
|
||||
client.getVendor.mockResolvedValue(DefaultLdapVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, false));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -99,7 +100,7 @@ describe('readLdapUsers', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: UserConfig[] = [
|
||||
const userConfig: UserConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -114,7 +115,11 @@ describe('readLdapUsers', () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
const { users, userMemberOf } = await readLdapUsers(client, config);
|
||||
const { users, userMemberOf } = await readLdapUsers(
|
||||
client,
|
||||
userConfig,
|
||||
vendorConfig,
|
||||
);
|
||||
expect(users).toEqual([
|
||||
expect.objectContaining({
|
||||
metadata: {
|
||||
@@ -142,7 +147,11 @@ describe('readLdapUsers', () => {
|
||||
});
|
||||
|
||||
it('transfers all attributes from Microsoft Active Directory', async () => {
|
||||
client.getVendor.mockResolvedValue(ActiveDirectoryVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'distinguishedName',
|
||||
uuidAttributeName: 'objectGUID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, true));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -162,7 +171,7 @@ describe('readLdapUsers', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: UserConfig[] = [
|
||||
const userConfig: UserConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -177,7 +186,11 @@ describe('readLdapUsers', () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
const { users, userMemberOf } = await readLdapUsers(client, config);
|
||||
const { users, userMemberOf } = await readLdapUsers(
|
||||
client,
|
||||
userConfig,
|
||||
vendorConfig,
|
||||
);
|
||||
expect(users).toEqual([
|
||||
expect.objectContaining({
|
||||
metadata: {
|
||||
@@ -205,7 +218,11 @@ describe('readLdapUsers', () => {
|
||||
});
|
||||
|
||||
it('transfers all attributes from FreeIPA', async () => {
|
||||
client.getVendor.mockResolvedValue(FreeIpaVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'dn',
|
||||
uuidAttributeName: 'ipaUniqueID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, false));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -220,7 +237,7 @@ describe('readLdapUsers', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: UserConfig[] = [
|
||||
const userConfig: UserConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -235,7 +252,11 @@ describe('readLdapUsers', () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
const { users, userMemberOf } = await readLdapUsers(client, config);
|
||||
const { users, userMemberOf } = await readLdapUsers(
|
||||
client,
|
||||
userConfig,
|
||||
vendorConfig,
|
||||
);
|
||||
expect(users).toEqual([
|
||||
expect.objectContaining({
|
||||
metadata: {
|
||||
@@ -262,7 +283,11 @@ describe('readLdapUsers', () => {
|
||||
);
|
||||
});
|
||||
it('can process a list of UserConfigs', async () => {
|
||||
client.getVendor.mockResolvedValue(DefaultLdapVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, false));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -277,7 +302,7 @@ describe('readLdapUsers', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: UserConfig[] = [
|
||||
const userConfig: UserConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -305,12 +330,16 @@ describe('readLdapUsers', () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
const { users } = await readLdapUsers(client, config);
|
||||
const { users } = await readLdapUsers(client, userConfig, vendorConfig);
|
||||
expect(users).toHaveLength(2);
|
||||
});
|
||||
it('can process no UserConfigs', async () => {
|
||||
const config: UserConfig[] = [];
|
||||
const { users } = await readLdapUsers(client, config);
|
||||
const userConfig: UserConfig[] = [];
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
const { users } = await readLdapUsers(client, userConfig, vendorConfig);
|
||||
expect(users).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
@@ -324,7 +353,11 @@ describe('readLdapGroups', () => {
|
||||
afterEach(() => jest.resetAllMocks());
|
||||
|
||||
it('transfers all attributes from a default ldap vendor', async () => {
|
||||
client.getVendor.mockResolvedValue(DefaultLdapVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, false));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -340,7 +373,7 @@ describe('readLdapGroups', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: GroupConfig[] = [
|
||||
const groupConfig: GroupConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -359,7 +392,8 @@ describe('readLdapGroups', () => {
|
||||
];
|
||||
const { groups, groupMember, groupMemberOf } = await readLdapGroups(
|
||||
client,
|
||||
config,
|
||||
groupConfig,
|
||||
vendorConfig,
|
||||
);
|
||||
expect(groups).toEqual([
|
||||
expect.objectContaining({
|
||||
@@ -392,7 +426,11 @@ describe('readLdapGroups', () => {
|
||||
});
|
||||
|
||||
it('transfers all attributes from Microsoft Active Directory', async () => {
|
||||
client.getVendor.mockResolvedValue(ActiveDirectoryVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'distinguishedName',
|
||||
uuidAttributeName: 'objectGUID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, true));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -413,7 +451,7 @@ describe('readLdapGroups', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: GroupConfig[] = [
|
||||
const groupConfig: GroupConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -432,7 +470,8 @@ describe('readLdapGroups', () => {
|
||||
];
|
||||
const { groups, groupMember, groupMemberOf } = await readLdapGroups(
|
||||
client,
|
||||
config,
|
||||
groupConfig,
|
||||
vendorConfig,
|
||||
);
|
||||
expect(groups).toEqual([
|
||||
expect.objectContaining({
|
||||
@@ -465,7 +504,11 @@ describe('readLdapGroups', () => {
|
||||
});
|
||||
|
||||
it('can process a list of GroupConfigs', async () => {
|
||||
client.getVendor.mockResolvedValue(DefaultLdapVendor);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
client.getVendor.mockResolvedValue(CreateLdapVendor(vendorConfig, false));
|
||||
client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => {
|
||||
await fn(
|
||||
searchEntry({
|
||||
@@ -481,7 +524,7 @@ describe('readLdapGroups', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
const config: GroupConfig[] = [
|
||||
const groupConfig: GroupConfig[] = [
|
||||
{
|
||||
dn: 'ddd',
|
||||
options: {},
|
||||
@@ -513,13 +556,17 @@ describe('readLdapGroups', () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
const { groups } = await readLdapGroups(client, config);
|
||||
const { groups } = await readLdapGroups(client, groupConfig, vendorConfig);
|
||||
expect(groups).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('can process no GroupConfigs', async () => {
|
||||
const config: GroupConfig[] = [];
|
||||
const { groups } = await readLdapGroups(client, config);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
const groupConfig: GroupConfig[] = [];
|
||||
const { groups } = await readLdapGroups(client, groupConfig, vendorConfig);
|
||||
expect(groups).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
@@ -679,8 +726,12 @@ describe('defaultUserTransformer', () => {
|
||||
entryDN: ['dn-value'],
|
||||
entryUUID: ['uuid-value'],
|
||||
});
|
||||
|
||||
let output = await defaultUserTransformer(DefaultLdapVendor, config, entry);
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
const defaultLdapVendor = CreateLdapVendor(vendorConfig, false);
|
||||
let output = await defaultUserTransformer(defaultLdapVendor, config, entry);
|
||||
expect(output).toEqual({
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'User',
|
||||
@@ -703,7 +754,7 @@ describe('defaultUserTransformer', () => {
|
||||
(output!.metadata.annotations as any).c = 7;
|
||||
|
||||
// exact same inputs again
|
||||
output = await defaultUserTransformer(DefaultLdapVendor, config, entry);
|
||||
output = await defaultUserTransformer(defaultLdapVendor, config, entry);
|
||||
expect(output).toEqual({
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'User',
|
||||
@@ -757,8 +808,13 @@ describe('defaultGroupTransformer', () => {
|
||||
entryUUID: ['uuid-value'],
|
||||
});
|
||||
|
||||
const vendorConfig: VendorConfig = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
};
|
||||
const defaultLdapVendor = CreateLdapVendor(vendorConfig, false);
|
||||
let output = await defaultGroupTransformer(
|
||||
DefaultLdapVendor,
|
||||
defaultLdapVendor,
|
||||
config,
|
||||
entry,
|
||||
);
|
||||
@@ -786,7 +842,7 @@ describe('defaultGroupTransformer', () => {
|
||||
(output!.metadata.annotations as any).c = 7;
|
||||
|
||||
// exact same inputs again
|
||||
output = await defaultGroupTransformer(DefaultLdapVendor, config, entry);
|
||||
output = await defaultGroupTransformer(defaultLdapVendor, config, entry);
|
||||
expect(output).toEqual({
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Group',
|
||||
|
||||
@@ -24,7 +24,7 @@ import lodashSet from 'lodash/set';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { buildOrgHierarchy } from './org';
|
||||
import { LdapClient } from './client';
|
||||
import { GroupConfig, UserConfig } from './config';
|
||||
import { GroupConfig, UserConfig, VendorConfig } from './config';
|
||||
import {
|
||||
LDAP_DN_ANNOTATION,
|
||||
LDAP_RDN_ANNOTATION,
|
||||
@@ -104,22 +104,23 @@ export async function defaultUserTransformer(
|
||||
*/
|
||||
export async function readLdapUsers(
|
||||
client: LdapClient,
|
||||
config: UserConfig[],
|
||||
userConfig: UserConfig[],
|
||||
vendorConfig: VendorConfig,
|
||||
opts?: { transformer?: UserTransformer },
|
||||
): Promise<{
|
||||
users: UserEntity[]; // With all relations empty
|
||||
userMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups
|
||||
}> {
|
||||
if (config.length === 0) {
|
||||
if (userConfig.length === 0) {
|
||||
return { users: [], userMemberOf: new Map() };
|
||||
}
|
||||
const entities: UserEntity[] = [];
|
||||
const userMemberOf: Map<string, Set<string>> = new Map();
|
||||
|
||||
const vendor = await client.getVendor();
|
||||
const vendor = await client.getVendor(vendorConfig);
|
||||
const transformer = opts?.transformer ?? defaultUserTransformer;
|
||||
|
||||
for (const cfg of config) {
|
||||
for (const cfg of userConfig) {
|
||||
const { dn, options, map } = cfg;
|
||||
await client.searchStreaming(dn, options, async user => {
|
||||
const entity = await transformer(vendor, cfg, user);
|
||||
@@ -210,7 +211,8 @@ export async function defaultGroupTransformer(
|
||||
*/
|
||||
export async function readLdapGroups(
|
||||
client: LdapClient,
|
||||
config: GroupConfig[],
|
||||
groupConfig: GroupConfig[],
|
||||
vendorConfig: VendorConfig,
|
||||
opts?: {
|
||||
transformer?: GroupTransformer;
|
||||
},
|
||||
@@ -219,17 +221,17 @@ export async function readLdapGroups(
|
||||
groupMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups
|
||||
groupMember: Map<string, Set<string>>; // DN -> DN or UUID of groups & users
|
||||
}> {
|
||||
if (config.length === 0) {
|
||||
if (groupConfig.length === 0) {
|
||||
return { groups: [], groupMemberOf: new Map(), groupMember: new Map() };
|
||||
}
|
||||
const groups: GroupEntity[] = [];
|
||||
const groupMemberOf: Map<string, Set<string>> = new Map();
|
||||
const groupMember: Map<string, Set<string>> = new Map();
|
||||
|
||||
const vendor = await client.getVendor();
|
||||
const vendor = await client.getVendor(vendorConfig);
|
||||
const transformer = opts?.transformer ?? defaultGroupTransformer;
|
||||
|
||||
for (const cfg of config) {
|
||||
for (const cfg of groupConfig) {
|
||||
const { dn, map, options } = cfg;
|
||||
|
||||
await client.searchStreaming(dn, options, async entry => {
|
||||
@@ -275,6 +277,7 @@ export async function readLdapOrg(
|
||||
client: LdapClient,
|
||||
userConfig: UserConfig[],
|
||||
groupConfig: GroupConfig[],
|
||||
vendorConfig: VendorConfig,
|
||||
options: {
|
||||
groupTransformer?: GroupTransformer;
|
||||
userTransformer?: UserTransformer;
|
||||
@@ -287,12 +290,18 @@ export async function readLdapOrg(
|
||||
// Invokes the above "raw" read functions and stitches together the results
|
||||
// with all relations etc filled in.
|
||||
|
||||
const { users, userMemberOf } = await readLdapUsers(client, userConfig, {
|
||||
transformer: options?.userTransformer,
|
||||
});
|
||||
const { users, userMemberOf } = await readLdapUsers(
|
||||
client,
|
||||
userConfig,
|
||||
vendorConfig,
|
||||
{
|
||||
transformer: options?.userTransformer,
|
||||
},
|
||||
);
|
||||
const { groups, groupMemberOf, groupMember } = await readLdapGroups(
|
||||
client,
|
||||
groupConfig,
|
||||
vendorConfig,
|
||||
{ transformer: options?.groupTransformer },
|
||||
);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { SearchEntry } from 'ldapjs';
|
||||
import { VendorConfig } from './config';
|
||||
|
||||
/**
|
||||
* An LDAP Vendor handles unique nuances between different vendors.
|
||||
@@ -39,48 +40,26 @@ export type LdapVendor = {
|
||||
decodeStringAttribute: (entry: SearchEntry, name: string) => string[];
|
||||
};
|
||||
|
||||
export const DefaultLdapVendor: LdapVendor = {
|
||||
dnAttributeName: 'entryDN',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
decodeStringAttribute: (entry, name) => {
|
||||
return decode(entry, name, value => {
|
||||
return value.toString();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const ActiveDirectoryVendor: LdapVendor = {
|
||||
dnAttributeName: 'distinguishedName',
|
||||
uuidAttributeName: 'objectGUID',
|
||||
decodeStringAttribute: (entry, name) => {
|
||||
const decoder = (value: string | Buffer) => {
|
||||
if (name === ActiveDirectoryVendor.uuidAttributeName) {
|
||||
return formatGUID(value);
|
||||
}
|
||||
return value.toString();
|
||||
};
|
||||
return decode(entry, name, decoder);
|
||||
},
|
||||
};
|
||||
|
||||
export const FreeIpaVendor: LdapVendor = {
|
||||
dnAttributeName: 'dn',
|
||||
uuidAttributeName: 'ipaUniqueID',
|
||||
decodeStringAttribute: (entry, name) => {
|
||||
return decode(entry, name, value => {
|
||||
return value.toString();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const AEDirVendor: LdapVendor = {
|
||||
dnAttributeName: 'dn',
|
||||
uuidAttributeName: 'entryUUID',
|
||||
decodeStringAttribute: (entry, name) => {
|
||||
return decode(entry, name, value => {
|
||||
return value.toString();
|
||||
});
|
||||
},
|
||||
export const CreateLdapVendor = (
|
||||
vendorConfig: VendorConfig,
|
||||
isActiveDirectoryVendor: boolean,
|
||||
): LdapVendor => {
|
||||
return {
|
||||
dnAttributeName: vendorConfig.dnAttributeName,
|
||||
uuidAttributeName: vendorConfig.uuidAttributeName,
|
||||
decodeStringAttribute: (entry, name) => {
|
||||
const decoder = (value: string | Buffer) => {
|
||||
if (
|
||||
isActiveDirectoryVendor &&
|
||||
name === vendorConfig.uuidAttributeName
|
||||
) {
|
||||
return formatGUID(value);
|
||||
}
|
||||
return value.toString();
|
||||
};
|
||||
return decode(entry, name, decoder);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Decode an attribute to a consumer
|
||||
|
||||
@@ -294,6 +294,7 @@ export class LdapOrgEntityProvider implements EntityProvider {
|
||||
client,
|
||||
this.options.provider.users,
|
||||
this.options.provider.groups,
|
||||
this.options.provider.vendor,
|
||||
{
|
||||
groupTransformer: this.options.groupTransformer,
|
||||
userTransformer: this.options.userTransformer,
|
||||
|
||||
@@ -109,6 +109,7 @@ export class LdapOrgReaderProcessor implements CatalogProcessor {
|
||||
client,
|
||||
provider.users,
|
||||
provider.groups,
|
||||
provider.vendor,
|
||||
{
|
||||
groupTransformer: this.groupTransformer,
|
||||
userTransformer: this.userTransformer,
|
||||
|
||||
Reference in New Issue
Block a user