@backstage/plugin-catalog-backend-module-ldap 0.9.0-next.2 → 0.9.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @backstage/plugin-catalog-backend-module-ldap
2
2
 
3
+ ## 0.9.1-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/backend-plugin-api@1.0.1-next.0
9
+ - @backstage/catalog-model@1.7.0
10
+ - @backstage/config@1.2.0
11
+ - @backstage/errors@1.2.4
12
+ - @backstage/types@1.1.1
13
+ - @backstage/plugin-catalog-common@1.1.0
14
+ - @backstage/plugin-catalog-node@1.13.1-next.0
15
+
16
+ ## 0.9.0
17
+
18
+ ### Minor Changes
19
+
20
+ - d425fc4: **BREAKING**: The return values from `createBackendPlugin`, `createBackendModule`, and `createServiceFactory` are now simply `BackendFeature` and `ServiceFactory`, instead of the previously deprecated form of a function that returns them. For this reason, `createServiceFactory` also no longer accepts the callback form where you provide direct options to the service. This also affects all `coreServices.*` service refs.
21
+
22
+ This may in particular affect tests; if you were effectively doing `createBackendModule({...})()` (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your `packages/backend/src/index.ts` too, where you add plugins, modules, and services. If you were using `createServiceFactory` with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
23
+
24
+ As part of this change, the `IdentityFactoryOptions` type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to [migrate to the new auth system](https://backstage.io/docs/tutorials/auth-service-migration) if you still rely on it.
25
+
26
+ ### Patch Changes
27
+
28
+ - b50e4a8: Add support for optional configuration of `dnAttributeName` and `uuidAttributeName` in LDAP vendor
29
+ - Updated dependencies
30
+ - @backstage/backend-plugin-api@1.0.0
31
+ - @backstage/catalog-model@1.7.0
32
+ - @backstage/plugin-catalog-common@1.1.0
33
+ - @backstage/plugin-catalog-node@1.13.0
34
+ - @backstage/config@1.2.0
35
+ - @backstage/errors@1.2.4
36
+ - @backstage/types@1.1.1
37
+
3
38
  ## 0.9.0-next.2
4
39
 
5
40
  ### Patch Changes
package/config.d.ts CHANGED
@@ -409,6 +409,20 @@ export interface Config {
409
409
  members?: string;
410
410
  };
411
411
  }>;
412
+ /**
413
+ * Configuration for overriding the vendor-specific default attribute names.
414
+ */
415
+ vendor?: {
416
+ /**
417
+ * Attribute name for the distinguished name (DN) of an entry,
418
+ */
419
+ dnAttributeName?: string;
420
+
421
+ /**
422
+ * Attribute name for the unique identifier (UUID) of an entry,
423
+ */
424
+ uuidAttributeName?: string;
425
+ };
412
426
  }>;
413
427
  };
414
428
 
@@ -638,6 +652,20 @@ export interface Config {
638
652
  members?: string;
639
653
  };
640
654
  };
655
+ /**
656
+ * Configuration for overriding the vendor-specific default attribute names.
657
+ */
658
+ vendor?: {
659
+ /**
660
+ * Attribute name for the distinguished name (DN) of an entry,
661
+ */
662
+ dnAttributeName?: string;
663
+
664
+ /**
665
+ * Attribute name for the unique identifier (UUID) of an entry,
666
+ */
667
+ uuidAttributeName?: string;
668
+ };
641
669
  };
642
670
  };
643
671
  };
@@ -865,6 +893,20 @@ export interface Config {
865
893
  members?: string;
866
894
  };
867
895
  };
896
+ /**
897
+ * Configuration for overriding the vendor-specific default attribute names.
898
+ */
899
+ vendor?: {
900
+ /**
901
+ * Attribute name for the distinguished name (DN) of an entry,
902
+ */
903
+ dnAttributeName?: string;
904
+
905
+ /**
906
+ * Attribute name for the unique identifier (UUID) of an entry,
907
+ */
908
+ uuidAttributeName?: string;
909
+ };
868
910
  }>;
869
911
  };
870
912
  };
package/dist/index.cjs.js CHANGED
@@ -372,6 +372,15 @@ function readBindConfig(c) {
372
372
  secret: c.getString("secret")
373
373
  };
374
374
  }
375
+ function readVendorConfig(c) {
376
+ if (!c) {
377
+ return void 0;
378
+ }
379
+ return {
380
+ dnAttributeName: c.getOptionalString("dnAttributeName"),
381
+ uuidAttributeName: c.getOptionalString("uuidAttributeName")
382
+ };
383
+ }
375
384
  function readOptionsConfig(c) {
376
385
  if (!c) {
377
386
  return {};
@@ -488,7 +497,8 @@ function readLdapLegacyConfig(config) {
488
497
  }),
489
498
  groups: readGroupConfig(c.getConfig("groups")).map((it) => {
490
499
  return mergeWith__default.default({}, defaultGroupConfig, it, replaceArraysIfPresent);
491
- })
500
+ }),
501
+ vendor: readVendorConfig(c.getOptionalConfig("vendor"))
492
502
  };
493
503
  return freeze(newConfig);
494
504
  });
@@ -520,7 +530,8 @@ function readProviderConfigs(config) {
520
530
  ).map((it) => {
521
531
  return mergeWith__default.default({}, defaultGroupConfig, it, replaceArraysIfPresent);
522
532
  }),
523
- schedule
533
+ schedule,
534
+ vendor: readVendorConfig(c.getOptionalConfig("vendor"))
524
535
  };
525
536
  return freeze(newConfig);
526
537
  });
@@ -601,15 +612,20 @@ async function defaultUserTransformer(vendor, config, entry) {
601
612
  });
602
613
  return entity;
603
614
  }
