@backstage/plugin-catalog-backend-module-ldap 0.10.0-next.2 → 0.10.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 +19 -0
- package/dist/processors/LdapOrgEntityProvider.cjs.js +1 -3
- package/dist/processors/LdapOrgEntityProvider.cjs.js.map +1 -1
- package/dist/processors/LdapOrgReaderProcessor.cjs.js +1 -3
- package/dist/processors/LdapOrgReaderProcessor.cjs.js.map +1 -1
- package/package.json +18 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend-module-ldap
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 415aeb3: Add Support for Google LDAP Vendor
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 884a86c: Added a `dnCaseSensitive` flag to support LDAP servers with mixed-case attributes.
|
|
12
|
+
- 4e58bc7: Upgrade to uuid v11 internally
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- @backstage/config@1.3.0
|
|
15
|
+
- @backstage/types@1.2.0
|
|
16
|
+
- @backstage/plugin-catalog-node@1.14.0
|
|
17
|
+
- @backstage/backend-plugin-api@1.0.2
|
|
18
|
+
- @backstage/catalog-model@1.7.1
|
|
19
|
+
- @backstage/errors@1.2.5
|
|
20
|
+
- @backstage/plugin-catalog-common@1.1.1
|
|
21
|
+
|
|
3
22
|
## 0.10.0-next.2
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
|
@@ -129,9 +129,7 @@ class LdapOrgEntityProvider {
|
|
|
129
129
|
this.options.provider.vendor,
|
|
130
130
|
{
|
|
131
131
|
groupTransformer: this.options.groupTransformer,
|
|
132
|
-
userTransformer: this.options.userTransformer
|
|
133
|
-
logger
|
|
134
|
-
}
|
|
132
|
+
userTransformer: this.options.userTransformer}
|
|
135
133
|
);
|
|
136
134
|
const { markCommitComplete } = markReadComplete({ users, groups });
|
|
137
135
|
await this.connection.applyMutation({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LdapOrgEntityProvider.cjs.js","sources":["../../src/processors/LdapOrgEntityProvider.ts"],"sourcesContent":["/*\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"],"names":["readProviderConfigs","config","readLdapLegacyConfig","client","LdapClient","readLdapOrg","uuid","LDAP_DN_ANNOTATION","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LdapOrgEntityProvider.cjs.js","sources":["../../src/processors/LdapOrgEntityProvider.ts"],"sourcesContent":["/*\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"],"names":["readProviderConfigs","config","readLdapLegacyConfig","client","LdapClient","readLdapOrg","uuid","LDAP_DN_ANNOTATION","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION"],"mappings":"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"}
|
|
@@ -52,9 +52,7 @@ class LdapOrgReaderProcessor {
|
|
|
52
52
|
provider.vendor,
|
|
53
53
|
{
|
|
54
54
|
groupTransformer: this.groupTransformer,
|
|
55
|
-
userTransformer: this.userTransformer
|
|
56
|
-
logger: this.logger
|
|
57
|
-
}
|
|
55
|
+
userTransformer: this.userTransformer}
|
|
58
56
|
);
|
|
59
57
|
const duration = ((Date.now() - startTimestamp) / 1e3).toFixed(1);
|
|
60
58
|
this.logger.debug(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LdapOrgReaderProcessor.cjs.js","sources":["../../src/processors/LdapOrgReaderProcessor.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 { 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"],"names":["config","readLdapLegacyConfig","client","LdapClient","readLdapOrg","processingResult"],"mappings":";;;;;;;;AAsCO,MAAM,sBAAmD,CAAA;AAAA,EAC7C,SAAA;AAAA,EACA,MAAA;AAAA,EACA,gBAAA;AAAA,EACA,eAAA;AAAA,EAEjB,OAAO,UACL,CAAA,UAAA,EACA,OAKA,EAAA;AAEA,IAAA,MAAMA,WACJ,UAAW,CAAA,iBAAA,CAAkB,MAAM,CACnC,IAAA,UAAA,CAAW,kBAAkB,4BAA4B,CAAA;AAC3D,IAAA,OAAO,IAAI,sBAAuB,CAAA;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,SAAW,EAAAA,QAAA,GAASC,2BAAqB,CAAAD,QAAM,IAAI;AAAC,KACrD,CAAA;AAAA;AACH,EAEA,YAAY,OAKT,EAAA;AACD,IAAA,IAAA,CAAK,YAAY,OAAQ,CAAA,SAAA;AACzB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,mBAAmB,OAAQ,CAAA,gBAAA;AAChC,IAAA,IAAA,CAAK,kBAAkB,OAAQ,CAAA,eAAA;AAAA;AACjC,EAEA,gBAA2B,GAAA;AACzB,IAAO,OAAA,wBAAA;AAAA;AACT,EAEA,MAAM,YAAA,CACJ,QACA,EAAA,SAAA,EACA,IACkB,EAAA;AAClB,IAAI,IAAA,QAAA,CAAS,SAAS,UAAY,EAAA;AAChC,MAAO,OAAA,KAAA;AAAA;AAGT,IAAM,MAAA,QAAA,GAAW,KAAK,SAAU,CAAA,IAAA,CAAK,OAAK,QAAS,CAAA,MAAA,KAAW,EAAE,MAAM,CAAA;AACtE,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,6CAAA,EAAgD,SAAS,MAAM,CAAA,kEAAA;AAAA,OACjE;AAAA;AAIF,IAAM,MAAA,cAAA,GAAiB,KAAK,GAAI,EAAA;AAChC,IAAK,IAAA,CAAA,MAAA,CAAO,KAAK,+BAA+B,CAAA;AAKhD,IAAM,MAAAE,QAAA,GAAS,MAAMC,iBAAW,CAAA,MAAA;AAAA,MAC9B,IAAK,CAAA,MAAA;AAAA,MACL,QAAS,CAAA,MAAA;AAAA,MACT,QAAS,CAAA,IAAA;AAAA,MACT,QAAS,CAAA;AAAA,KACX;AACA,IAAA,MAAM,EAAE,KAAA,EAAO,MAAO,EAAA,GAAI,MAAMC,gBAAA;AAAA,MAC9BF,QAAA;AAAA,MACA,QAAS,CAAA,KAAA;AAAA,MACT,QAAS,CAAA,MAAA;AAAA,MACT,QAAS,CAAA,MAAA;AAAA,MACT;AAAA,QACE,kBAAkB,IAAK,CAAA,gBAAA;AAAA,QACvB,iBAAiB,IAAK,CAAA,
|
|
1
|
+
{"version":3,"file":"LdapOrgReaderProcessor.cjs.js","sources":["../../src/processors/LdapOrgReaderProcessor.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 { 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"],"names":["config","readLdapLegacyConfig","client","LdapClient","readLdapOrg","processingResult"],"mappings":";;;;;;;;AAsCO,MAAM,sBAAmD,CAAA;AAAA,EAC7C,SAAA;AAAA,EACA,MAAA;AAAA,EACA,gBAAA;AAAA,EACA,eAAA;AAAA,EAEjB,OAAO,UACL,CAAA,UAAA,EACA,OAKA,EAAA;AAEA,IAAA,MAAMA,WACJ,UAAW,CAAA,iBAAA,CAAkB,MAAM,CACnC,IAAA,UAAA,CAAW,kBAAkB,4BAA4B,CAAA;AAC3D,IAAA,OAAO,IAAI,sBAAuB,CAAA;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,SAAW,EAAAA,QAAA,GAASC,2BAAqB,CAAAD,QAAM,IAAI;AAAC,KACrD,CAAA;AAAA;AACH,EAEA,YAAY,OAKT,EAAA;AACD,IAAA,IAAA,CAAK,YAAY,OAAQ,CAAA,SAAA;AACzB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA;AACtB,IAAA,IAAA,CAAK,mBAAmB,OAAQ,CAAA,gBAAA;AAChC,IAAA,IAAA,CAAK,kBAAkB,OAAQ,CAAA,eAAA;AAAA;AACjC,EAEA,gBAA2B,GAAA;AACzB,IAAO,OAAA,wBAAA;AAAA;AACT,EAEA,MAAM,YAAA,CACJ,QACA,EAAA,SAAA,EACA,IACkB,EAAA;AAClB,IAAI,IAAA,QAAA,CAAS,SAAS,UAAY,EAAA;AAChC,MAAO,OAAA,KAAA;AAAA;AAGT,IAAM,MAAA,QAAA,GAAW,KAAK,SAAU,CAAA,IAAA,CAAK,OAAK,QAAS,CAAA,MAAA,KAAW,EAAE,MAAM,CAAA;AACtE,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,6CAAA,EAAgD,SAAS,MAAM,CAAA,kEAAA;AAAA,OACjE;AAAA;AAIF,IAAM,MAAA,cAAA,GAAiB,KAAK,GAAI,EAAA;AAChC,IAAK,IAAA,CAAA,MAAA,CAAO,KAAK,+BAA+B,CAAA;AAKhD,IAAM,MAAAE,QAAA,GAAS,MAAMC,iBAAW,CAAA,MAAA;AAAA,MAC9B,IAAK,CAAA,MAAA;AAAA,MACL,QAAS,CAAA,MAAA;AAAA,MACT,QAAS,CAAA,IAAA;AAAA,MACT,QAAS,CAAA;AAAA,KACX;AACA,IAAA,MAAM,EAAE,KAAA,EAAO,MAAO,EAAA,GAAI,MAAMC,gBAAA;AAAA,MAC9BF,QAAA;AAAA,MACA,QAAS,CAAA,KAAA;AAAA,MACT,QAAS,CAAA,MAAA;AAAA,MACT,QAAS,CAAA,MAAA;AAAA,MACT;AAAA,QACE,kBAAkB,IAAK,CAAA,gBAAA;AAAA,QACvB,iBAAiB,IAAK,CAAA,eAExB;AAAA,KACF;AAEA,IAAA,MAAM,aAAa,IAAK,CAAA,GAAA,KAAQ,cAAkB,IAAA,GAAA,EAAM,QAAQ,CAAC,CAAA;AACjE,IAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,MACV,QAAQ,KAAM,CAAA,MAAM,mBAAmB,MAAO,CAAA,MAAM,mBAAmB,QAAQ,CAAA,QAAA;AAAA,KACjF;AAGA,IAAA,KAAA,MAAW,SAAS,MAAQ,EAAA;AAC1B,MAAA,IAAA,CAAKG,kCAAiB,CAAA,MAAA,CAAO,QAAU,EAAA,KAAK,CAAC,CAAA;AAAA;AAE/C,IAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,MAAA,IAAA,CAAKA,kCAAiB,CAAA,MAAA,CAAO,QAAU,EAAA,IAAI,CAAC,CAAA;AAAA;AAG9C,IAAO,OAAA,IAAA;AAAA;AAEX;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-catalog-backend-module-ldap",
|
|
3
|
-
"version": "0.10.0
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A Backstage catalog backend module that helps integrate towards LDAP",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin-module",
|
|
@@ -38,21 +38,28 @@
|
|
|
38
38
|
"test": "backstage-cli package test"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@backstage/backend-plugin-api": "1.0.2
|
|
42
|
-
"@backstage/catalog-model": "1.7.
|
|
43
|
-
"@backstage/config": "1.
|
|
44
|
-
"@backstage/errors": "1.2.
|
|
45
|
-
"@backstage/plugin-catalog-common": "1.1.
|
|
46
|
-
"@backstage/plugin-catalog-node": "1.14.0
|
|
47
|
-
"@backstage/types": "1.
|
|
41
|
+
"@backstage/backend-plugin-api": "^1.0.2",
|
|
42
|
+
"@backstage/catalog-model": "^1.7.1",
|
|
43
|
+
"@backstage/config": "^1.3.0",
|
|
44
|
+
"@backstage/errors": "^1.2.5",
|
|
45
|
+
"@backstage/plugin-catalog-common": "^1.1.1",
|
|
46
|
+
"@backstage/plugin-catalog-node": "^1.14.0",
|
|
47
|
+
"@backstage/types": "^1.2.0",
|
|
48
48
|
"@types/ldapjs": "^2.2.5",
|
|
49
49
|
"ldapjs": "^2.3.3",
|
|
50
50
|
"lodash": "^4.17.21",
|
|
51
|
-
"uuid": "^
|
|
51
|
+
"uuid": "^11.0.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@backstage/cli": "0.29.0
|
|
54
|
+
"@backstage/cli": "^0.29.0",
|
|
55
55
|
"@types/lodash": "^4.14.151"
|
|
56
56
|
},
|
|
57
|
-
"configSchema": "config.d.ts"
|
|
57
|
+
"configSchema": "config.d.ts",
|
|
58
|
+
"typesVersions": {
|
|
59
|
+
"*": {
|
|
60
|
+
"index": [
|
|
61
|
+
"dist/index.d.ts"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
58
65
|
}
|