From 37b92259da2a6f92bd6fcd9f5a69a10caf49dea0 Mon Sep 17 00:00:00 2001 From: Craig Tracey Date: Mon, 23 Oct 2023 17:15:25 -0400 Subject: [PATCH] Update Keycloak plugin for dynamic backend Add dynamic backend module capabilities for the Keycloak backend plugin. Signed-off-by: Craig Tracey --- plugins/keycloak-backend/package.json | 26 +++++- plugins/keycloak-backend/src/alpha.ts | 24 ++++++ ...atalogModuleKeycloakEntityProvider.test.ts | 79 +++++++++++++++++++ .../catalogModuleKeycloakEntityProvider.ts | 53 +++++++++++++ plugins/keycloak-backend/src/module/index.ts | 17 ++++ 5 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 plugins/keycloak-backend/src/alpha.ts create mode 100644 plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts create mode 100644 plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts create mode 100644 plugins/keycloak-backend/src/module/index.ts diff --git a/plugins/keycloak-backend/package.json b/plugins/keycloak-backend/package.json index 444cbda8d0b..5b81626d183 100644 --- a/plugins/keycloak-backend/package.json +++ b/plugins/keycloak-backend/package.json @@ -11,7 +11,22 @@ "types": "dist/index.d.ts" }, "backstage": { - "role": "backend-plugin" + "role": "backend-plugin-module" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } }, "scripts": { "start": "opener http://localhost:8080/admin/master/console/#/janus-realm && opener http://localhost:7007/catalog/entities && turbo run start:plugin start:keycloak", @@ -23,10 +38,12 @@ "test": "backstage-cli package test --passWithNoTests --coverage", "clean": "backstage-cli package clean", "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" + "postpack": "backstage-cli package postpack", + "export-dynamic": "janus-cli package export-dynamic-plugin" }, "dependencies": { "@backstage/backend-common": "^0.19.8", + "@backstage/backend-plugin-api": "^0.6.6", "@backstage/backend-tasks": "^0.5.11", "@backstage/catalog-model": "^1.4.3", "@backstage/config": "^1.1.1", @@ -38,11 +55,13 @@ }, "devDependencies": { "@backstage/backend-app-api": "0.5.6", + "@backstage/backend-test-utils": "^0.2.7", "@backstage/cli": "0.23.0", "@backstage/plugin-auth-node": "0.4.0", "@backstage/plugin-catalog-backend": "1.14.0", "@backstage/plugin-permission-common": "0.7.9", "@backstage/plugin-permission-node": "0.7.17", + "@janus-idp/cli": "1.1.0", "@types/lodash": "4.14.200", "@types/supertest": "2.0.14", "@types/uuid": "9.0.5", @@ -54,6 +73,9 @@ }, "files": [ "dist", + "dist-dynamic/*.*", + "dist-dynamic/dist/**", + "dist-dynamic/alpha/*", "config.d.ts" ], "configSchema": "config.d.ts", diff --git a/plugins/keycloak-backend/src/alpha.ts b/plugins/keycloak-backend/src/alpha.ts new file mode 100644 index 00000000000..fa76fe0079e --- /dev/null +++ b/plugins/keycloak-backend/src/alpha.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Janus IDP 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. + */ + +/** + * The Keycloak backend plugin integrates Keycloak into Backstage + * + * @packageDocumentation + */ + +export * from './module'; +export { default } from './module'; diff --git a/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts b/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts new file mode 100644 index 00000000000..72a61db78a2 --- /dev/null +++ b/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The Janus IDP 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 { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { EntityProvider } from '@backstage/plugin-catalog-node'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; + +import { catalogModuleKeycloakEntityProvider } from './catalogModuleKeycloakEntityProvider'; + +describe('catalogModuleKeycloakEntityProvider', () => { + it('should register provider at the catalog extension point', async () => { + let addedProviders: Array | undefined; + let usedSchedule: TaskScheduleDefinition | undefined; + + const extensionPoint = { + addEntityProvider: (providers: any) => { + addedProviders = providers; + }, + }; + const runner = jest.fn(); + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { + usedSchedule = schedule; + return { run: runner }; + }, + }); + + const config = { + catalog: { + providers: { + keycloakOrg: { + default: { + baseUrl: 'https://example.com/auth', + schedule: { + frequency: { + minutes: 3, + }, + timeout: { + minutes: 7, + }, + }, + }, + }, + }, + }, + }; + + await startTestBackend({ + extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + features: [ + catalogModuleKeycloakEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + scheduler.factory, + ], + }); + + expect(usedSchedule?.frequency.minutes).toEqual(3); + expect(usedSchedule?.timeout.minutes).toEqual(7); + expect(addedProviders?.length).toEqual(1); + expect(addedProviders?.pop()?.getProviderName()).toEqual( + 'KeycloakOrgEntityProvider:default', + ); + expect(runner).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts b/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts new file mode 100644 index 00000000000..389dec2c044 --- /dev/null +++ b/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2023 The Janus IDP 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 { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; + +import { KeycloakOrgEntityProvider } from '../providers'; + +/** + * Registers the `KeycloakEntityProvider` with the catalog processing extension point. + * + * @alpha + */ +export const catalogModuleKeycloakEntityProvider = createBackendModule({ + pluginId: 'catalog', + moduleId: 'keycloakEntityProvider', + register(env) { + env.registerInit({ + deps: { + catalog: catalogProcessingExtensionPoint, + config: coreServices.rootConfig, + logger: coreServices.logger, + scheduler: coreServices.scheduler, + }, + async init({ catalog, config, logger, scheduler }) { + catalog.addEntityProvider( + KeycloakOrgEntityProvider.fromConfig(config, { + id: 'development', + logger: loggerToWinstonLogger(logger), + scheduler, + }), + ); + }, + }); + }, +}); diff --git a/plugins/keycloak-backend/src/module/index.ts b/plugins/keycloak-backend/src/module/index.ts new file mode 100644 index 00000000000..58200963db8 --- /dev/null +++ b/plugins/keycloak-backend/src/module/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Janus IDP 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 { catalogModuleKeycloakEntityProvider as default } from './catalogModuleKeycloakEntityProvider';