604
- async function readLdapUsers(client, config, opts) {
605
- if (config.length === 0) {
615
+ async function readLdapUsers(client, userConfig, vendorConfig, opts) {
616
+ if (userConfig.length === 0) {
606
617
  return { users: [], userMemberOf: /* @__PURE__ */ new Map() };
607
618
  }
608
619
  const entities = [];
609
620
  const userMemberOf = /* @__PURE__ */ new Map();
610
- const vendor = await client.getVendor();
621
+ const vendorDefaults = await client.getVendor();
622
+ const vendor = {
623
+ dnAttributeName: vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,
624
+ uuidAttributeName: vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,
625
+ decodeStringAttribute: vendorDefaults.decodeStringAttribute
626
+ };
611
627
  const transformer = opts?.transformer ?? defaultUserTransformer;
612
- for (const cfg of config) {
628
+ for (const cfg of userConfig) {
613
629
  const { dn, options, map } = cfg;
614
630
  await client.searchStreaming(dn, options, async (user) => {
615
631
  const entity = await transformer(vendor, cfg, user);
@@ -673,16 +689,21 @@ async function defaultGroupTransformer(vendor, config, entry) {
673
689
  });
674
690
  return entity;
675
691
  }
676
- async function readLdapGroups(client, config, opts) {
677
- if (config.length === 0) {
692
+ async function readLdapGroups(client, groupConfig, vendorConfig, opts) {
693
+ if (groupConfig.length === 0) {
678
694
  return { groups: [], groupMemberOf: /* @__PURE__ */ new Map(), groupMember: /* @__PURE__ */ new Map() };
679
695
  }
680
696
  const groups = [];
681
697
  const groupMemberOf = /* @__PURE__ */ new Map();
682
698
  const groupMember = /* @__PURE__ */ new Map();
683
- const vendor = await client.getVendor();
699
+ const vendorDefaults = await client.getVendor();
700
+ const vendor = {
701
+ dnAttributeName: vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,
702
+ uuidAttributeName: vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,
703
+ decodeStringAttribute: vendorDefaults.decodeStringAttribute
704
+ };
684
705
  const transformer = opts?.transformer ?? defaultGroupTransformer;
685
- for (const cfg of config) {
706
+ for (const cfg of groupConfig) {
686
707
  const { dn, map, options } = cfg;
687
708
  await client.searchStreaming(dn, options, async (entry) => {
688
709
  if (!entry) {
@@ -707,13 +728,19 @@ async function readLdapGroups(client, config, opts) {
707
728
  groupMember
708
729
  };
709
730
  }
710
- async function readLdapOrg(client, userConfig, groupConfig, options) {
711
- const { users, userMemberOf } = await readLdapUsers(client, userConfig, {
712
- transformer: options?.userTransformer
713
- });
731
+ async function readLdapOrg(client, userConfig, groupConfig, vendorConfig, options) {
732
+ const { users, userMemberOf } = await readLdapUsers(
733
+ client,
734
+ userConfig,
735
+ vendorConfig,
736
+ {
737
+ transformer: options?.userTransformer
738
+ }
739
+ );
714
740
  const { groups, groupMemberOf, groupMember } = await readLdapGroups(
715
741
  client,
716
742
  groupConfig,
743
+ vendorConfig,
717
744
  { transformer: options?.groupTransformer }
718
745
  );
719
746
  resolveRelations(groups, users, userMemberOf, groupMemberOf, groupMember);
@@ -939,6 +966,7 @@ class LdapOrgEntityProvider {
939
966
  client,
940
967
  this.options.provider.users,
941
968
  this.options.provider.groups,
969
+ this.options.provider.vendor,
942
970
  {
943
971
  groupTransformer: this.options.groupTransformer,
944
972
  userTransformer: this.options.userTransformer,
@@ -1055,6 +1083,7 @@ class LdapOrgReaderProcessor {
1055
1083
  client,
1056
1084
  provider.users,
1057
1085
  provider.groups,
1086
+ provider.vendor,
1058
1087
  {
1059
1088
  groupTransformer: this.groupTransformer,
1060
1089
  userTransformer: this.userTransformer,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/ldap/util.ts","../src/ldap/vendors.ts","../src/ldap/client.ts","../src/ldap/config.ts","../src/ldap/constants.ts","../src/ldap/org.ts","../src/ldap/read.ts","../src/processors/LdapOrgEntityProvider.ts","../src/processors/LdapOrgReaderProcessor.ts","../src/module.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Error as LDAPError, SearchEntry, SearchOptions } from 'ldapjs';\nimport { cloneDeep } from 'lodash';\nimport { LdapVendor } from './vendors';\n\n/**\n * Builds a string form of an LDAP Error structure.\n *\n * @param error - The error\n */\nexport function errorString(error: LDAPError) {\n return `${error.code} ${error.name}: ${error.message}`;\n}\n\n/**\n * Maps a single-valued attribute to a consumer.\n *\n * This helper can be useful when implementing a user or group transformer.\n *\n * @param entry - The LDAP source entry\n * @param vendor - The LDAP vendor\n * @param attributeName - The source attribute to map. If the attribute is\n * undefined the mapping will be silently ignored.\n * @param setter - The function to be called with the decoded attribute from the\n * source entry\n *\n * @public\n */\nexport function mapStringAttr(\n entry: SearchEntry,\n vendor: LdapVendor,\n attributeName: string | undefined,\n setter: (value: string) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n if (values && values.length === 1) {\n setter(values[0]);\n }\n }\n}\n\nexport function createOptions(inputOptions: SearchOptions): SearchOptions {\n const result = cloneDeep(inputOptions);\n\n if (result.paged === true) {\n result.paged = { pagePause: true };\n } else if (typeof result.paged === 'object') {\n result.paged.pagePause = true;\n }\n\n return result;\n}\n\nexport type RecursivePartial<T> = {\n [P in keyof T]?: T[P] extends (infer U)[]\n ? RecursivePartial<U>[]\n : T[P] extends object\n ? RecursivePartial<T[P]>\n : T[P];\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchEntry } from 'ldapjs';\n\n/**\n * An LDAP Vendor handles unique nuances between different vendors.\n *\n * @public\n */\nexport type LdapVendor = {\n /**\n * The attribute name that holds the distinguished name (DN) for an entry.\n */\n dnAttributeName: string;\n /**\n * The attribute name that holds a universal unique identifier for an entry.\n */\n uuidAttributeName: string;\n /**\n * Decode ldap entry values for a given attribute name to their string representation.\n *\n * @param entry - The ldap entry\n * @param name - The attribute to decode\n */\n decodeStringAttribute: (entry: SearchEntry, name: string) => string[];\n};\n\nexport const DefaultLdapVendor: LdapVendor = {\n dnAttributeName: 'entryDN',\n uuidAttributeName: 'entryUUID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const ActiveDirectoryVendor: LdapVendor = {\n dnAttributeName: 'distinguishedName',\n uuidAttributeName: 'objectGUID',\n decodeStringAttribute: (entry, name) => {\n const decoder = (value: string | Buffer) => {\n if (name === ActiveDirectoryVendor.uuidAttributeName) {\n return formatGUID(value);\n }\n return value.toString();\n };\n return decode(entry, name, decoder);\n },\n};\n\nexport const FreeIpaVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'ipaUniqueID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const AEDirVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'entryUUID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\n// Decode an attribute to a consumer\nfunction decode(\n entry: SearchEntry,\n attributeName: string,\n decoder: (value: string | Buffer) => string,\n): string[] {\n const values = entry.raw[attributeName];\n if (Array.isArray(values)) {\n return values.map(v => {\n return decoder(v);\n });\n } else if (values) {\n return [decoder(values)];\n }\n return [];\n}\n\n// Formats a Microsoft Active Directory binary-encoded uuid to a readable string\n// See https://github.com/ldapjs/node-ldapjs/issues/297#issuecomment-137765214\nfunction formatGUID(objectGUID: string | Buffer): string {\n let data: Buffer;\n if (typeof objectGUID === 'string') {\n data = Buffer.from(objectGUID, 'binary');\n } else {\n data = objectGUID;\n }\n // GUID_FORMAT_D\n let template = '{3}{2}{1}{0}-{5}{4}-{7}{6}-{8}{9}-{10}{11}{12}{13}{14}{15}';\n\n // check each byte\n for (let i = 0; i < data.length; i++) {\n let dataStr = data[i].toString(16);\n dataStr = data[i] >= 16 ? dataStr : `0${dataStr}`;\n\n // insert that character into the template\n template = template.replace(`{${i}}`, dataStr);\n }\n return template;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardedError, stringifyError } from '@backstage/errors';\nimport { readFile } from 'fs/promises';\nimport ldap, { Client, SearchEntry, SearchOptions } from 'ldapjs';\nimport { cloneDeep } from 'lodash';\nimport tlsLib from 'tls';\nimport { BindConfig, TLSConfig } from './config';\nimport { createOptions, errorString } from './util';\nimport {\n AEDirVendor,\n ActiveDirectoryVendor,\n DefaultLdapVendor,\n FreeIpaVendor,\n LdapVendor,\n} from './vendors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Basic wrapper for the `ldapjs` library.\n *\n * Helps out with promisifying calls, paging, binding etc.\n *\n * @public\n */\nexport class LdapClient {\n private vendor: Promise<LdapVendor> | undefined;\n\n static async create(\n logger: LoggerService,\n target: string,\n bind?: BindConfig,\n tls?: TLSConfig,\n ): Promise<LdapClient> {\n let secureContext;\n if (tls && tls.certs && tls.keys) {\n const cert = await readFile(tls.certs, 'utf-8');\n const key = await readFile(tls.keys, 'utf-8');\n secureContext = tlsLib.createSecureContext({\n cert: cert,\n key: key,\n });\n }\n\n const client = ldap.createClient({\n url: target,\n tlsOptions: {\n secureContext,\n rejectUnauthorized: tls?.rejectUnauthorized,\n },\n });\n\n // We want to have a catch-all error handler at the top, since the default\n // behavior of the client is to blow up the entire process when it fails,\n // unless an error handler is set.\n client.on('error', (err: ldap.Error) => {\n logger.warn(`LDAP client threw an error, ${errorString(err)}`);\n });\n\n if (!bind) {\n return new LdapClient(client, logger);\n }\n\n return new Promise<LdapClient>((resolve, reject) => {\n const { dn, secret } = bind;\n client.bind(dn, secret, err => {\n if (err) {\n reject(`LDAP bind failed for ${dn}, ${errorString(err)}`);\n } else {\n resolve(new LdapClient(client, logger));\n }\n });\n });\n }\n\n constructor(\n private readonly client: Client,\n private readonly logger: LoggerService,\n ) {}\n\n /**\n * Performs an LDAP search operation.\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n */\n async search(dn: string, options: SearchOptions): Promise<SearchEntry[]> {\n try {\n const output: SearchEntry[] = [];\n\n const logInterval = setInterval(() => {\n this.logger.debug(`Read ${output.length} LDAP entries so far...`);\n }, 5000);\n\n const search = new Promise<SearchEntry[]>((resolve, reject) => {\n // Note that we clone the (frozen) options, since ldapjs rudely tries to\n // overwrite parts of them\n this.client.search(dn, cloneDeep(options), (err, res) => {\n if (err) {\n reject(new Error(errorString(err)));\n return;\n }\n\n res.on('searchReference', () => {\n this.logger.warn('Received unsupported search referral');\n });\n\n res.on('searchEntry', entry => {\n output.push(entry);\n });\n\n res.on('error', e => {\n reject(new Error(errorString(e)));\n });\n\n res.on('page', (_result, cb) => {\n if (cb) {\n cb();\n }\n });\n\n res.on('end', r => {\n if (!r) {\n reject(new Error('Null response'));\n } else if (r.status !== 0) {\n reject(new Error(`Got status ${r.status}: ${r.errorMessage}`));\n } else {\n resolve(output);\n }\n });\n });\n });\n\n return await search.finally(() => {\n clearInterval(logInterval);\n });\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Performs an LDAP search operation, calls a function on each entry to limit memory usage\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n * @param f - The callback to call on each search entry\n */\n async searchStreaming(\n dn: string,\n options: SearchOptions,\n f: (entry: SearchEntry) => Promise<void> | void,\n ): Promise<void> {\n try {\n return await new Promise<void>((resolve, reject) => {\n // Note that we clone the (frozen) options, since ldapjs rudely tries to\n // overwrite parts of them\n this.client.search(dn, createOptions(options), (err, res) => {\n if (err) {\n reject(new Error(errorString(err)));\n }\n let awaitList: Array<Promise<void> | void> = [];\n let transformError = false;\n\n const transformReject = (e: Error) => {\n transformError = true;\n reject(\n new Error(\n `Transform function threw an exception, ${stringifyError(e)}`,\n ),\n );\n };\n\n res.on('searchReference', () => {\n this.logger.warn('Received unsupported search referral');\n });\n\n res.on('searchEntry', entry => {\n if (!transformError) awaitList.push(f(entry));\n });\n\n res.on('page', (_, cb) => {\n // awaits completion before fetching next page\n Promise.all(awaitList)\n .then(() => {\n // flush list\n awaitList = [];\n if (cb) cb();\n })\n .catch(transformReject);\n });\n\n res.on('error', e => {\n reject(new Error(errorString(e)));\n });\n\n res.on('end', r => {\n if (!r) {\n throw new Error('Null response');\n } else if (r.status !== 0) {\n throw new Error(`Got status ${r.status}: ${r.errorMessage}`);\n } else {\n Promise.all(awaitList)\n .then(() => resolve())\n .catch(transformReject);\n }\n });\n });\n });\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Get the Server Vendor.\n * Currently only detects Microsoft Active Directory Servers.\n *\n * @see https://ldapwiki.com/wiki/Determine%20LDAP%20Server%20Vendor\n */\n async getVendor(): Promise<LdapVendor> {\n if (this.vendor) {\n return this.vendor;\n }\n this.vendor = this.getRootDSE()\n .then(root => {\n if (root && root.raw?.forestFunctionality) {\n return ActiveDirectoryVendor;\n } else if (root && root.raw?.ipaDomainLevel) {\n return FreeIpaVendor;\n } else if (root && 'aeRoot' in root.raw) {\n return AEDirVendor;\n }\n return DefaultLdapVendor;\n })\n .catch(err => {\n this.vendor = undefined;\n throw err;\n });\n return this.vendor;\n }\n\n /**\n * Get the Root DSE.\n *\n * @see https://ldapwiki.com/wiki/RootDSE\n */\n async getRootDSE(): Promise<SearchEntry | undefined> {\n const result = await this.search('', {\n scope: 'base',\n filter: '(objectclass=*)',\n } as SearchOptions);\n if (result && result.length === 1) {\n return result[0];\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SchedulerServiceTaskScheduleDefinition,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { SearchOptions } from 'ldapjs';\nimport mergeWith from 'lodash/mergeWith';\nimport { trimEnd } from 'lodash';\nimport { RecursivePartial } from './util';\n\n/**\n * The configuration parameters for a single LDAP provider.\n *\n * @public\n */\nexport type LdapProviderConfig = {\n // The id of the\n id: string;\n // The prefix of the target that this matches on, e.g.\n // \"ldaps://ds.example.net\", with no trailing slash.\n target: string;\n // TLS settings\n tls?: TLSConfig;\n // The settings to use for the bind command. If none are specified, the bind\n // command is not issued.\n bind?: BindConfig;\n // The settings that govern the reading and interpretation of users\n users: UserConfig[];\n // The settings that govern the reading and interpretation of groups\n groups: GroupConfig[];\n // Schedule configuration for refresh tasks.\n schedule?: SchedulerServiceTaskScheduleDefinition;\n};\n\n/**\n * TLS settings\n *\n * @public\n */\nexport type TLSConfig = {\n // Node TLS rejectUnauthorized\n rejectUnauthorized?: boolean;\n // A file containing private keys in PEM format\n keys?: string;\n // A file containing cert chains in PEM format\n certs?: string;\n};\n\n/**\n * The settings to use for the a command.\n *\n * @public\n */\nexport type BindConfig = {\n // The DN of the user to auth as, e.g.\n // uid=ldap-robot,ou=robots,ou=example,dc=example,dc=net\n dn: string;\n // The secret of the user to auth as (its password)\n secret: string;\n};\n\n/**\n * The settings that govern the reading and interpretation of users.\n *\n * @public\n */\nexport type UserConfig = {\n // The DN under which users are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported. The\n // default is scope \"one\" and attributes \"*\" and \"+\".\n options: SearchOptions;\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"uid\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"uid\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity.\n description?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity. Defaults to \"mail\".\n email: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.memberOf field of the entity. Defaults to \"memberOf\".\n memberOf: string;\n };\n};\n\n/**\n * The settings that govern the reading and interpretation of groups.\n *\n * @public\n */\nexport type GroupConfig = {\n // The DN under which groups are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported.\n options: SearchOptions;\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"cn\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"cn\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity. Defaults to \"description\".\n description: string;\n // The name of the attribute that shall be used for the value of the\n // spec.type field of the entity. Defaults to \"groupType\".\n type: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity.\n email?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.parent field of the entity. Defaults to \"memberOf\".\n memberOf: string;\n // The name of the attribute that shall be used for the values of the\n // spec.children field of the entity. Defaults to \"member\".\n members: string;\n };\n};\n\nconst defaultUserConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'uid',\n name: 'uid',\n displayName: 'cn',\n email: 'mail',\n memberOf: 'memberOf',\n },\n};\n\nconst defaultGroupConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'cn',\n name: 'cn',\n description: 'description',\n displayName: 'cn',\n type: 'groupType',\n memberOf: 'memberOf',\n members: 'member',\n },\n};\n\nfunction freeze<T>(data: T): T {\n return JSON.parse(JSON.stringify(data), (_key, value) => {\n if (typeof value === 'object' && value !== null) {\n Object.freeze(value);\n }\n return value;\n });\n}\n\nfunction readTlsConfig(\n c: Config | undefined,\n): LdapProviderConfig['tls'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n rejectUnauthorized: c.getOptionalBoolean('rejectUnauthorized'),\n keys: c.getOptionalString('keys'),\n certs: c.getOptionalString('certs'),\n };\n}\n\nfunction readBindConfig(\n c: Config | undefined,\n): LdapProviderConfig['bind'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dn: c.getString('dn'),\n secret: c.getString('secret'),\n };\n}\n\nfunction readOptionsConfig(c: Config | undefined): SearchOptions {\n if (!c) {\n return {};\n }\n\n const paged = readOptionsPagedConfig(c);\n\n return {\n scope: c.getOptionalString('scope') as SearchOptions['scope'],\n filter: formatFilter(c.getOptionalString('filter')),\n attributes: c.getOptionalStringArray('attributes'),\n sizeLimit: c.getOptionalNumber('sizeLimit'),\n timeLimit: c.getOptionalNumber('timeLimit'),\n derefAliases: c.getOptionalNumber('derefAliases'),\n typesOnly: c.getOptionalBoolean('typesOnly'),\n ...(paged !== undefined ? { paged } : undefined),\n };\n}\n\nfunction readOptionsPagedConfig(c: Config): SearchOptions['paged'] {\n const pagedConfig = c.getOptional('paged');\n if (pagedConfig === undefined) {\n return undefined;\n }\n\n if (pagedConfig === true || pagedConfig === false) {\n return pagedConfig;\n }\n\n const pageSize = c.getOptionalNumber('paged.pageSize');\n const pagePause = c.getOptionalBoolean('paged.pagePause');\n return {\n ...(pageSize !== undefined ? { pageSize } : undefined),\n ...(pagePause !== undefined ? { pagePause } : undefined),\n };\n}\n\nfunction readSetConfig(\n c: Config | undefined,\n): { [path: string]: JsonValue } | undefined {\n if (!c) {\n return undefined;\n }\n return c.get();\n}\n\nfunction readUserMapConfig(c: Config | undefined): Partial<UserConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n };\n}\n\nfunction readGroupMapConfig(\n c: Config | undefined,\n): Partial<GroupConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n type: c.getOptionalString('type'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n members: c.getOptionalString('members'),\n };\n}\n\nfunction readUserConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['users']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleUserConfig(it));\n }\n return [readSingleUserConfig(c)];\n}\n\nfunction readSingleUserConfig(c: Config): RecursivePartial<UserConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readUserMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction readGroupConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['groups']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleGroupConfig(it));\n }\n return [readSingleGroupConfig(c)];\n}\n\nfunction readSingleGroupConfig(c: Config): RecursivePartial<GroupConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readGroupMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction formatFilter(filter?: string): string | undefined {\n // Remove extra whitespace between blocks to support multiline filters from the configuration\n return filter?.replace(/\\s*(\\(|\\))/g, '$1')?.trim();\n}\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n * @deprecated This exists for backwards compatibility only and will be removed in the future.\n */\nexport function readLdapLegacyConfig(config: Config): LdapProviderConfig[] {\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n return providerConfigs.map(c => {\n const newConfig = {\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(c.getConfig('users')).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(c.getConfig('groups')).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\n/**\n * Parses all configured providers.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n */\nexport function readProviderConfigs(config: Config): LdapProviderConfig[] {\n const providersConfig = config.getOptionalConfig('catalog.providers.ldapOrg');\n if (!providersConfig) {\n return [];\n }\n\n return providersConfig.keys().map(id => {\n const c = providersConfig.getConfig(id);\n\n const schedule = c.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n c.getConfig('schedule'),\n )\n : undefined;\n\n const isUserList = Array.isArray(c.getOptional('users'));\n const isGroupList = Array.isArray(c.getOptional('groups'));\n\n const newConfig = {\n id,\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(\n isUserList\n ? c.getOptionalConfigArray('users')\n : c.getOptionalConfig('users'),\n ).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(\n isGroupList\n ? c.getOptionalConfigArray('groups')\n : c.getOptionalConfig('groups'),\n ).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n schedule,\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\nfunction replaceArraysIfPresent(_into: any, from: any) {\n // Replace arrays instead of merging, otherwise default behavior\n return Array.isArray(from) ? from : undefined;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The name of an entity annotation, that references the RDN of the LDAP object\n * it was ingested from.\n *\n * The RDN is the name of the leftmost attribute that identifies the item; for\n * example, for an item with the fully qualified DN\n * uid=john,ou=people,ou=spotify,dc=spotify,dc=net the generated entity would\n * have this annotation, with the value \"john\".\n *\n * @public\n */\nexport const LDAP_RDN_ANNOTATION = 'backstage.io/ldap-rdn';\n\n/**\n * The name of an entity annotation, that references the DN of the LDAP object\n * it was ingested from.\n *\n * The DN is the fully qualified name that identifies the item; for example,\n * for an item with the DN uid=john,ou=people,ou=spotify,dc=spotify,dc=net the\n * generated entity would have this annotation, with that full string as its\n * value.\n *\n * @public\n */\nexport const LDAP_DN_ANNOTATION = 'backstage.io/ldap-dn';\n\n/**\n * The name of an entity annotation, that references the UUID of the LDAP\n * object it was ingested from.\n *\n * The UUID is the globally unique ID that identifies the item; for example,\n * for an item with the UUID 76ef928a-b251-1037-9840-d78227f36a7e, the\n * generated entity would have this annotation, with that full string as its\n * value.\n *\n * @public\n */\nexport const LDAP_UUID_ANNOTATION = 'backstage.io/ldap-uuid';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\n\n// TODO: Copied from plugin-catalog-backend, but we could also export them from\n// there. Or move them to catalog-model.\n\nexport function buildOrgHierarchy(groups: GroupEntity[]) {\n const groupsByRef = new Map(groups.map(g => [stringifyEntityRef(g), g]));\n\n //\n // Make sure that g.parent.children contain g\n //\n\n for (const group of groups) {\n const selfRef = stringifyEntityRef(group);\n const parentRef = group.spec.parent;\n if (parentRef) {\n const parent = groupsByRef.get(parentRef);\n if (parent && !parent.spec.children.includes(selfRef)) {\n parent.spec.children.push(selfRef);\n }\n }\n }\n\n //\n // Make sure that g.children.parent is g\n //\n\n for (const group of groups) {\n const selfRef = stringifyEntityRef(group);\n for (const childRef of group.spec.children) {\n const child = groupsByRef.get(childRef);\n if (child && !child.spec.parent) {\n child.spec.parent = selfRef;\n }\n }\n }\n}\n\n// Ensure that users have their transitive group memberships. Requires that\n// the groups were previously processed with buildOrgHierarchy()\nexport function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) {\n const groupsByRef = new Map(groups.map(g => [stringifyEntityRef(g), g]));\n\n users.forEach(user => {\n const transitiveMemberOf = new Set<string>();\n\n const todo = [\n ...(user.spec.memberOf ?? []),\n ...groups\n .filter(g => g.spec.members?.includes(stringifyEntityRef(user)))\n .map(g => stringifyEntityRef(g)),\n ];\n\n for (;;) {\n const current = todo.pop();\n if (!current) {\n break;\n }\n\n if (!transitiveMemberOf.has(current)) {\n transitiveMemberOf.add(current);\n const group = groupsByRef.get(current);\n if (group?.spec.parent) {\n todo.push(group.spec.parent);\n }\n }\n }\n\n user.spec.memberOf = [...transitiveMemberOf];\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { SearchEntry } from 'ldapjs';\nimport lodashSet from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport { buildOrgHierarchy } from './org';\nimport { LdapClient } from './client';\nimport { GroupConfig, UserConfig } from './config';\nimport {\n LDAP_DN_ANNOTATION,\n LDAP_RDN_ANNOTATION,\n LDAP_UUID_ANNOTATION,\n} from './constants';\nimport { LdapVendor } from './vendors';\nimport { GroupTransformer, UserTransformer } from './types';\nimport { mapStringAttr } from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n vendor: LdapVendor,\n config: UserConfig,\n entry: SearchEntry,\n): Promise<UserEntity | undefined> {\n const { set, map } = config;\n\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'User',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n profile: {},\n memberOf: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads users out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The user data configuration\n * @param opts - Additional options\n */\nexport async function readLdapUsers(\n client: LdapClient,\n config: UserConfig[],\n opts?: { transformer?: UserTransformer },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n userMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n}> {\n if (config.length === 0) {\n return { users: [], userMemberOf: new Map() };\n }\n const entities: UserEntity[] = [];\n const userMemberOf: Map<string, Set<string>> = new Map();\n\n const vendor = await client.getVendor();\n const transformer = opts?.transformer ?? defaultUserTransformer;\n\n for (const cfg of config) {\n const { dn, options, map } = cfg;\n await client.searchStreaming(dn, options, async user => {\n const entity = await transformer(vendor, cfg, user);\n\n if (!entity) {\n return;\n }\n\n mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(userMemberOf, myDn, vs);\n });\n entities.push(entity);\n });\n }\n\n return { users: entities, userMemberOf };\n}\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n vendor: LdapVendor,\n config: GroupConfig,\n entry: SearchEntry,\n): Promise<GroupEntity | undefined> {\n const { set, map } = config;\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'Group',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n type: 'unknown',\n profile: {},\n children: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.type, v => {\n entity.spec.type = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The group data configuration\n * @param opts - Additional options\n */\nexport async function readLdapGroups(\n client: LdapClient,\n config: GroupConfig[],\n opts?: {\n transformer?: GroupTransformer;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n groupMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n groupMember: Map<string, Set<string>>; // DN -> DN or UUID of groups & users\n}> {\n if (config.length === 0) {\n return { groups: [], groupMemberOf: new Map(), groupMember: new Map() };\n }\n const groups: GroupEntity[] = [];\n const groupMemberOf: Map<string, Set<string>> = new Map();\n const groupMember: Map<string, Set<string>> = new Map();\n\n const vendor = await client.getVendor();\n const transformer = opts?.transformer ?? defaultGroupTransformer;\n\n for (const cfg of config) {\n const { dn, map, options } = cfg;\n\n await client.searchStreaming(dn, options, async entry => {\n if (!entry) {\n return;\n }\n\n const entity = await transformer(vendor, cfg, entry);\n\n if (!entity) {\n return;\n }\n\n mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(groupMemberOf, myDn, vs);\n });\n mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => {\n ensureItems(groupMember, myDn, vs);\n });\n\n groups.push(entity);\n });\n }\n\n return {\n groups,\n groupMemberOf,\n groupMember,\n };\n}\n\n/**\n * Reads users and groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param userConfig - The user data configuration\n * @param groupConfig - The group data configuration\n * @param options - Additional options\n *\n * @public\n */\nexport async function readLdapOrg(\n client: LdapClient,\n userConfig: UserConfig[],\n groupConfig: GroupConfig[],\n options: {\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[];\n groups: GroupEntity[];\n}> {\n // Invokes the above \"raw\" read functions and stitches together the results\n // with all relations etc filled in.\n\n const { users, userMemberOf } = await readLdapUsers(client, userConfig, {\n transformer: options?.userTransformer,\n });\n const { groups, groupMemberOf, groupMember } = await readLdapGroups(\n client,\n groupConfig,\n { transformer: options?.groupTransformer },\n );\n\n resolveRelations(groups, users, userMemberOf, groupMemberOf, groupMember);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\n//\n// Helpers\n//\n\n// Maps a multi-valued attribute of references to other objects, to a consumer\nfunction mapReferencesAttr(\n entry: SearchEntry,\n vendor: LdapVendor,\n attributeName: string | undefined,\n setter: (sourceDn: string, targets: string[]) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n const dn = vendor.decodeStringAttribute(entry, vendor.dnAttributeName);\n if (values && dn && dn.length === 1) {\n setter(dn[0], values);\n }\n }\n}\n\n// Inserts a number of values in a key-values mapping\nfunction ensureItems(\n target: Map<string, Set<string>>,\n key: string,\n values: string[],\n) {\n if (key) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n for (const value of values) {\n if (value) {\n set!.add(value);\n }\n }\n }\n}\n\n/**\n * Takes groups and entities with empty relations, and fills in the various\n * relations that were returned by the readers, and forms the org hierarchy.\n *\n * @param groups - Group entities with empty relations; modified in place\n * @param users - User entities with empty relations; modified in place\n * @param userMemberOf - For a user DN, the set of group DNs or UUIDs that the\n * user is a member of\n * @param groupMemberOf - For a group DN, the set of group DNs or UUIDs that\n * the group is a member of (parents in the hierarchy)\n * @param groupMember - For a group DN, the set of group DNs or UUIDs that are\n * members of the group (children in the hierarchy)\n */\nexport function resolveRelations(\n groups: GroupEntity[],\n users: UserEntity[],\n userMemberOf: Map<string, Set<string>>,\n groupMemberOf: Map<string, Set<string>>,\n groupMember: Map<string, Set<string>>,\n) {\n // Build reference lookup tables - all of the relations that are output from\n // the above calls can be expressed as either DNs or UUIDs so we need to be\n // able to find by both, as well as the entity reference. Note that we expect them to not\n // collide here - this is a reasonable assumption as long as the fields are\n // the supported forms.\n const userMap: Map<string, UserEntity> = new Map(); // by entityRef, dn, uuid\n const groupMap: Map<string, GroupEntity> = new Map(); // by entityRef, dn, uuid\n for (const user of users) {\n userMap.set(stringifyEntityRef(user), user);\n userMap.set(user.metadata.annotations![LDAP_DN_ANNOTATION], user);\n userMap.set(user.metadata.annotations![LDAP_RDN_ANNOTATION], user);\n userMap.set(user.metadata.annotations![LDAP_UUID_ANNOTATION], user);\n }\n for (const group of groups) {\n groupMap.set(stringifyEntityRef(group), group);\n groupMap.set(group.metadata.annotations![LDAP_DN_ANNOTATION], group);\n groupMap.set(group.metadata.annotations![LDAP_RDN_ANNOTATION], group);\n groupMap.set(group.metadata.annotations![LDAP_UUID_ANNOTATION], group);\n }\n\n // This can happen e.g. if entryUUID wasn't returned by the server\n userMap.delete('');\n groupMap.delete('');\n userMap.delete(undefined!);\n groupMap.delete(undefined!);\n\n // Fill in all of the immediate relations, now keyed on the entity reference. We\n // keep all parents at this point, whether the target model can support more\n // than one or not (it gets filtered farther down). And group children are\n // only groups in here.\n const newUserMemberOf: Map<string, Set<string>> = new Map();\n const newGroupParents: Map<string, Set<string>> = new Map();\n const newGroupChildren: Map<string, Set<string>> = new Map();\n\n // Resolve and store in the intermediaries. It may seem redundant that the\n // input data has both parent and children directions, as well as both\n // user->group and group->user - the reason is that different LDAP schemas\n // express relations in different directions. Some may have a user memberOf\n // overlay, some don't, for example.\n for (const [userN, groupsN] of userMemberOf.entries()) {\n const user = userMap.get(userN);\n if (user) {\n for (const groupN of groupsN) {\n const group = groupMap.get(groupN);\n if (group) {\n ensureItems(newUserMemberOf, stringifyEntityRef(user), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, parentsN] of groupMemberOf.entries()) {\n const group = groupMap.get(groupN);\n if (group) {\n for (const parentN of parentsN) {\n const parentGroup = groupMap.get(parentN);\n if (parentGroup) {\n ensureItems(newGroupParents, stringifyEntityRef(group), [\n stringifyEntityRef(parentGroup),\n ]);\n ensureItems(newGroupChildren, stringifyEntityRef(parentGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, membersN] of groupMember.entries()) {\n const group = groupMap.get(groupN);\n if (group) {\n for (const memberN of membersN) {\n // Group members can be both users and groups in the input model, so\n // try both\n const memberUser = userMap.get(memberN);\n if (memberUser) {\n ensureItems(newUserMemberOf, stringifyEntityRef(memberUser), [\n stringifyEntityRef(group),\n ]);\n } else {\n const memberGroup = groupMap.get(memberN);\n if (memberGroup) {\n ensureItems(newGroupChildren, stringifyEntityRef(group), [\n stringifyEntityRef(memberGroup),\n ]);\n ensureItems(newGroupParents, stringifyEntityRef(memberGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n }\n\n // Write down the relations again into the actual entities\n for (const [userN, groupsN] of newUserMemberOf.entries()) {\n const user = userMap.get(userN);\n if (user) {\n user.spec.memberOf = Array.from(groupsN).sort();\n }\n }\n for (const [groupN, parentsN] of newGroupParents.entries()) {\n if (parentsN.size === 1) {\n const group = groupMap.get(groupN);\n if (group) {\n group.spec.parent = parentsN.values().next().value;\n }\n }\n }\n for (const [groupN, childrenN] of newGroupChildren.entries()) {\n const group = groupMap.get(groupN);\n if (group) {\n group.spec.children = Array.from(childrenN).sort();\n }\n }\n\n // Fill out the rest of the hierarchy\n buildOrgHierarchy(groups);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport {\n GroupTransformer,\n LdapClient,\n LdapProviderConfig,\n LDAP_DN_ANNOTATION,\n readLdapOrg,\n UserTransformer,\n} from '../ldap';\nimport {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport { readLdapLegacyConfig, readProviderConfigs } from '../ldap';\n\n/**\n * Options for {@link LdapOrgEntityProvider}.\n *\n * @public\n */\nexport type LdapOrgEntityProviderOptions =\n | LdapOrgEntityProviderLegacyOptions\n | {\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: SchedulerService;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n userTransformer?: UserTransformer | Record<string, UserTransformer>;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n groupTransformer?: GroupTransformer | Record<string, GroupTransformer>;\n };\n\n/**\n * Options for {@link LdapOrgEntityProvider}.\n *\n * @public\n * @deprecated This interface exists for backwards compatibility only and will be removed in the future.\n */\nexport interface LdapOrgEntityProviderLegacyOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The target that this provider should consume.\n *\n * Should exactly match the \"target\" field of one of the \"ldap.providers\"\n * configuration entries.\n *\n * @example \"ldaps://ds-read.example.net\"\n */\n target: string;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * The function that transforms a user entry in LDAP to an entity.\n */\n userTransformer?: UserTransformer;\n\n /**\n * The function that transforms a group entry in LDAP to an entity.\n */\n groupTransformer?: GroupTransformer;\n}\n\n/**\n * Reads user and group entries out of an LDAP service, and provides them as\n * User and Group entities for the catalog.\n *\n * @remarks\n *\n * Add an instance of this class to your catalog builder, and then periodically\n * call the {@link LdapOrgEntityProvider.read} method.\n *\n * @public\n */\nexport class LdapOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private scheduleFn?: () => Promise<void>;\n\n static fromConfig(\n configRoot: Config,\n options: LdapOrgEntityProviderOptions,\n ): LdapOrgEntityProvider[] {\n if ('id' in options) {\n return [LdapOrgEntityProvider.fromLegacyConfig(configRoot, options)];\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n function getTransformer<T extends Function>(\n id: string,\n transformers?: T | Record<string, T>,\n ): T | undefined {\n if (['undefined', 'function'].includes(typeof transformers)) {\n return transformers as T;\n }\n\n return (transformers as Record<string, T>)[id];\n }\n\n return readProviderConfigs(configRoot).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for LdapOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n const provider = new LdapOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: options.logger,\n userTransformer: getTransformer(\n providerConfig.id,\n options.userTransformer,\n ),\n groupTransformer: getTransformer(\n providerConfig.id,\n options.groupTransformer,\n ),\n });\n\n if (taskRunner !== 'manual') {\n provider.schedule(taskRunner);\n }\n\n return provider;\n });\n }\n\n static fromLegacyConfig(\n configRoot: Config,\n options: LdapOrgEntityProviderLegacyOptions,\n ): LdapOrgEntityProvider {\n // TODO(freben): Deprecate the old catalog.processors.ldapOrg config\n const config =\n configRoot.getOptionalConfig('ldap') ||\n configRoot.getOptionalConfig('catalog.processors.ldapOrg');\n const providers = config ? readLdapLegacyConfig(config) : [];\n const provider = providers.find(p => options.target === p.target);\n if (!provider) {\n throw new TypeError(\n `There is no LDAP configuration that matches \"${options.target}\". Please add a configuration entry for it under \"ldap.providers\".`,\n );\n }\n\n const logger = options.logger.child({\n target: options.target,\n });\n\n const result = new LdapOrgEntityProvider({\n id: options.id,\n provider,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n logger,\n });\n\n if (options.schedule !== 'manual') {\n result.schedule(options.schedule);\n }\n\n return result;\n }\n\n constructor(\n private options: {\n id: string;\n provider: LdapProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n },\n ) {}\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName() {\n return `LdapOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one single complete ingestion. This is only necessary if you use\n * manual scheduling.\n */\n async read(options?: { logger?: LoggerService }) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const { markReadComplete } = trackProgress(logger);\n\n // Be lazy and create the client each time; even though it's pretty\n // inefficient, we usually only do this once per entire refresh loop and\n // don't have to worry about timeouts and reconnects etc.\n const client = await LdapClient.create(\n this.options.logger,\n this.options.provider.target,\n this.options.provider.bind,\n this.options.provider.tls,\n );\n\n const { users, groups } = await readLdapOrg(\n client,\n this.options.provider.users,\n this.options.provider.groups,\n {\n groupTransformer: this.options.groupTransformer,\n userTransformer: this.options.userTransformer,\n logger,\n },\n );\n\n const { markCommitComplete } = markReadComplete({ users, groups });\n\n await this.connection.applyMutation({\n type: 'full',\n entities: [...users, ...groups].map(entity => ({\n locationKey: `ldap-org-provider:${this.options.id}`,\n entity: withLocations(this.options.id, entity),\n })),\n });\n\n markCommitComplete();\n }\n\n private schedule(taskRunner: SchedulerServiceTaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async () => {\n const logger = this.options.logger.child({\n class: LdapOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.read({ logger });\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: LoggerService) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading LDAP users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\n summary = `${read.users.length} LDAP users and ${read.groups.length} LDAP groups`;\n const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n timestamp = Date.now();\n logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`);\n return { markCommitComplete };\n }\n\n function markCommitComplete() {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`);\n }\n\n return { markReadComplete };\n}\n\n// Makes sure that emitted entities have a proper location based on their DN\nfunction withLocations(providerId: string, entity: Entity): Entity {\n const dn =\n entity.metadata.annotations?.[LDAP_DN_ANNOTATION] || entity.metadata.name;\n const location = `ldap://${providerId}/${encodeURIComponent(dn)}`;\n return merge(\n {\n metadata: {\n annotations: {\n [ANNOTATION_LOCATION]: location,\n [ANNOTATION_ORIGIN_LOCATION]: location,\n },\n },\n },\n entity,\n ) as Entity;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n GroupTransformer,\n LdapClient,\n LdapProviderConfig,\n readLdapLegacyConfig,\n readLdapOrg,\n UserTransformer,\n} from '../ldap';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Extracts teams and users out of an LDAP server.\n *\n * @public\n */\nexport class LdapOrgReaderProcessor implements CatalogProcessor {\n private readonly providers: LdapProviderConfig[];\n private readonly logger: LoggerService;\n private readonly groupTransformer?: GroupTransformer;\n private readonly userTransformer?: UserTransformer;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n },\n ) {\n // TODO(freben): Deprecate the old catalog.processors.ldapOrg config\n const config =\n configRoot.getOptionalConfig('ldap') ||\n configRoot.getOptionalConfig('catalog.processors.ldapOrg');\n return new LdapOrgReaderProcessor({\n ...options,\n providers: config ? readLdapLegacyConfig(config) : [],\n });\n }\n\n constructor(options: {\n providers: LdapProviderConfig[];\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n }) {\n this.providers = options.providers;\n this.logger = options.logger;\n this.groupTransformer = options.groupTransformer;\n this.userTransformer = options.userTransformer;\n }\n\n getProcessorName(): string {\n return 'LdapOrgReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'ldap-org') {\n return false;\n }\n\n const provider = this.providers.find(p => location.target === p.target);\n if (!provider) {\n throw new Error(\n `There is no LDAP configuration that matches \"${location.target}\". Please add a configuration entry for it under \"ldap.providers\".`,\n );\n }\n\n // Read out all of the raw data\n const startTimestamp = Date.now();\n this.logger.info('Reading LDAP users and groups');\n\n // Be lazy and create the client each time; even though it's pretty\n // inefficient, we usually only do this once per entire refresh loop and\n // don't have to worry about timeouts and reconnects etc.\n const client = await LdapClient.create(\n this.logger,\n provider.target,\n provider.bind,\n provider.tls,\n );\n const { users, groups } = await readLdapOrg(\n client,\n provider.users,\n provider.groups,\n {\n groupTransformer: this.groupTransformer,\n userTransformer: this.userTransformer,\n logger: this.logger,\n },\n );\n\n const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);\n this.logger.debug(\n `Read ${users.length} LDAP users and ${groups.length} LDAP groups in ${duration} seconds`,\n );\n\n // Done!\n for (const group of groups) {\n emit(processingResult.entity(location, group));\n }\n for (const user of users) {\n emit(processingResult.entity(location, user));\n }\n\n return true;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n createExtensionPoint,\n} from '@backstage/backend-plugin-api';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';\nimport {\n GroupTransformer,\n UserTransformer,\n} from '@backstage/plugin-catalog-backend-module-ldap';\nimport { LdapOrgEntityProvider } from './processors';\n\n/**\n * Interface for {@link LdapOrgEntityProviderTransformsExtensionPoint}.\n *\n * @public\n */\nexport interface LdapOrgEntityProviderTransformsExtensionPoint {\n /**\n * Set the function that transforms a user entry in LDAP to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n setUserTransformer(\n transformer: UserTransformer | Record<string, UserTransformer>,\n ): void;\n\n /**\n * Set the function that transforms a group entry in LDAP to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n setGroupTransformer(\n transformer: GroupTransformer | Record<string, GroupTransformer>,\n ): void;\n}\n\n/**\n * Extension point used to customize the transforms used by the module.\n *\n * @public\n */\nexport const ldapOrgEntityProviderTransformsExtensionPoint =\n createExtensionPoint<LdapOrgEntityProviderTransformsExtensionPoint>({\n id: 'catalog.ldapOrgEntityProvider.transforms',\n });\n\n/**\n * Registers the LdapOrgEntityProvider with the catalog processing extension point.\n *\n * @public\n */\nexport const catalogModuleLdapOrgEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'ldapOrgEntityProvider',\n register(env) {\n let userTransformer:\n | UserTransformer\n | Record<string, UserTransformer>\n | undefined;\n let groupTransformer:\n | GroupTransformer\n | Record<string, GroupTransformer>\n | undefined;\n\n env.registerExtensionPoint(ldapOrgEntityProviderTransformsExtensionPoint, {\n setUserTransformer(transformer) {\n if (userTransformer) {\n throw new Error('User transformer may only be set once');\n }\n userTransformer = transformer;\n },\n setGroupTransformer(transformer) {\n if (groupTransformer) {\n throw new Error('Group transformer may only be set once');\n }\n groupTransformer = transformer;\n },\n });\n\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n },\n async init({ catalog, config, logger, scheduler }) {\n catalog.addEntityProvider(\n LdapOrgEntityProvider.fromConfig(config, {\n logger,\n scheduler,\n userTransformer: userTransformer,\n groupTransformer: groupTransformer,\n }),\n );\n },\n });\n },\n});\n"],"names":["cloneDeep","readFile","tlsLib","ldap","ForwardedError","stringifyError","trimEnd","mergeWith","readSchedulerServiceTaskScheduleDefinitionFromConfig","stringifyEntityRef","lodashSet","uuid","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","processingResult","createExtensionPoint","createBackendModule","catalogProcessingExtensionPoint","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/ldap/util.ts","../src/ldap/vendors.ts","../src/ldap/client.ts","../src/ldap/config.ts","../src/ldap/constants.ts","../src/ldap/org.ts","../src/ldap/read.ts","../src/processors/LdapOrgEntityProvider.ts","../src/processors/LdapOrgReaderProcessor.ts","../src/module.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Error as LDAPError, SearchEntry, SearchOptions } from 'ldapjs';\nimport { cloneDeep } from 'lodash';\nimport { LdapVendor } from './vendors';\n\n/**\n * Builds a string form of an LDAP Error structure.\n *\n * @param error - The error\n */\nexport function errorString(error: LDAPError) {\n return `${error.code} ${error.name}: ${error.message}`;\n}\n\n/**\n * Maps a single-valued attribute to a consumer.\n *\n * This helper can be useful when implementing a user or group transformer.\n *\n * @param entry - The LDAP source entry\n * @param vendor - The LDAP vendor\n * @param attributeName - The source attribute to map. If the attribute is\n * undefined the mapping will be silently ignored.\n * @param setter - The function to be called with the decoded attribute from the\n * source entry\n *\n * @public\n */\nexport function mapStringAttr(\n entry: SearchEntry,\n vendor: LdapVendor,\n attributeName: string | undefined,\n setter: (value: string) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n if (values && values.length === 1) {\n setter(values[0]);\n }\n }\n}\n\nexport function createOptions(inputOptions: SearchOptions): SearchOptions {\n const result = cloneDeep(inputOptions);\n\n if (result.paged === true) {\n result.paged = { pagePause: true };\n } else if (typeof result.paged === 'object') {\n result.paged.pagePause = true;\n }\n\n return result;\n}\n\nexport type RecursivePartial<T> = {\n [P in keyof T]?: T[P] extends (infer U)[]\n ? RecursivePartial<U>[]\n : T[P] extends object\n ? RecursivePartial<T[P]>\n : T[P];\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchEntry } from 'ldapjs';\n\n/**\n * An LDAP Vendor handles unique nuances between different vendors.\n *\n * @public\n */\nexport type LdapVendor = {\n /**\n * The attribute name that holds the distinguished name (DN) for an entry.\n */\n dnAttributeName: string;\n /**\n * The attribute name that holds a universal unique identifier for an entry.\n */\n uuidAttributeName: string;\n /**\n * Decode ldap entry values for a given attribute name to their string representation.\n *\n * @param entry - The ldap entry\n * @param name - The attribute to decode\n */\n decodeStringAttribute: (entry: SearchEntry, name: string) => string[];\n};\n\nexport const DefaultLdapVendor: LdapVendor = {\n dnAttributeName: 'entryDN',\n uuidAttributeName: 'entryUUID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const ActiveDirectoryVendor: LdapVendor = {\n dnAttributeName: 'distinguishedName',\n uuidAttributeName: 'objectGUID',\n decodeStringAttribute: (entry, name) => {\n const decoder = (value: string | Buffer) => {\n if (name === ActiveDirectoryVendor.uuidAttributeName) {\n return formatGUID(value);\n }\n return value.toString();\n };\n return decode(entry, name, decoder);\n },\n};\n\nexport const FreeIpaVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'ipaUniqueID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const AEDirVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'entryUUID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\n// Decode an attribute to a consumer\nfunction decode(\n entry: SearchEntry,\n attributeName: string,\n decoder: (value: string | Buffer) => string,\n): string[] {\n const values = entry.raw[attributeName];\n if (Array.isArray(values)) {\n return values.map(v => {\n return decoder(v);\n });\n } else if (values) {\n return [decoder(values)];\n }\n return [];\n}\n\n// Formats a Microsoft Active Directory binary-encoded uuid to a readable string\n// See https://github.com/ldapjs/node-ldapjs/issues/297#issuecomment-137765214\nfunction formatGUID(objectGUID: string | Buffer): string {\n let data: Buffer;\n if (typeof objectGUID === 'string') {\n data = Buffer.from(objectGUID, 'binary');\n } else {\n data = objectGUID;\n }\n // GUID_FORMAT_D\n let template = '{3}{2}{1}{0}-{5}{4}-{7}{6}-{8}{9}-{10}{11}{12}{13}{14}{15}';\n\n // check each byte\n for (let i = 0; i < data.length; i++) {\n let dataStr = data[i].toString(16);\n dataStr = data[i] >= 16 ? dataStr : `0${dataStr}`;\n\n // insert that character into the template\n template = template.replace(`{${i}}`, dataStr);\n }\n return template;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardedError, stringifyError } from '@backstage/errors';\nimport { readFile } from 'fs/promises';\nimport ldap, { Client, SearchEntry, SearchOptions } from 'ldapjs';\nimport { cloneDeep } from 'lodash';\nimport tlsLib from 'tls';\nimport { BindConfig, TLSConfig } from './config';\nimport { createOptions, errorString } from './util';\nimport {\n AEDirVendor,\n ActiveDirectoryVendor,\n DefaultLdapVendor,\n FreeIpaVendor,\n LdapVendor,\n} from './vendors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Basic wrapper for the `ldapjs` library.\n *\n * Helps out with promisifying calls, paging, binding etc.\n *\n * @public\n */\nexport class LdapClient {\n private vendor: Promise<LdapVendor> | undefined;\n\n static async create(\n logger: LoggerService,\n target: string,\n bind?: BindConfig,\n tls?: TLSConfig,\n ): Promise<LdapClient> {\n let secureContext;\n if (tls && tls.certs && tls.keys) {\n const cert = await readFile(tls.certs, 'utf-8');\n const key = await readFile(tls.keys, 'utf-8');\n secureContext = tlsLib.createSecureContext({\n cert: cert,\n key: key,\n });\n }\n\n const client = ldap.createClient({\n url: target,\n tlsOptions: {\n secureContext,\n rejectUnauthorized: tls?.rejectUnauthorized,\n },\n });\n\n // We want to have a catch-all error handler at the top, since the default\n // behavior of the client is to blow up the entire process when it fails,\n // unless an error handler is set.\n client.on('error', (err: ldap.Error) => {\n logger.warn(`LDAP client threw an error, ${errorString(err)}`);\n });\n\n if (!bind) {\n return new LdapClient(client, logger);\n }\n\n return new Promise<LdapClient>((resolve, reject) => {\n const { dn, secret } = bind;\n client.bind(dn, secret, err => {\n if (err) {\n reject(`LDAP bind failed for ${dn}, ${errorString(err)}`);\n } else {\n resolve(new LdapClient(client, logger));\n }\n });\n });\n }\n\n constructor(\n private readonly client: Client,\n private readonly logger: LoggerService,\n ) {}\n\n /**\n * Performs an LDAP search operation.\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n */\n async search(dn: string, options: SearchOptions): Promise<SearchEntry[]> {\n try {\n const output: SearchEntry[] = [];\n\n const logInterval = setInterval(() => {\n this.logger.debug(`Read ${output.length} LDAP entries so far...`);\n }, 5000);\n\n const search = new Promise<SearchEntry[]>((resolve, reject) => {\n // Note that we clone the (frozen) options, since ldapjs rudely tries to\n // overwrite parts of them\n this.client.search(dn, cloneDeep(options), (err, res) => {\n if (err) {\n reject(new Error(errorString(err)));\n return;\n }\n\n res.on('searchReference', () => {\n this.logger.warn('Received unsupported search referral');\n });\n\n res.on('searchEntry', entry => {\n output.push(entry);\n });\n\n res.on('error', e => {\n reject(new Error(errorString(e)));\n });\n\n res.on('page', (_result, cb) => {\n if (cb) {\n cb();\n }\n });\n\n res.on('end', r => {\n if (!r) {\n reject(new Error('Null response'));\n } else if (r.status !== 0) {\n reject(new Error(`Got status ${r.status}: ${r.errorMessage}`));\n } else {\n resolve(output);\n }\n });\n });\n });\n\n return await search.finally(() => {\n clearInterval(logInterval);\n });\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Performs an LDAP search operation, calls a function on each entry to limit memory usage\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n * @param f - The callback to call on each search entry\n */\n async searchStreaming(\n dn: string,\n options: SearchOptions,\n f: (entry: SearchEntry) => Promise<void> | void,\n ): Promise<void> {\n try {\n return await new Promise<void>((resolve, reject) => {\n // Note that we clone the (frozen) options, since ldapjs rudely tries to\n // overwrite parts of them\n this.client.search(dn, createOptions(options), (err, res) => {\n if (err) {\n reject(new Error(errorString(err)));\n }\n let awaitList: Array<Promise<void> | void> = [];\n let transformError = false;\n\n const transformReject = (e: Error) => {\n transformError = true;\n reject(\n new Error(\n `Transform function threw an exception, ${stringifyError(e)}`,\n ),\n );\n };\n\n res.on('searchReference', () => {\n this.logger.warn('Received unsupported search referral');\n });\n\n res.on('searchEntry', entry => {\n if (!transformError) awaitList.push(f(entry));\n });\n\n res.on('page', (_, cb) => {\n // awaits completion before fetching next page\n Promise.all(awaitList)\n .then(() => {\n // flush list\n awaitList = [];\n if (cb) cb();\n })\n .catch(transformReject);\n });\n\n res.on('error', e => {\n reject(new Error(errorString(e)));\n });\n\n res.on('end', r => {\n if (!r) {\n throw new Error('Null response');\n } else if (r.status !== 0) {\n throw new Error(`Got status ${r.status}: ${r.errorMessage}`);\n } else {\n Promise.all(awaitList)\n .then(() => resolve())\n .catch(transformReject);\n }\n });\n });\n });\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Get the Server Vendor.\n * Currently only detects Microsoft Active Directory Servers.\n *\n * @see https://ldapwiki.com/wiki/Determine%20LDAP%20Server%20Vendor\n */\n async getVendor(): Promise<LdapVendor> {\n if (this.vendor) {\n return this.vendor;\n }\n this.vendor = this.getRootDSE()\n .then(root => {\n if (root && root.raw?.forestFunctionality) {\n return ActiveDirectoryVendor;\n } else if (root && root.raw?.ipaDomainLevel) {\n return FreeIpaVendor;\n } else if (root && 'aeRoot' in root.raw) {\n return AEDirVendor;\n }\n return DefaultLdapVendor;\n })\n .catch(err => {\n this.vendor = undefined;\n throw err;\n });\n return this.vendor;\n }\n\n /**\n * Get the Root DSE.\n *\n * @see https://ldapwiki.com/wiki/RootDSE\n */\n async getRootDSE(): Promise<SearchEntry | undefined> {\n const result = await this.search('', {\n scope: 'base',\n filter: '(objectclass=*)',\n } as SearchOptions);\n if (result && result.length === 1) {\n return result[0];\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SchedulerServiceTaskScheduleDefinition,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { SearchOptions } from 'ldapjs';\nimport mergeWith from 'lodash/mergeWith';\nimport { trimEnd } from 'lodash';\nimport { RecursivePartial } from './util';\n\n/**\n * The configuration parameters for a single LDAP provider.\n *\n * @public\n */\nexport type LdapProviderConfig = {\n // The id of the\n id: string;\n // The prefix of the target that this matches on, e.g.\n // \"ldaps://ds.example.net\", with no trailing slash.\n target: string;\n // TLS settings\n tls?: TLSConfig;\n // The settings to use for the bind command. If none are specified, the bind\n // command is not issued.\n bind?: BindConfig;\n // The settings that govern the reading and interpretation of users\n users: UserConfig[];\n // The settings that govern the reading and interpretation of groups\n groups: GroupConfig[];\n // Schedule configuration for refresh tasks.\n schedule?: SchedulerServiceTaskScheduleDefinition;\n // Configuration for overriding the vendor-specific default attribute names.\n vendor?: VendorConfig;\n};\n\n/**\n * TLS settings\n *\n * @public\n */\nexport type TLSConfig = {\n // Node TLS rejectUnauthorized\n rejectUnauthorized?: boolean;\n // A file containing private keys in PEM format\n keys?: string;\n // A file containing cert chains in PEM format\n certs?: string;\n};\n\n/**\n * The settings to use for the a command.\n *\n * @public\n */\nexport type BindConfig = {\n // The DN of the user to auth as, e.g.\n // uid=ldap-robot,ou=robots,ou=example,dc=example,dc=net\n dn: string;\n // The secret of the user to auth as (its password)\n secret: string;\n};\n\n/**\n * The settings that govern the reading and interpretation of users.\n *\n * @public\n */\nexport type UserConfig = {\n // The DN under which users are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported. The\n // default is scope \"one\" and attributes \"*\" and \"+\".\n options: SearchOptions;\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"uid\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"uid\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity.\n description?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity. Defaults to \"mail\".\n email: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.memberOf field of the entity. Defaults to \"memberOf\".\n memberOf: string;\n };\n};\n\n/**\n * The settings that govern the reading and interpretation of groups.\n *\n * @public\n */\nexport type GroupConfig = {\n // The DN under which groups are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported.\n options: SearchOptions;\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"cn\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"cn\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity. Defaults to \"description\".\n description: string;\n // The name of the attribute that shall be used for the value of the\n // spec.type field of the entity. Defaults to \"groupType\".\n type: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity.\n email?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.parent field of the entity. Defaults to \"memberOf\".\n memberOf: string;\n // The name of the attribute that shall be used for the values of the\n // spec.children field of the entity. Defaults to \"member\".\n members: string;\n };\n};\n\n/**\n * Configuration for LDAP vendor-specific attributes.\n *\n * Allows custom attribute names for distinguished names (DN) and\n * universally unique identifiers (UUID) in LDAP directories.\n *\n * @public\n */\nexport type VendorConfig = {\n /**\n * Attribute name for the distinguished name (DN) of an entry,\n */\n dnAttributeName?: string;\n\n /**\n * Attribute name for the unique identifier (UUID) of an entry,\n */\n uuidAttributeName?: string;\n};\n\nconst defaultUserConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'uid',\n name: 'uid',\n displayName: 'cn',\n email: 'mail',\n memberOf: 'memberOf',\n },\n};\n\nconst defaultGroupConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'cn',\n name: 'cn',\n description: 'description',\n displayName: 'cn',\n type: 'groupType',\n memberOf: 'memberOf',\n members: 'member',\n },\n};\n\nfunction freeze<T>(data: T): T {\n return JSON.parse(JSON.stringify(data), (_key, value) => {\n if (typeof value === 'object' && value !== null) {\n Object.freeze(value);\n }\n return value;\n });\n}\n\nfunction readTlsConfig(\n c: Config | undefined,\n): LdapProviderConfig['tls'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n rejectUnauthorized: c.getOptionalBoolean('rejectUnauthorized'),\n keys: c.getOptionalString('keys'),\n certs: c.getOptionalString('certs'),\n };\n}\n\nfunction readBindConfig(\n c: Config | undefined,\n): LdapProviderConfig['bind'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dn: c.getString('dn'),\n secret: c.getString('secret'),\n };\n}\n\nfunction readVendorConfig(\n c: Config | undefined,\n): LdapProviderConfig['vendor'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dnAttributeName: c.getOptionalString('dnAttributeName'),\n uuidAttributeName: c.getOptionalString('uuidAttributeName'),\n };\n}\n\nfunction readOptionsConfig(c: Config | undefined): SearchOptions {\n if (!c) {\n return {};\n }\n\n const paged = readOptionsPagedConfig(c);\n\n return {\n scope: c.getOptionalString('scope') as SearchOptions['scope'],\n filter: formatFilter(c.getOptionalString('filter')),\n attributes: c.getOptionalStringArray('attributes'),\n sizeLimit: c.getOptionalNumber('sizeLimit'),\n timeLimit: c.getOptionalNumber('timeLimit'),\n derefAliases: c.getOptionalNumber('derefAliases'),\n typesOnly: c.getOptionalBoolean('typesOnly'),\n ...(paged !== undefined ? { paged } : undefined),\n };\n}\n\nfunction readOptionsPagedConfig(c: Config): SearchOptions['paged'] {\n const pagedConfig = c.getOptional('paged');\n if (pagedConfig === undefined) {\n return undefined;\n }\n\n if (pagedConfig === true || pagedConfig === false) {\n return pagedConfig;\n }\n\n const pageSize = c.getOptionalNumber('paged.pageSize');\n const pagePause = c.getOptionalBoolean('paged.pagePause');\n return {\n ...(pageSize !== undefined ? { pageSize } : undefined),\n ...(pagePause !== undefined ? { pagePause } : undefined),\n };\n}\n\nfunction readSetConfig(\n c: Config | undefined,\n): { [path: string]: JsonValue } | undefined {\n if (!c) {\n return undefined;\n }\n return c.get();\n}\n\nfunction readUserMapConfig(c: Config | undefined): Partial<UserConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n };\n}\n\nfunction readGroupMapConfig(\n c: Config | undefined,\n): Partial<GroupConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n type: c.getOptionalString('type'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n members: c.getOptionalString('members'),\n };\n}\n\nfunction readUserConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['users']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleUserConfig(it));\n }\n return [readSingleUserConfig(c)];\n}\n\nfunction readSingleUserConfig(c: Config): RecursivePartial<UserConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readUserMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction readGroupConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['groups']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleGroupConfig(it));\n }\n return [readSingleGroupConfig(c)];\n}\n\nfunction readSingleGroupConfig(c: Config): RecursivePartial<GroupConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readGroupMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction formatFilter(filter?: string): string | undefined {\n // Remove extra whitespace between blocks to support multiline filters from the configuration\n return filter?.replace(/\\s*(\\(|\\))/g, '$1')?.trim();\n}\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n * @deprecated This exists for backwards compatibility only and will be removed in the future.\n */\nexport function readLdapLegacyConfig(config: Config): LdapProviderConfig[] {\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n return providerConfigs.map(c => {\n const newConfig = {\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(c.getConfig('users')).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(c.getConfig('groups')).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n vendor: readVendorConfig(c.getOptionalConfig('vendor')),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\n/**\n * Parses all configured providers.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n */\nexport function readProviderConfigs(config: Config): LdapProviderConfig[] {\n const providersConfig = config.getOptionalConfig('catalog.providers.ldapOrg');\n if (!providersConfig) {\n return [];\n }\n\n return providersConfig.keys().map(id => {\n const c = providersConfig.getConfig(id);\n const schedule = c.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n c.getConfig('schedule'),\n )\n : undefined;\n\n const isUserList = Array.isArray(c.getOptional('users'));\n const isGroupList = Array.isArray(c.getOptional('groups'));\n\n const newConfig = {\n id,\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(\n isUserList\n ? c.getOptionalConfigArray('users')\n : c.getOptionalConfig('users'),\n ).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(\n isGroupList\n ? c.getOptionalConfigArray('groups')\n : c.getOptionalConfig('groups'),\n ).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n schedule,\n vendor: readVendorConfig(c.getOptionalConfig('vendor')),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\nfunction replaceArraysIfPresent(_into: any, from: any) {\n // Replace arrays instead of merging, otherwise default behavior\n return Array.isArray(from) ? from : undefined;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The name of an entity annotation, that references the RDN of the LDAP object\n * it was ingested from.\n *\n * The RDN is the name of the leftmost attribute that identifies the item; for\n * example, for an item with the fully qualified DN\n * uid=john,ou=people,ou=spotify,dc=spotify,dc=net the generated entity would\n * have this annotation, with the value \"john\".\n *\n * @public\n */\nexport const LDAP_RDN_ANNOTATION = 'backstage.io/ldap-rdn';\n\n/**\n * The name of an entity annotation, that references the DN of the LDAP object\n * it was ingested from.\n *\n * The DN is the fully qualified name that identifies the item; for example,\n * for an item with the DN uid=john,ou=people,ou=spotify,dc=spotify,dc=net the\n * generated entity would have this annotation, with that full string as its\n * value.\n *\n * @public\n */\nexport const LDAP_DN_ANNOTATION = 'backstage.io/ldap-dn';\n\n/**\n * The name of an entity annotation, that references the UUID of the LDAP\n * object it was ingested from.\n *\n * The UUID is the globally unique ID that identifies the item; for example,\n * for an item with the UUID 76ef928a-b251-1037-9840-d78227f36a7e, the\n * generated entity would have this annotation, with that full string as its\n * value.\n *\n * @public\n */\nexport const LDAP_UUID_ANNOTATION = 'backstage.io/ldap-uuid';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\n\n// TODO: Copied from plugin-catalog-backend, but we could also export them from\n// there. Or move them to catalog-model.\n\nexport function buildOrgHierarchy(groups: GroupEntity[]) {\n const groupsByRef = new Map(groups.map(g => [stringifyEntityRef(g), g]));\n\n //\n // Make sure that g.parent.children contain g\n //\n\n for (const group of groups) {\n const selfRef = stringifyEntityRef(group);\n const parentRef = group.spec.parent;\n if (parentRef) {\n const parent = groupsByRef.get(parentRef);\n if (parent && !parent.spec.children.includes(selfRef)) {\n parent.spec.children.push(selfRef);\n }\n }\n }\n\n //\n // Make sure that g.children.parent is g\n //\n\n for (const group of groups) {\n const selfRef = stringifyEntityRef(group);\n for (const childRef of group.spec.children) {\n const child = groupsByRef.get(childRef);\n if (child && !child.spec.parent) {\n child.spec.parent = selfRef;\n }\n }\n }\n}\n\n// Ensure that users have their transitive group memberships. Requires that\n// the groups were previously processed with buildOrgHierarchy()\nexport function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) {\n const groupsByRef = new Map(groups.map(g => [stringifyEntityRef(g), g]));\n\n users.forEach(user => {\n const transitiveMemberOf = new Set<string>();\n\n const todo = [\n ...(user.spec.memberOf ?? []),\n ...groups\n .filter(g => g.spec.members?.includes(stringifyEntityRef(user)))\n .map(g => stringifyEntityRef(g)),\n ];\n\n for (;;) {\n const current = todo.pop();\n if (!current) {\n break;\n }\n\n if (!transitiveMemberOf.has(current)) {\n transitiveMemberOf.add(current);\n const group = groupsByRef.get(current);\n if (group?.spec.parent) {\n todo.push(group.spec.parent);\n }\n }\n }\n\n user.spec.memberOf = [...transitiveMemberOf];\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { SearchEntry } from 'ldapjs';\nimport lodashSet from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport { buildOrgHierarchy } from './org';\nimport { LdapClient } from './client';\nimport { GroupConfig, UserConfig, VendorConfig } from './config';\nimport {\n LDAP_DN_ANNOTATION,\n LDAP_RDN_ANNOTATION,\n LDAP_UUID_ANNOTATION,\n} from './constants';\nimport { LdapVendor } from './vendors';\nimport { GroupTransformer, UserTransformer } from './types';\nimport { mapStringAttr } from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n vendor: LdapVendor,\n config: UserConfig,\n entry: SearchEntry,\n): Promise<UserEntity | undefined> {\n const { set, map } = config;\n\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'User',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n profile: {},\n memberOf: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads users out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The user data configuration\n * @param opts - Additional options\n */\nexport async function readLdapUsers(\n client: LdapClient,\n userConfig: UserConfig[],\n vendorConfig: VendorConfig | undefined,\n opts?: { transformer?: UserTransformer },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n userMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n}> {\n if (userConfig.length === 0) {\n return { users: [], userMemberOf: new Map() };\n }\n const entities: UserEntity[] = [];\n const userMemberOf: Map<string, Set<string>> = new Map();\n const vendorDefaults = await client.getVendor();\n const vendor: LdapVendor = {\n dnAttributeName:\n vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,\n uuidAttributeName:\n vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,\n decodeStringAttribute: vendorDefaults.decodeStringAttribute,\n };\n const transformer = opts?.transformer ?? defaultUserTransformer;\n\n for (const cfg of userConfig) {\n const { dn, options, map } = cfg;\n await client.searchStreaming(dn, options, async user => {\n const entity = await transformer(vendor, cfg, user);\n\n if (!entity) {\n return;\n }\n\n mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(userMemberOf, myDn, vs);\n });\n entities.push(entity);\n });\n }\n\n return { users: entities, userMemberOf };\n}\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n vendor: LdapVendor,\n config: GroupConfig,\n entry: SearchEntry,\n): Promise<GroupEntity | undefined> {\n const { set, map } = config;\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'Group',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n type: 'unknown',\n profile: {},\n children: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.type, v => {\n entity.spec.type = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The group data configuration\n * @param opts - Additional options\n */\nexport async function readLdapGroups(\n client: LdapClient,\n groupConfig: GroupConfig[],\n vendorConfig: VendorConfig | undefined,\n opts?: {\n transformer?: GroupTransformer;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n groupMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n groupMember: Map<string, Set<string>>; // DN -> DN or UUID of groups & users\n}> {\n if (groupConfig.length === 0) {\n return { groups: [], groupMemberOf: new Map(), groupMember: new Map() };\n }\n const groups: GroupEntity[] = [];\n const groupMemberOf: Map<string, Set<string>> = new Map();\n const groupMember: Map<string, Set<string>> = new Map();\n\n const vendorDefaults = await client.getVendor();\n const vendor: LdapVendor = {\n dnAttributeName:\n vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,\n uuidAttributeName:\n vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,\n decodeStringAttribute: vendorDefaults.decodeStringAttribute,\n };\n\n const transformer = opts?.transformer ?? defaultGroupTransformer;\n\n for (const cfg of groupConfig) {\n const { dn, map, options } = cfg;\n\n await client.searchStreaming(dn, options, async entry => {\n if (!entry) {\n return;\n }\n\n const entity = await transformer(vendor, cfg, entry);\n\n if (!entity) {\n return;\n }\n\n mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(groupMemberOf, myDn, vs);\n });\n mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => {\n ensureItems(groupMember, myDn, vs);\n });\n\n groups.push(entity);\n });\n }\n\n return {\n groups,\n groupMemberOf,\n groupMember,\n };\n}\n\n/**\n * Reads users and groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param userConfig - The user data configuration\n * @param groupConfig - The group data configuration\n * @param options - Additional options\n *\n * @public\n */\nexport async function readLdapOrg(\n client: LdapClient,\n userConfig: UserConfig[],\n groupConfig: GroupConfig[],\n vendorConfig: VendorConfig | undefined,\n options: {\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[];\n groups: GroupEntity[];\n}> {\n // Invokes the above \"raw\" read functions and stitches together the results\n // with all relations etc filled in.\n\n const { users, userMemberOf } = await readLdapUsers(\n client,\n userConfig,\n vendorConfig,\n {\n transformer: options?.userTransformer,\n },\n );\n const { groups, groupMemberOf, groupMember } = await readLdapGroups(\n client,\n groupConfig,\n vendorConfig,\n { transformer: options?.groupTransformer },\n );\n\n resolveRelations(groups, users, userMemberOf, groupMemberOf, groupMember);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\n//\n// Helpers\n//\n\n// Maps a multi-valued attribute of references to other objects, to a consumer\nfunction mapReferencesAttr(\n entry: SearchEntry,\n vendor: LdapVendor,\n attributeName: string | undefined,\n setter: (sourceDn: string, targets: string[]) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n const dn = vendor.decodeStringAttribute(entry, vendor.dnAttributeName);\n if (values && dn && dn.length === 1) {\n setter(dn[0], values);\n }\n }\n}\n\n// Inserts a number of values in a key-values mapping\nfunction ensureItems(\n target: Map<string, Set<string>>,\n key: string,\n values: string[],\n) {\n if (key) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n for (const value of values) {\n if (value) {\n set!.add(value);\n }\n }\n }\n}\n\n/**\n * Takes groups and entities with empty relations, and fills in the various\n * relations that were returned by the readers, and forms the org hierarchy.\n *\n * @param groups - Group entities with empty relations; modified in place\n * @param users - User entities with empty relations; modified in place\n * @param userMemberOf - For a user DN, the set of group DNs or UUIDs that the\n * user is a member of\n * @param groupMemberOf - For a group DN, the set of group DNs or UUIDs that\n * the group is a member of (parents in the hierarchy)\n * @param groupMember - For a group DN, the set of group DNs or UUIDs that are\n * members of the group (children in the hierarchy)\n */\nexport function resolveRelations(\n groups: GroupEntity[],\n users: UserEntity[],\n userMemberOf: Map<string, Set<string>>,\n groupMemberOf: Map<string, Set<string>>,\n groupMember: Map<string, Set<string>>,\n) {\n // Build reference lookup tables - all of the relations that are output from\n // the above calls can be expressed as either DNs or UUIDs so we need to be\n // able to find by both, as well as the entity reference. Note that we expect them to not\n // collide here - this is a reasonable assumption as long as the fields are\n // the supported forms.\n const userMap: Map<string, UserEntity> = new Map(); // by entityRef, dn, uuid\n const groupMap: Map<string, GroupEntity> = new Map(); // by entityRef, dn, uuid\n for (const user of users) {\n userMap.set(stringifyEntityRef(user), user);\n userMap.set(user.metadata.annotations![LDAP_DN_ANNOTATION], user);\n userMap.set(user.metadata.annotations![LDAP_RDN_ANNOTATION], user);\n userMap.set(user.metadata.annotations![LDAP_UUID_ANNOTATION], user);\n }\n for (const group of groups) {\n groupMap.set(stringifyEntityRef(group), group);\n groupMap.set(group.metadata.annotations![LDAP_DN_ANNOTATION], group);\n groupMap.set(group.metadata.annotations![LDAP_RDN_ANNOTATION], group);\n groupMap.set(group.metadata.annotations![LDAP_UUID_ANNOTATION], group);\n }\n\n // This can happen e.g. if entryUUID wasn't returned by the server\n userMap.delete('');\n groupMap.delete('');\n userMap.delete(undefined!);\n groupMap.delete(undefined!);\n\n // Fill in all of the immediate relations, now keyed on the entity reference. We\n // keep all parents at this point, whether the target model can support more\n // than one or not (it gets filtered farther down). And group children are\n // only groups in here.\n const newUserMemberOf: Map<string, Set<string>> = new Map();\n const newGroupParents: Map<string, Set<string>> = new Map();\n const newGroupChildren: Map<string, Set<string>> = new Map();\n\n // Resolve and store in the intermediaries. It may seem redundant that the\n // input data has both parent and children directions, as well as both\n // user->group and group->user - the reason is that different LDAP schemas\n // express relations in different directions. Some may have a user memberOf\n // overlay, some don't, for example.\n for (const [userN, groupsN] of userMemberOf.entries()) {\n const user = userMap.get(userN);\n if (user) {\n for (const groupN of groupsN) {\n const group = groupMap.get(groupN);\n if (group) {\n ensureItems(newUserMemberOf, stringifyEntityRef(user), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, parentsN] of groupMemberOf.entries()) {\n const group = groupMap.get(groupN);\n if (group) {\n for (const parentN of parentsN) {\n const parentGroup = groupMap.get(parentN);\n if (parentGroup) {\n ensureItems(newGroupParents, stringifyEntityRef(group), [\n stringifyEntityRef(parentGroup),\n ]);\n ensureItems(newGroupChildren, stringifyEntityRef(parentGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, membersN] of groupMember.entries()) {\n const group = groupMap.get(groupN);\n if (group) {\n for (const memberN of membersN) {\n // Group members can be both users and groups in the input model, so\n // try both\n const memberUser = userMap.get(memberN);\n if (memberUser) {\n ensureItems(newUserMemberOf, stringifyEntityRef(memberUser), [\n stringifyEntityRef(group),\n ]);\n } else {\n const memberGroup = groupMap.get(memberN);\n if (memberGroup) {\n ensureItems(newGroupChildren, stringifyEntityRef(group), [\n stringifyEntityRef(memberGroup),\n ]);\n ensureItems(newGroupParents, stringifyEntityRef(memberGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n }\n\n // Write down the relations again into the actual entities\n for (const [userN, groupsN] of newUserMemberOf.entries()) {\n const user = userMap.get(userN);\n if (user) {\n user.spec.memberOf = Array.from(groupsN).sort();\n }\n }\n for (const [groupN, parentsN] of newGroupParents.entries()) {\n if (parentsN.size === 1) {\n const group = groupMap.get(groupN);\n if (group) {\n group.spec.parent = parentsN.values().next().value;\n }\n }\n }\n for (const [groupN, childrenN] of newGroupChildren.entries()) {\n const group = groupMap.get(groupN);\n if (group) {\n group.spec.children = Array.from(childrenN).sort();\n }\n }\n\n // Fill out the rest of the hierarchy\n buildOrgHierarchy(groups);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport {\n GroupTransformer,\n LdapClient,\n LdapProviderConfig,\n LDAP_DN_ANNOTATION,\n readLdapOrg,\n UserTransformer,\n} from '../ldap';\nimport {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport { readLdapLegacyConfig, readProviderConfigs } from '../ldap';\n\n/**\n * Options for {@link LdapOrgEntityProvider}.\n *\n * @public\n */\nexport type LdapOrgEntityProviderOptions =\n | LdapOrgEntityProviderLegacyOptions\n | {\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: SchedulerService;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n userTransformer?: UserTransformer | Record<string, UserTransformer>;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n groupTransformer?: GroupTransformer | Record<string, GroupTransformer>;\n };\n\n/**\n * Options for {@link LdapOrgEntityProvider}.\n *\n * @public\n * @deprecated This interface exists for backwards compatibility only and will be removed in the future.\n */\nexport interface LdapOrgEntityProviderLegacyOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The target that this provider should consume.\n *\n * Should exactly match the \"target\" field of one of the \"ldap.providers\"\n * configuration entries.\n *\n * @example \"ldaps://ds-read.example.net\"\n */\n target: string;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | SchedulerServiceTaskRunner;\n\n /**\n * The function that transforms a user entry in LDAP to an entity.\n */\n userTransformer?: UserTransformer;\n\n /**\n * The function that transforms a group entry in LDAP to an entity.\n */\n groupTransformer?: GroupTransformer;\n}\n\n/**\n * Reads user and group entries out of an LDAP service, and provides them as\n * User and Group entities for the catalog.\n *\n * @remarks\n *\n * Add an instance of this class to your catalog builder, and then periodically\n * call the {@link LdapOrgEntityProvider.read} method.\n *\n * @public\n */\nexport class LdapOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private scheduleFn?: () => Promise<void>;\n\n static fromConfig(\n configRoot: Config,\n options: LdapOrgEntityProviderOptions,\n ): LdapOrgEntityProvider[] {\n if ('id' in options) {\n return [LdapOrgEntityProvider.fromLegacyConfig(configRoot, options)];\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n function getTransformer<T extends Function>(\n id: string,\n transformers?: T | Record<string, T>,\n ): T | undefined {\n if (['undefined', 'function'].includes(typeof transformers)) {\n return transformers as T;\n }\n\n return (transformers as Record<string, T>)[id];\n }\n\n return readProviderConfigs(configRoot).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for LdapOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n const provider = new LdapOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: options.logger,\n userTransformer: getTransformer(\n providerConfig.id,\n options.userTransformer,\n ),\n groupTransformer: getTransformer(\n providerConfig.id,\n options.groupTransformer,\n ),\n });\n\n if (taskRunner !== 'manual') {\n provider.schedule(taskRunner);\n }\n\n return provider;\n });\n }\n\n static fromLegacyConfig(\n configRoot: Config,\n options: LdapOrgEntityProviderLegacyOptions,\n ): LdapOrgEntityProvider {\n // TODO(freben): Deprecate the old catalog.processors.ldapOrg config\n const config =\n configRoot.getOptionalConfig('ldap') ||\n configRoot.getOptionalConfig('catalog.processors.ldapOrg');\n const providers = config ? readLdapLegacyConfig(config) : [];\n const provider = providers.find(p => options.target === p.target);\n if (!provider) {\n throw new TypeError(\n `There is no LDAP configuration that matches \"${options.target}\". Please add a configuration entry for it under \"ldap.providers\".`,\n );\n }\n\n const logger = options.logger.child({\n target: options.target,\n });\n\n const result = new LdapOrgEntityProvider({\n id: options.id,\n provider,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n logger,\n });\n\n if (options.schedule !== 'manual') {\n result.schedule(options.schedule);\n }\n\n return result;\n }\n\n constructor(\n private options: {\n id: string;\n provider: LdapProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n },\n ) {}\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName() {\n return `LdapOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one single complete ingestion. This is only necessary if you use\n * manual scheduling.\n */\n async read(options?: { logger?: LoggerService }) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const { markReadComplete } = trackProgress(logger);\n\n // Be lazy and create the client each time; even though it's pretty\n // inefficient, we usually only do this once per entire refresh loop and\n // don't have to worry about timeouts and reconnects etc.\n const client = await LdapClient.create(\n this.options.logger,\n this.options.provider.target,\n this.options.provider.bind,\n this.options.provider.tls,\n );\n\n const { users, groups } = await readLdapOrg(\n client,\n this.options.provider.users,\n this.options.provider.groups,\n this.options.provider.vendor,\n {\n groupTransformer: this.options.groupTransformer,\n userTransformer: this.options.userTransformer,\n logger,\n },\n );\n\n const { markCommitComplete } = markReadComplete({ users, groups });\n\n await this.connection.applyMutation({\n type: 'full',\n entities: [...users, ...groups].map(entity => ({\n locationKey: `ldap-org-provider:${this.options.id}`,\n entity: withLocations(this.options.id, entity),\n })),\n });\n\n markCommitComplete();\n }\n\n private schedule(taskRunner: SchedulerServiceTaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async () => {\n const logger = this.options.logger.child({\n class: LdapOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.read({ logger });\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: LoggerService) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading LDAP users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\n summary = `${read.users.length} LDAP users and ${read.groups.length} LDAP groups`;\n const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n timestamp = Date.now();\n logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`);\n return { markCommitComplete };\n }\n\n function markCommitComplete() {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`);\n }\n\n return { markReadComplete };\n}\n\n// Makes sure that emitted entities have a proper location based on their DN\nfunction withLocations(providerId: string, entity: Entity): Entity {\n const dn =\n entity.metadata.annotations?.[LDAP_DN_ANNOTATION] || entity.metadata.name;\n const location = `ldap://${providerId}/${encodeURIComponent(dn)}`;\n return merge(\n {\n metadata: {\n annotations: {\n [ANNOTATION_LOCATION]: location,\n [ANNOTATION_ORIGIN_LOCATION]: location,\n },\n },\n },\n entity,\n ) as Entity;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n GroupTransformer,\n LdapClient,\n LdapProviderConfig,\n readLdapLegacyConfig,\n readLdapOrg,\n UserTransformer,\n} from '../ldap';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Extracts teams and users out of an LDAP server.\n *\n * @public\n */\nexport class LdapOrgReaderProcessor implements CatalogProcessor {\n private readonly providers: LdapProviderConfig[];\n private readonly logger: LoggerService;\n private readonly groupTransformer?: GroupTransformer;\n private readonly userTransformer?: UserTransformer;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n },\n ) {\n // TODO(freben): Deprecate the old catalog.processors.ldapOrg config\n const config =\n configRoot.getOptionalConfig('ldap') ||\n configRoot.getOptionalConfig('catalog.processors.ldapOrg');\n return new LdapOrgReaderProcessor({\n ...options,\n providers: config ? readLdapLegacyConfig(config) : [],\n });\n }\n\n constructor(options: {\n providers: LdapProviderConfig[];\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n }) {\n this.providers = options.providers;\n this.logger = options.logger;\n this.groupTransformer = options.groupTransformer;\n this.userTransformer = options.userTransformer;\n }\n\n getProcessorName(): string {\n return 'LdapOrgReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'ldap-org') {\n return false;\n }\n\n const provider = this.providers.find(p => location.target === p.target);\n if (!provider) {\n throw new Error(\n `There is no LDAP configuration that matches \"${location.target}\". Please add a configuration entry for it under \"ldap.providers\".`,\n );\n }\n\n // Read out all of the raw data\n const startTimestamp = Date.now();\n this.logger.info('Reading LDAP users and groups');\n\n // Be lazy and create the client each time; even though it's pretty\n // inefficient, we usually only do this once per entire refresh loop and\n // don't have to worry about timeouts and reconnects etc.\n const client = await LdapClient.create(\n this.logger,\n provider.target,\n provider.bind,\n provider.tls,\n );\n const { users, groups } = await readLdapOrg(\n client,\n provider.users,\n provider.groups,\n provider.vendor,\n {\n groupTransformer: this.groupTransformer,\n userTransformer: this.userTransformer,\n logger: this.logger,\n },\n );\n\n const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);\n this.logger.debug(\n `Read ${users.length} LDAP users and ${groups.length} LDAP groups in ${duration} seconds`,\n );\n\n // Done!\n for (const group of groups) {\n emit(processingResult.entity(location, group));\n }\n for (const user of users) {\n emit(processingResult.entity(location, user));\n }\n\n return true;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n createExtensionPoint,\n} from '@backstage/backend-plugin-api';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';\nimport {\n GroupTransformer,\n UserTransformer,\n} from '@backstage/plugin-catalog-backend-module-ldap';\nimport { LdapOrgEntityProvider } from './processors';\n\n/**\n * Interface for {@link LdapOrgEntityProviderTransformsExtensionPoint}.\n *\n * @public\n */\nexport interface LdapOrgEntityProviderTransformsExtensionPoint {\n /**\n * Set the function that transforms a user entry in LDAP to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n setUserTransformer(\n transformer: UserTransformer | Record<string, UserTransformer>,\n ): void;\n\n /**\n * Set the function that transforms a group entry in LDAP to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n setGroupTransformer(\n transformer: GroupTransformer | Record<string, GroupTransformer>,\n ): void;\n}\n\n/**\n * Extension point used to customize the transforms used by the module.\n *\n * @public\n */\nexport const ldapOrgEntityProviderTransformsExtensionPoint =\n createExtensionPoint<LdapOrgEntityProviderTransformsExtensionPoint>({\n id: 'catalog.ldapOrgEntityProvider.transforms',\n });\n\n/**\n * Registers the LdapOrgEntityProvider with the catalog processing extension point.\n *\n * @public\n */\nexport const catalogModuleLdapOrgEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'ldapOrgEntityProvider',\n register(env) {\n let userTransformer:\n | UserTransformer\n | Record<string, UserTransformer>\n | undefined;\n let groupTransformer:\n | GroupTransformer\n | Record<string, GroupTransformer>\n | undefined;\n\n env.registerExtensionPoint(ldapOrgEntityProviderTransformsExtensionPoint, {\n setUserTransformer(transformer) {\n if (userTransformer) {\n throw new Error('User transformer may only be set once');\n }\n userTransformer = transformer;\n },\n setGroupTransformer(transformer) {\n if (groupTransformer) {\n throw new Error('Group transformer may only be set once');\n }\n groupTransformer = transformer;\n },\n });\n\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n },\n async init({ catalog, config, logger, scheduler }) {\n catalog.addEntityProvider(\n LdapOrgEntityProvider.fromConfig(config, {\n logger,\n scheduler,\n userTransformer: userTransformer,\n groupTransformer: groupTransformer,\n }),\n );\n },\n });\n },\n});\n"],"names":["cloneDeep","readFile","tlsLib","ldap","ForwardedError","stringifyError","trimEnd","mergeWith","readSchedulerServiceTaskScheduleDefinitionFromConfig","stringifyEntityRef","lodashSet","uuid","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","processingResult","createExtensionPoint","createBackendModule","catalogProcessingExtensionPoint","coreServices"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ type LdapProviderConfig = {
21
21
  users: UserConfig[];
22
22
  groups: GroupConfig[];
23
23
  schedule?: SchedulerServiceTaskScheduleDefinition;
24
+ vendor?: VendorConfig;
24
25
  };
25
26
  /**
26
27
  * TLS settings
@@ -85,6 +86,24 @@ type GroupConfig = {
85
86
  members: string;
86
87
  };
87
88
  };
89
+ /**
90
+ * Configuration for LDAP vendor-specific attributes.
91
+ *
92
+ * Allows custom attribute names for distinguished names (DN) and
93
+ * universally unique identifiers (UUID) in LDAP directories.
94
+ *
95
+ * @public
96
+ */
97
+ type VendorConfig = {
98
+ /**
99
+ * Attribute name for the distinguished name (DN) of an entry,
100
+ */
101
+ dnAttributeName?: string;
102
+ /**
103
+ * Attribute name for the unique identifier (UUID) of an entry,
104
+ */
105
+ uuidAttributeName?: string;
106
+ };
88
107
  /**
89
108
  * Parses configuration.
90
109
  *
@@ -275,7 +294,7 @@ declare function defaultGroupTransformer(vendor: LdapVendor, config: GroupConfig
275
294
  *
276
295
  * @public
277
296
  */
278
- declare function readLdapOrg(client: LdapClient, userConfig: UserConfig[], groupConfig: GroupConfig[], options: {
297
+ declare function readLdapOrg(client: LdapClient, userConfig: UserConfig[], groupConfig: GroupConfig[], vendorConfig: VendorConfig | undefined, options: {
279
298
  groupTransformer?: GroupTransformer;
280
299
  userTransformer?: UserTransformer;
281
300
  logger: LoggerService;
@@ -464,4 +483,4 @@ declare const ldapOrgEntityProviderTransformsExtensionPoint: _backstage_backend_
464
483
  */
465
484
  declare const catalogModuleLdapOrgEntityProvider: _backstage_backend_plugin_api.BackendFeature;
466
485
 
467
- export { type BindConfig, type GroupConfig, type GroupTransformer, LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, LDAP_UUID_ANNOTATION, LdapClient, LdapOrgEntityProvider, type LdapOrgEntityProviderLegacyOptions, type LdapOrgEntityProviderOptions, type LdapOrgEntityProviderTransformsExtensionPoint, LdapOrgReaderProcessor, type LdapProviderConfig, type LdapVendor, type TLSConfig, type UserConfig, type UserTransformer, catalogModuleLdapOrgEntityProvider as default, defaultGroupTransformer, defaultUserTransformer, ldapOrgEntityProviderTransformsExtensionPoint, mapStringAttr, readLdapLegacyConfig, readLdapOrg, readProviderConfigs };
486
+ export { type BindConfig, type GroupConfig, type GroupTransformer, LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, LDAP_UUID_ANNOTATION, LdapClient, LdapOrgEntityProvider, type LdapOrgEntityProviderLegacyOptions, type LdapOrgEntityProviderOptions, type LdapOrgEntityProviderTransformsExtensionPoint, LdapOrgReaderProcessor, type LdapProviderConfig, type LdapVendor, type TLSConfig, type UserConfig, type UserTransformer, type VendorConfig, catalogModuleLdapOrgEntityProvider as default, defaultGroupTransformer, defaultUserTransformer, ldapOrgEntityProviderTransformsExtensionPoint, mapStringAttr, readLdapLegacyConfig, readLdapOrg, readProviderConfigs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-ldap",
3
- "version": "0.9.0-next.2",
3
+ "version": "0.9.1-next.0",
4
4
  "description": "A Backstage catalog backend module that helps integrate towards LDAP",
5
5
  "backstage": {
6
6
  "role": "backend-plugin-module",
@@ -38,12 +38,12 @@
38
38
  "test": "backstage-cli package test"
39
39
  },
40
40
  "dependencies": {
41
- "@backstage/backend-plugin-api": "^1.0.0-next.2",
42
- "@backstage/catalog-model": "^1.6.0",
41
+ "@backstage/backend-plugin-api": "^1.0.1-next.0",
42
+ "@backstage/catalog-model": "^1.7.0",
43
43
  "@backstage/config": "^1.2.0",
44
44
  "@backstage/errors": "^1.2.4",
45
- "@backstage/plugin-catalog-common": "^1.0.26",
46
- "@backstage/plugin-catalog-node": "^1.12.7-next.2",
45
+ "@backstage/plugin-catalog-common": "^1.1.0",
46
+ "@backstage/plugin-catalog-node": "^1.13.1-next.0",
47
47
  "@backstage/types": "^1.1.1",
48
48
  "@types/ldapjs": "^2.2.5",
49
49
  "ldapjs": "^2.3.3",
@@ -51,7 +51,7 @@
51
51
  "uuid": "^9.0.0"
52
52
  },
53
53
  "devDependencies": {
54
- "@backstage/cli": "^0.27.1-next.2",
54
+ "@backstage/cli": "^0.28.0-next.0",
55
55
  "@types/lodash": "^4.14.151"
56
56
  },
57
57
  "configSchema": "config.d.ts"