diff --git a/.changeset/tricky-carrots-lick.md b/.changeset/tricky-carrots-lick.md new file mode 100644 index 0000000000..dd5c2d4288 --- /dev/null +++ b/.changeset/tricky-carrots-lick.md @@ -0,0 +1,24 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Move `LdapOrgReaderProcessor` from `@backstage/plugin-catalog-backend` +to `@backstage/plugin-catalog-backend-module-ldap`. + +The `LdapOrgReaderProcessor` isn't registered by default anymore, if +you want to continue using it you have to register it manually at the catalog +builder: + +1. Add dependency to `@backstage/plugin-catalog-backend-module-ldap` to the `package.json` of your backend. +2. Add the processor to the catalog builder: + +```typescript +// packages/backend/src/plugins/catalog.ts +builder.addProcessor( + LdapOrgReaderProcessor.fromConfig(config, { + logger, + }), +); +``` + +For more configuration details, see the [README of the `@backstage/plugin-catalog-backend-module-ldap` package](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-ldap/README.md). diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 0fd00e5737..846e050c49 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -122,6 +122,7 @@ Knex kubectl kubernetes kubernetes +ldap learnings Leasot lerna diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md index 24a4335b8b..836601971c 100644 --- a/docs/integrations/ldap/org.md +++ b/docs/integrations/ldap/org.md @@ -14,19 +14,25 @@ entities that mirror your org setup. ## Installation -The processor that performs the import, `LdapOrgReaderProcessor`, comes -installed with the default setup of Backstage. +1. The processor is not installed by default, therefore you have to add a + dependency to `@backstage/plugin-catalog-backend-module-ldap` to your backend + package. -If you replace the set of processors in your installation using that facility of -the catalog builder class, you can import and add it as follows. +```bash +# From your Backstage root directory +cd packages/backend +yarn add @backstage/plugin-catalog-backend-module-ldap +``` -```ts -// Typically in packages/backend/src/plugins/catalog.ts -import { LdapOrgReaderProcessor } from '@backstage/plugin-catalog-backend'; +2. The `LdapOrgReaderProcessor` is not registered by default, so you have to + register it in the catalog plugin: -builder.replaceProcessors( - LdapOrgReaderProcessor.fromConfig(config, { logger }), - // ... +```typescript +// packages/backend/src/plugins/catalog.ts +builder.addProcessor( + LdapOrgReaderProcessor.fromConfig(config, { + logger, + }), ); ``` diff --git a/plugins/catalog-backend-module-ldap/.eslintrc.js b/plugins/catalog-backend-module-ldap/.eslintrc.js new file mode 100644 index 0000000000..16a033dbc6 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint.backend')], +}; diff --git a/plugins/catalog-backend-module-ldap/README.md b/plugins/catalog-backend-module-ldap/README.md new file mode 100644 index 0000000000..2bc34ba949 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/README.md @@ -0,0 +1,10 @@ +# Catalog Backend Module for LDAP + +This is an extension module to the plugin-catalog-backend plugin, providing an LdapOrgReaderProcessor that can be +used to ingest organization data from an LDAP server. This processor is useful if you want to import users and +groups from your Active Directory or another LDAP compatible server. + +## Getting started + +See [Backstage documentation](https://backstage.io/docs/integrations/ldap/org) for details on how to install +and configure the plugin. diff --git a/plugins/catalog-backend-module-ldap/api-report.md b/plugins/catalog-backend-module-ldap/api-report.md new file mode 100644 index 0000000000..d5e9d731ea --- /dev/null +++ b/plugins/catalog-backend-module-ldap/api-report.md @@ -0,0 +1,72 @@ +## API Report File for "@backstage/plugin-catalog-backend-module-ldap" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { CatalogProcessor } from '@backstage/plugin-catalog-backend'; +import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend'; +import { Client } from 'ldapjs'; +import { Config } from '@backstage/config'; +import { GroupEntity } from '@backstage/catalog-model'; +import { JsonValue } from '@backstage/config'; +import { LocationSpec } from '@backstage/catalog-model'; +import { Logger } from 'winston'; +import { SearchEntry } from 'ldapjs'; +import { SearchOptions } from 'ldapjs'; +import { UserEntity } from '@backstage/catalog-model'; + +// @public +export const LDAP_DN_ANNOTATION = "backstage.io/ldap-dn"; + +// @public +export const LDAP_RDN_ANNOTATION = "backstage.io/ldap-rdn"; + +// @public +export const LDAP_UUID_ANNOTATION = "backstage.io/ldap-uuid"; + +// @public +export class LdapClient { + constructor(client: Client); + // (undocumented) + static create(logger: Logger, target: string, bind?: BindConfig): Promise; + getRootDSE(): Promise; + getVendor(): Promise; + search(dn: string, options: SearchOptions): Promise; + } + +// @public +export class LdapOrgReaderProcessor implements CatalogProcessor { + constructor(options: { + providers: LdapProviderConfig[]; + logger: Logger; + }); + // (undocumented) + static fromConfig(config: Config, options: { + logger: Logger; + }): LdapOrgReaderProcessor; + // (undocumented) + readLocation(location: LocationSpec, _optional: boolean, emit: CatalogProcessorEmit): Promise; +} + +// @public +export type LdapProviderConfig = { + target: string; + bind?: BindConfig; + users: UserConfig; + groups: GroupConfig; +}; + +// @public +export function readLdapConfig(config: Config): LdapProviderConfig[]; + +// @public +export function readLdapOrg(client: LdapClient, userConfig: UserConfig, groupConfig: GroupConfig): Promise<{ + users: UserEntity[]; + groups: GroupEntity[]; +}>; + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/plugins/catalog-backend-module-ldap/config.d.ts b/plugins/catalog-backend-module-ldap/config.d.ts new file mode 100644 index 0000000000..57781fd711 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/config.d.ts @@ -0,0 +1,234 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JsonValue } from '@backstage/config'; + +export interface Config { + /** + * Configuration options for the catalog plugin. + */ + catalog?: { + /** + * List of processor-specific options and attributes + */ + processors?: { + /** + * LdapOrgReaderProcessor configuration + */ + ldapOrg?: { + /** + * The configuration parameters for each single LDAP provider. + */ + providers: Array<{ + /** + * The prefix of the target that this matches on, e.g. + * "ldaps://ds.example.net", with no trailing slash. + */ + target: string; + + /** + * The settings to use for the bind command. If none are specified, + * the bind command is not issued. + */ + bind?: { + /** + * The DN of the user to auth as. + * + * E.g. "uid=ldap-robot,ou=robots,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The secret of the user to auth as (its password). + * + * @visibility secret + */ + secret: string; + }; + + /** + * The settings that govern the reading and interpretation of users. + */ + users: { + /** + * The DN under which users are stored. + * + * E.g. "ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The search options to use. The default is scope "one" and + * attributes "*" and "+". + * + * It is common to want to specify a filter, to narrow down the set + * of matching items. + */ + options: { + scope?: 'base' | 'one' | 'sub'; + filter?: string; + attributes?: string | string[]; + paged?: + | boolean + | { + pageSize?: number; + pagePause?: boolean; + }; + }; + /** + * JSON paths (on a.b.c form) and hard coded values to set on those + * paths. + * + * This can be useful for example if you want to hard code a + * namespace or similar on the generated entities. + */ + set?: { [key: string]: JsonValue }; + /** + * Mappings from well known entity fields, to LDAP attribute names + */ + map?: { + /** + * The name of the attribute that holds the relative + * distinguished name of each entry. Defaults to "uid". + */ + rdn?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.name field of the entity. Defaults to "uid". + */ + name?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.description field of the entity. + */ + description?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.displayName field of the entity. Defaults to + * "cn". + */ + displayName?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.email field of the entity. Defaults to + * "mail". + */ + email?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.picture field of the entity. + */ + picture?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.memberOf field of the entity. Defaults to "memberOf". + */ + memberOf?: string; + }; + }; + + /** + * The settings that govern the reading and interpretation of groups. + */ + groups: { + /** + * The DN under which groups are stored. + * + * E.g. "ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The search options to use. The default is scope "one" and + * attributes "*" and "+". + * + * It is common to want to specify a filter, to narrow down the set + * of matching items. + */ + options: { + scope?: 'base' | 'one' | 'sub'; + filter?: string; + attributes?: string | string[]; + paged?: + | boolean + | { + pageSize?: number; + pagePause?: boolean; + }; + }; + /** + * JSON paths (on a.b.c form) and hard coded values to set on those + * paths. + * + * This can be useful for example if you want to hard code a + * namespace or similar on the generated entities. + */ + set?: { [key: string]: JsonValue }; + /** + * Mappings from well known entity fields, to LDAP attribute names + */ + map?: { + /** + * The name of the attribute that holds the relative + * distinguished name of each entry. Defaults to "cn". + */ + rdn?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.name field of the entity. Defaults to "cn". + */ + name?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.description field of the entity. Defaults to + * "description". + */ + description?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.type field of the entity. Defaults to "groupType". + */ + type?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.displayName field of the entity. Defaults to + * "cn". + */ + displayName?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.email field of the entity. + */ + email?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.picture field of the entity. + */ + picture?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.parent field of the entity. Defaults to "memberOf". + */ + memberOf?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.children field of the entity. Defaults to "member". + */ + members?: string; + }; + }; + }>; + }; + }; + }; +} diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json new file mode 100644 index 0000000000..d8a5545368 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/package.json @@ -0,0 +1,50 @@ +{ + "name": "@backstage/plugin-catalog-backend-module-ldap", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/catalog-backend-module-ldap" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "build": "backstage-cli backend:build", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/catalog-model": "^0.8.3", + "@backstage/config": "^0.1.5", + "@backstage/plugin-catalog-backend": "^0.10.2", + "@types/ldapjs": "^1.0.10", + "ldapjs": "^2.2.0", + "lodash": "^4.17.15", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/cli": "^0.7.1", + "@backstage/test-utils": "^0.1.13", + "@types/lodash": "^4.14.151", + "msw": "^0.21.2" + }, + "files": [ + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/catalog-backend-module-ldap/src/index.ts b/plugins/catalog-backend-module-ldap/src/index.ts new file mode 100644 index 0000000000..25353df4c4 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/src/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './processors'; +export * from './ldap'; diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/client.ts b/plugins/catalog-backend-module-ldap/src/ldap/client.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/client.ts rename to plugins/catalog-backend-module-ldap/src/ldap/client.ts diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/config.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/config.test.ts rename to plugins/catalog-backend-module-ldap/src/ldap/config.test.ts diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts similarity index 99% rename from plugins/catalog-backend/src/ingestion/processors/ldap/config.ts rename to plugins/catalog-backend-module-ldap/src/ldap/config.ts index 70aa729e84..eefe43f97a 100644 --- a/plugins/catalog-backend/src/ingestion/processors/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -17,7 +17,7 @@ import { Config, JsonValue } from '@backstage/config'; import { SearchOptions } from 'ldapjs'; import mergeWith from 'lodash/mergeWith'; -import { RecursivePartial } from '../../../util'; +import { RecursivePartial } from '@backstage/plugin-catalog-backend'; /** * The configuration parameters for a single LDAP provider. diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/constants.ts b/plugins/catalog-backend-module-ldap/src/ldap/constants.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/constants.ts rename to plugins/catalog-backend-module-ldap/src/ldap/constants.ts diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/index.ts b/plugins/catalog-backend-module-ldap/src/ldap/index.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/index.ts rename to plugins/catalog-backend-module-ldap/src/ldap/index.ts diff --git a/plugins/catalog-backend-module-ldap/src/ldap/org.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/org.test.ts new file mode 100644 index 0000000000..254f511c4f --- /dev/null +++ b/plugins/catalog-backend-module-ldap/src/ldap/org.test.ts @@ -0,0 +1,94 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { buildMemberOf, buildOrgHierarchy } from './org'; + +function g( + name: string, + parent: string | undefined, + children: string[], +): GroupEntity { + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name }, + spec: { type: 'team', parent, children }, + }; +} + +describe('buildOrgHierarchy', () => { + it('adds groups to their parent.children', () => { + const a = g('a', undefined, []); + const b = g('b', 'a', []); + const c = g('c', 'b', []); + const d = g('d', 'a', []); + buildOrgHierarchy([a, b, c, d]); + expect(a.spec.children).toEqual(expect.arrayContaining(['b', 'd'])); + expect(b.spec.children).toEqual(expect.arrayContaining(['c'])); + expect(c.spec.children).toEqual([]); + expect(d.spec.children).toEqual([]); + }); + + it('sets parent of groups children', () => { + const a = g('a', undefined, ['b', 'd']); + const b = g('b', undefined, ['c']); + const c = g('c', undefined, []); + const d = g('d', undefined, []); + buildOrgHierarchy([a, b, c, d]); + expect(a.spec.parent).toBeUndefined(); + expect(b.spec.parent).toBe('a'); + expect(c.spec.parent).toBe('b'); + expect(d.spec.parent).toBe('a'); + }); +}); + +describe('buildMemberOf', () => { + it('fills indirect member of groups', () => { + const a = g('a', undefined, []); + const b = g('b', 'a', []); + const c = g('c', 'b', []); + const u: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { name: 'n' }, + spec: { profile: {}, memberOf: ['c'] }, + }; + + const groups = [a, b, c]; + buildOrgHierarchy(groups); + buildMemberOf(groups, [u]); + expect(u.spec.memberOf).toEqual(expect.arrayContaining(['a', 'b', 'c'])); + }); + + it('takes group spec.members into account', () => { + const a = g('a', undefined, []); + const b = g('b', 'a', []); + const c = g('c', 'b', []); + c.spec.members = ['n']; + const u: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { name: 'n' }, + spec: { profile: {}, memberOf: [] }, + }; + + const groups = [a, b, c]; + buildOrgHierarchy(groups); + buildMemberOf(groups, [u]); + expect(u.spec.memberOf).toEqual(expect.arrayContaining(['a', 'b', 'c'])); + }); +}); diff --git a/plugins/catalog-backend-module-ldap/src/ldap/org.ts b/plugins/catalog-backend-module-ldap/src/ldap/org.ts new file mode 100644 index 0000000000..fe59451a9d --- /dev/null +++ b/plugins/catalog-backend-module-ldap/src/ldap/org.ts @@ -0,0 +1,87 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; + +// TODO: Copied from plugin-catalog-backend, but we could also export them from +// there. Or move them to catalog-model. + +export function buildOrgHierarchy(groups: GroupEntity[]) { + const groupsByName = new Map(groups.map(g => [g.metadata.name, g])); + + // + // Make sure that g.parent.children contain g + // + + for (const group of groups) { + const selfName = group.metadata.name; + const parentName = group.spec.parent; + if (parentName) { + const parent = groupsByName.get(parentName); + if (parent && !parent.spec.children.includes(selfName)) { + parent.spec.children.push(selfName); + } + } + } + + // + // Make sure that g.children.parent is g + // + + for (const group of groups) { + const selfName = group.metadata.name; + for (const childName of group.spec.children) { + const child = groupsByName.get(childName); + if (child && !child.spec.parent) { + child.spec.parent = selfName; + } + } + } +} + +// Ensure that users have their transitive group memberships. Requires that +// the groups were previously processed with buildOrgHierarchy() +export function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) { + const groupsByName = new Map(groups.map(g => [g.metadata.name, g])); + + users.forEach(user => { + const transitiveMemberOf = new Set(); + + const todo = [ + ...user.spec.memberOf, + ...groups + .filter(g => g.spec.members?.includes(user.metadata.name)) + .map(g => g.metadata.name), + ]; + + for (;;) { + const current = todo.pop(); + if (!current) { + break; + } + + if (!transitiveMemberOf.has(current)) { + transitiveMemberOf.add(current); + const group = groupsByName.get(current); + if (group?.spec.parent) { + todo.push(group.spec.parent); + } + } + } + + user.spec.memberOf = [...transitiveMemberOf]; + }); +} diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts similarity index 99% rename from plugins/catalog-backend/src/ingestion/processors/ldap/read.test.ts rename to plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index e043a644ce..b357b6b408 100644 --- a/plugins/catalog-backend/src/ingestion/processors/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -17,7 +17,7 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { SearchEntry } from 'ldapjs'; import merge from 'lodash/merge'; -import { RecursivePartial } from '../../../util'; +import { RecursivePartial } from '@backstage/plugin-catalog-backend'; import { LdapClient } from './client'; import { GroupConfig, UserConfig } from './config'; import { diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts similarity index 99% rename from plugins/catalog-backend/src/ingestion/processors/ldap/read.ts rename to plugins/catalog-backend-module-ldap/src/ldap/read.ts index fb740e5e0a..a662b36d87 100644 --- a/plugins/catalog-backend/src/ingestion/processors/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -17,7 +17,7 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { SearchEntry } from 'ldapjs'; import lodashSet from 'lodash/set'; -import { buildOrgHierarchy } from '../util/org'; +import { buildOrgHierarchy } from './org'; import { LdapClient } from './client'; import { GroupConfig, UserConfig } from './config'; import { diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/util.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/util.test.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/util.test.ts rename to plugins/catalog-backend-module-ldap/src/ldap/util.test.ts diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/util.ts b/plugins/catalog-backend-module-ldap/src/ldap/util.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/util.ts rename to plugins/catalog-backend-module-ldap/src/ldap/util.ts diff --git a/plugins/catalog-backend/src/ingestion/processors/ldap/vendors.ts b/plugins/catalog-backend-module-ldap/src/ldap/vendors.ts similarity index 100% rename from plugins/catalog-backend/src/ingestion/processors/ldap/vendors.ts rename to plugins/catalog-backend-module-ldap/src/ldap/vendors.ts diff --git a/plugins/catalog-backend/src/ingestion/processors/LdapOrgReaderProcessor.ts b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts similarity index 95% rename from plugins/catalog-backend/src/ingestion/processors/LdapOrgReaderProcessor.ts rename to plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts index ab13e1f19f..79c0ed6964 100644 --- a/plugins/catalog-backend/src/ingestion/processors/LdapOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts @@ -22,9 +22,12 @@ import { LdapProviderConfig, readLdapConfig, readLdapOrg, -} from './ldap'; -import * as results from './results'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; +} from '../ldap'; +import { + CatalogProcessor, + CatalogProcessorEmit, + results, +} from '@backstage/plugin-catalog-backend'; /** * Extracts teams and users out of an LDAP server. diff --git a/plugins/catalog-backend-module-ldap/src/processors/index.ts b/plugins/catalog-backend-module-ldap/src/processors/index.ts new file mode 100644 index 0000000000..6e3f413085 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/src/processors/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { LdapOrgReaderProcessor } from './LdapOrgReaderProcessor'; diff --git a/plugins/catalog-backend-module-ldap/src/setupTests.ts b/plugins/catalog-backend-module-ldap/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/catalog-backend-module-ldap/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/catalog-backend/config.d.ts b/plugins/catalog-backend/config.d.ts index 04f76e06c7..e00e532622 100644 --- a/plugins/catalog-backend/config.d.ts +++ b/plugins/catalog-backend/config.d.ts @@ -145,211 +145,6 @@ export interface Config { }>; }; - /** - * LdapOrgReaderProcessor configuration - */ - ldapOrg?: { - /** - * The configuration parameters for each single LDAP provider. - */ - providers: Array<{ - /** - * The prefix of the target that this matches on, e.g. - * "ldaps://ds.example.net", with no trailing slash. - */ - target: string; - - /** - * The settings to use for the bind command. If none are specified, - * the bind command is not issued. - */ - bind?: { - /** - * The DN of the user to auth as. - * - * E.g. "uid=ldap-robot,ou=robots,ou=example,dc=example,dc=net" - */ - dn: string; - /** - * The secret of the user to auth as (its password). - * - * @visibility secret - */ - secret: string; - }; - - /** - * The settings that govern the reading and interpretation of users. - */ - users: { - /** - * The DN under which users are stored. - * - * E.g. "ou=people,ou=example,dc=example,dc=net" - */ - dn: string; - /** - * The search options to use. The default is scope "one" and - * attributes "*" and "+". - * - * It is common to want to specify a filter, to narrow down the set - * of matching items. - */ - options: { - scope?: 'base' | 'one' | 'sub'; - filter?: string; - attributes?: string | string[]; - paged?: - | boolean - | { - pageSize?: number; - pagePause?: boolean; - }; - }; - /** - * JSON paths (on a.b.c form) and hard coded values to set on those - * paths. - * - * This can be useful for example if you want to hard code a - * namespace or similar on the generated entities. - */ - set?: { [key: string]: JsonValue }; - /** - * Mappings from well known entity fields, to LDAP attribute names - */ - map?: { - /** - * The name of the attribute that holds the relative - * distinguished name of each entry. Defaults to "uid". - */ - rdn?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.name field of the entity. Defaults to "uid". - */ - name?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.description field of the entity. - */ - description?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.displayName field of the entity. Defaults to - * "cn". - */ - displayName?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.email field of the entity. Defaults to - * "mail". - */ - email?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.picture field of the entity. - */ - picture?: string; - /** - * The name of the attribute that shall be used for the values of - * the spec.memberOf field of the entity. Defaults to "memberOf". - */ - memberOf?: string; - }; - }; - - /** - * The settings that govern the reading and interpretation of groups. - */ - groups: { - /** - * The DN under which groups are stored. - * - * E.g. "ou=people,ou=example,dc=example,dc=net" - */ - dn: string; - /** - * The search options to use. The default is scope "one" and - * attributes "*" and "+". - * - * It is common to want to specify a filter, to narrow down the set - * of matching items. - */ - options: { - scope?: 'base' | 'one' | 'sub'; - filter?: string; - attributes?: string | string[]; - paged?: - | boolean - | { - pageSize?: number; - pagePause?: boolean; - }; - }; - /** - * JSON paths (on a.b.c form) and hard coded values to set on those - * paths. - * - * This can be useful for example if you want to hard code a - * namespace or similar on the generated entities. - */ - set?: { [key: string]: JsonValue }; - /** - * Mappings from well known entity fields, to LDAP attribute names - */ - map?: { - /** - * The name of the attribute that holds the relative - * distinguished name of each entry. Defaults to "cn". - */ - rdn?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.name field of the entity. Defaults to "cn". - */ - name?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.description field of the entity. Defaults to - * "description". - */ - description?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.type field of the entity. Defaults to "groupType". - */ - type?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.displayName field of the entity. Defaults to - * "cn". - */ - displayName?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.email field of the entity. - */ - email?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.picture field of the entity. - */ - picture?: string; - /** - * The name of the attribute that shall be used for the values of - * the spec.parent field of the entity. Defaults to "memberOf". - */ - memberOf?: string; - /** - * The name of the attribute that shall be used for the values of - * the spec.children field of the entity. Defaults to "member". - */ - members?: string; - }; - }; - }>; - }; - /** * AwsOrganizationCloudAccountProcessor configuration */ diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 1ad33b1589..144b30306a 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -39,7 +39,6 @@ "@backstage/search-common": "^0.1.2", "@octokit/graphql": "^4.5.8", "@types/express": "^4.17.6", - "@types/ldapjs": "^1.0.9", "aws-sdk": "^2.840.0", "codeowners-utils": "^1.0.2", "core-js": "^3.6.5", @@ -51,7 +50,6 @@ "git-url-parse": "^11.4.4", "glob": "^7.1.6", "knex": "^0.95.1", - "ldapjs": "^2.2.0", "lodash": "^4.17.15", "morgan": "^1.10.0", "p-limit": "^3.0.2", diff --git a/plugins/catalog-backend/src/ingestion/processors/index.ts b/plugins/catalog-backend/src/ingestion/processors/index.ts index 5abe117fd3..88258e3bb8 100644 --- a/plugins/catalog-backend/src/ingestion/processors/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/index.ts @@ -25,7 +25,6 @@ export { CodeOwnersProcessor } from './CodeOwnersProcessor'; export { FileReaderProcessor } from './FileReaderProcessor'; export { GithubDiscoveryProcessor } from './GithubDiscoveryProcessor'; export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor'; -export { LdapOrgReaderProcessor } from './LdapOrgReaderProcessor'; export { LocationEntityProcessor } from './LocationEntityProcessor'; export { PlaceholderProcessor } from './PlaceholderProcessor'; export type { PlaceholderResolver } from './PlaceholderProcessor'; diff --git a/plugins/catalog-backend/src/next/NextCatalogBuilder.ts b/plugins/catalog-backend/src/next/NextCatalogBuilder.ts index 041f07f4ed..a525dacd51 100644 --- a/plugins/catalog-backend/src/next/NextCatalogBuilder.ts +++ b/plugins/catalog-backend/src/next/NextCatalogBuilder.ts @@ -49,7 +49,6 @@ import { FileReaderProcessor, GithubDiscoveryProcessor, GithubOrgReaderProcessor, - LdapOrgReaderProcessor, PlaceholderProcessor, PlaceholderResolver, UrlReaderProcessor, @@ -371,7 +370,6 @@ export class NextCatalogBuilder { BitbucketDiscoveryProcessor.fromConfig(config, { logger }), GithubDiscoveryProcessor.fromConfig(config, { logger }), GithubOrgReaderProcessor.fromConfig(config, { logger }), - LdapOrgReaderProcessor.fromConfig(config, { logger }), new UrlReaderProcessor({ reader, logger }), CodeOwnersProcessor.fromConfig(config, { logger, reader }), new AnnotateLocationEntityProcessor({ integrations }), diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 7d3a5fcbf5..76b4af7450 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -48,7 +48,6 @@ import { GithubOrgReaderProcessor, HigherOrderOperation, HigherOrderOperations, - LdapOrgReaderProcessor, LocationEntityProcessor, LocationReaders, PlaceholderProcessor, @@ -317,7 +316,6 @@ export class CatalogBuilder { BitbucketDiscoveryProcessor.fromConfig(config, { logger }), GithubDiscoveryProcessor.fromConfig(config, { logger }), GithubOrgReaderProcessor.fromConfig(config, { logger }), - LdapOrgReaderProcessor.fromConfig(config, { logger }), new UrlReaderProcessor({ reader, logger }), CodeOwnersProcessor.fromConfig(config, { logger, reader }), new LocationEntityProcessor({ integrations }), diff --git a/yarn.lock b/yarn.lock index 8cb086c3d2..2a6827419c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6106,7 +6106,7 @@ "@types/koa-compose" "*" "@types/node" "*" -"@types/ldapjs@^1.0.9": +"@types/ldapjs@^1.0.10": version "1.0.10" resolved "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-1.0.10.tgz#bac705c9e154b97d69496b5213cc28dbe9715a37" integrity sha512-AMkMxkK/wjYtWebNH2O+rARfo7scBpW3T23g6zmGCwDgbyDbR79XWpcSqhPWdU+fChaF+I3dVyl9X2dT1CyI9w==