@backstage-community/plugin-catalog-backend-module-keycloak 3.17.1 → 3.18.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 +17 -0
- package/dist/module/catalogModuleKeycloakEntityProvider.cjs.js +2 -2
- package/dist/module/catalogModuleKeycloakEntityProvider.cjs.js.map +1 -1
- package/dist/providers/KeycloakOrgEntityProvider.cjs.js +9 -7
- package/dist/providers/KeycloakOrgEntityProvider.cjs.js.map +1 -1
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @backstage-community/plugin-catalog-backend-module-keycloak
|
|
2
2
|
|
|
3
|
+
## 3.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e8105de: Backstage version bump to v1.48.4
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 95eca61: Updated dependency `@types/lodash` to `4.17.24`.
|
|
12
|
+
- f788dc3: Updated dependency `@keycloak/keycloak-admin-client` to `26.5.6`.
|
|
13
|
+
|
|
14
|
+
## 3.17.2
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 5c9737a: Updated dependency `@keycloak/keycloak-admin-client` to `26.5.4`.
|
|
19
|
+
|
|
3
20
|
## 3.17.1
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var errors = require('@backstage/errors');
|
|
5
|
-
var
|
|
5
|
+
var pluginCatalogNode = require('@backstage/plugin-catalog-node');
|
|
6
6
|
var extensions = require('../extensions.cjs.js');
|
|
7
7
|
var KeycloakOrgEntityProvider = require('../providers/KeycloakOrgEntityProvider.cjs.js');
|
|
8
8
|
|
|
@@ -28,7 +28,7 @@ const catalogModuleKeycloakEntityProvider = backendPluginApi.createBackendModule
|
|
|
28
28
|
});
|
|
29
29
|
env.registerInit({
|
|
30
30
|
deps: {
|
|
31
|
-
catalog:
|
|
31
|
+
catalog: pluginCatalogNode.catalogProcessingExtensionPoint,
|
|
32
32
|
config: backendPluginApi.coreServices.rootConfig,
|
|
33
33
|
logger: backendPluginApi.coreServices.logger,
|
|
34
34
|
scheduler: backendPluginApi.coreServices.scheduler
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalogModuleKeycloakEntityProvider.cjs.js","sources":["../../src/module/catalogModuleKeycloakEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2024 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} from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node
|
|
1
|
+
{"version":3,"file":"catalogModuleKeycloakEntityProvider.cjs.js","sources":["../../src/module/catalogModuleKeycloakEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2024 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} from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\n\nimport { keycloakTransformerExtensionPoint } from '../extensions';\nimport type { GroupTransformer, UserTransformer } from '../lib/types';\nimport { KeycloakOrgEntityProvider } from '../providers';\n\n/**\n * Registers the `KeycloakEntityProvider` with the catalog processing extension point.\n *\n * @public\n */\nexport const catalogModuleKeycloakEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'catalog-backend-module-keycloak',\n register(env) {\n let userTransformer: UserTransformer | undefined;\n let groupTransformer: GroupTransformer | undefined;\n\n env.registerExtensionPoint(keycloakTransformerExtensionPoint, {\n setUserTransformer(transformer) {\n if (userTransformer) {\n throw new InputError('User transformer may only be set once');\n }\n userTransformer = transformer;\n },\n setGroupTransformer(transformer) {\n if (groupTransformer) {\n throw new InputError('Group transformer may only be set once');\n }\n groupTransformer = transformer;\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 KeycloakOrgEntityProvider.fromConfig(\n { config, logger },\n {\n scheduler: scheduler,\n schedule: scheduler.createScheduledTaskRunner({\n frequency: { minutes: 30 },\n timeout: { minutes: 3 },\n }),\n userTransformer: userTransformer,\n groupTransformer: groupTransformer,\n },\n ),\n );\n },\n });\n },\n});\n"],"names":["createBackendModule","keycloakTransformerExtensionPoint","InputError","catalogProcessingExtensionPoint","coreServices","KeycloakOrgEntityProvider"],"mappings":";;;;;;;;AAgCO,MAAM,sCAAsCA,oCAAoB,CAAA;AAAA,EACrE,QAAU,EAAA,SAAA;AAAA,EACV,QAAU,EAAA,iCAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAI,IAAA,eAAA;AACJ,IAAI,IAAA,gBAAA;AAEJ,IAAA,GAAA,CAAI,uBAAuBC,4CAAmC,EAAA;AAAA,MAC5D,mBAAmB,WAAa,EAAA;AAC9B,QAAA,IAAI,eAAiB,EAAA;AACnB,UAAM,MAAA,IAAIC,kBAAW,uCAAuC,CAAA;AAAA;AAE9D,QAAkB,eAAA,GAAA,WAAA;AAAA,OACpB;AAAA,MACA,oBAAoB,WAAa,EAAA;AAC/B,QAAA,IAAI,gBAAkB,EAAA;AACpB,UAAM,MAAA,IAAIA,kBAAW,wCAAwC,CAAA;AAAA;AAE/D,QAAmB,gBAAA,GAAA,WAAA;AAAA;AACrB,KACD,CAAA;AACD,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,OAAS,EAAAC,iDAAA;AAAA,QACT,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA;AAAA,OAC1B;AAAA,MACA,MAAM,IAAK,CAAA,EAAE,SAAS,MAAQ,EAAA,MAAA,EAAQ,WAAa,EAAA;AACjD,QAAQ,OAAA,CAAA,iBAAA;AAAA,UACNC,mDAA0B,CAAA,UAAA;AAAA,YACxB,EAAE,QAAQ,MAAO,EAAA;AAAA,YACjB;AAAA,cACE,SAAA;AAAA,cACA,QAAA,EAAU,UAAU,yBAA0B,CAAA;AAAA,gBAC5C,SAAA,EAAW,EAAE,OAAA,EAAS,EAAG,EAAA;AAAA,gBACzB,OAAA,EAAS,EAAE,OAAA,EAAS,CAAE;AAAA,eACvB,CAAA;AAAA,cACD,eAAA;AAAA,cACA;AAAA;AACF;AACF,SACF;AAAA;AACF,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
var catalogModel = require('@backstage/catalog-model');
|
|
4
4
|
var errors = require('@backstage/errors');
|
|
5
|
+
var KeyCloakAdminClient = require('@keycloak/keycloak-admin-client');
|
|
6
|
+
var api = require('@opentelemetry/api');
|
|
5
7
|
var lodash = require('lodash');
|
|
8
|
+
var pLimit = require('p-limit');
|
|
6
9
|
var uuid = require('uuid');
|
|
7
10
|
var constants = require('../lib/constants.cjs.js');
|
|
8
11
|
var config = require('../lib/config.cjs.js');
|
|
9
12
|
var read = require('../lib/read.cjs.js');
|
|
10
13
|
var authenticate = require('../lib/authenticate.cjs.js');
|
|
11
|
-
|
|
14
|
+
|
|
15
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
16
|
|
|
13
17
|
function _interopNamespaceCompat(e) {
|
|
14
18
|
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
@@ -28,6 +32,8 @@ function _interopNamespaceCompat(e) {
|
|
|
28
32
|
return Object.freeze(n);
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
var KeyCloakAdminClient__default = /*#__PURE__*/_interopDefaultCompat(KeyCloakAdminClient);
|
|
36
|
+
var pLimit__default = /*#__PURE__*/_interopDefaultCompat(pLimit);
|
|
31
37
|
var uuid__namespace = /*#__PURE__*/_interopNamespaceCompat(uuid);
|
|
32
38
|
|
|
33
39
|
const withLocations = (baseUrl, realm, entity) => {
|
|
@@ -118,17 +124,13 @@ class KeycloakOrgEntityProvider {
|
|
|
118
124
|
const logger = options?.logger ?? this.options.logger;
|
|
119
125
|
const provider = this.options.provider;
|
|
120
126
|
const { markReadComplete } = trackProgress(logger);
|
|
121
|
-
const
|
|
122
|
-
const KeyCloakAdminClient = KeyCloakAdminClientModule.default;
|
|
123
|
-
const kcAdminClient = new KeyCloakAdminClient({
|
|
127
|
+
const kcAdminClient = new KeyCloakAdminClient__default.default({
|
|
124
128
|
baseUrl: provider.baseUrl,
|
|
125
129
|
realmName: provider.loginRealm
|
|
126
130
|
});
|
|
127
131
|
await authenticate.authenticate(kcAdminClient, provider, logger);
|
|
128
|
-
const pLimitCJSModule = await import('p-limit');
|
|
129
|
-
const limitFunc = pLimitCJSModule.default;
|
|
130
132
|
const concurrency = provider.maxConcurrency ?? 20;
|
|
131
|
-
const limit =
|
|
133
|
+
const limit = pLimit__default.default(concurrency);
|
|
132
134
|
const dataBatchFailureCounter = this.meter.createCounter(
|
|
133
135
|
"backend_keycloak.fetch.data.batch.failure.count",
|
|
134
136
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeycloakOrgEntityProvider.cjs.js","sources":["../../src/providers/KeycloakOrgEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2024 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 type {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n type Entity,\n} from '@backstage/catalog-model';\nimport type { Config } from '@backstage/config';\nimport { InputError, isError, NotFoundError } from '@backstage/errors';\nimport type {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\n\n// @ts-ignore\nimport { merge } from 'lodash';\nimport { LimitFunction } from 'p-limit';\nimport * as uuid from 'uuid';\n\nimport {\n GroupTransformer,\n KEYCLOAK_ID_ANNOTATION,\n KeycloakProviderConfig,\n UserTransformer,\n} from '../lib';\nimport { readProviderConfigs } from '../lib/config';\nimport { readKeycloakRealm } from '../lib/read';\nimport { authenticate } from '../lib/authenticate';\nimport { Attributes, Counter, Meter, metrics } from '@opentelemetry/api';\n\n/**\n * Options for {@link KeycloakOrgEntityProvider}.\n *\n * @public\n */\nexport interface KeycloakOrgEntityProviderOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The refresh schedule to use.\n * @remarks\n *\n * You can pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: SchedulerServiceTaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: SchedulerService;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\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// Makes sure that emitted entities have a proper location\nexport const withLocations = (\n baseUrl: string,\n realm: string,\n entity: Entity,\n): Entity => {\n const kind = entity.kind === 'Group' ? 'groups' : 'users';\n const location = `url:${baseUrl}/admin/realms/${realm}/${kind}/${entity.metadata.annotations?.[KEYCLOAK_ID_ANNOTATION]}`;\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/**\n * Ingests org data (users and groups) from GitHub.\n *\n * @public\n */\nexport class KeycloakOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private meter: Meter;\n private counter: Counter<Attributes>;\n private scheduleFn?: () => Promise<void>;\n\n /**\n * Static builder method to create multiple KeycloakOrgEntityProvider instances from a single config.\n * @param deps - The dependencies required for the provider, including the configuration and logger.\n * @param options - Options for scheduling tasks and transforming users and groups.\n * @returns An array of KeycloakOrgEntityProvider instances.\n */\n static fromConfig(\n deps: {\n config: Config;\n logger: LoggerService;\n },\n options: (\n | { schedule: SchedulerServiceTaskRunner }\n | { scheduler: SchedulerService }\n ) & {\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n },\n ): KeycloakOrgEntityProvider[] {\n const { config, logger } = deps;\n return readProviderConfigs(config).map(providerConfig => {\n let taskRunner: SchedulerServiceTaskRunner | string;\n if ('scheduler' in options && providerConfig.schedule) {\n // Create a scheduled task runner using the provided scheduler and schedule configuration\n taskRunner = options.scheduler.createScheduledTaskRunner(\n providerConfig.schedule,\n );\n } else if ('schedule' in options) {\n // Use the provided schedule directly\n taskRunner = options.schedule;\n } else {\n throw new InputError(\n `No schedule provided via config for KeycloakOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const provider = new KeycloakOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: logger,\n taskRunner: taskRunner,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n });\n\n return provider;\n });\n }\n\n constructor(\n private options: {\n id: string;\n provider: KeycloakProviderConfig;\n logger: LoggerService;\n taskRunner: SchedulerServiceTaskRunner;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n },\n ) {\n this.meter = metrics.getMeter('default');\n this.counter = this.meter.createCounter(\n 'backend_keycloak.fetch.task.failure.count',\n {\n description:\n 'Counts the number of failed Keycloak data fetch tasks. Each increment indicates a complete failure of a fetch task, meaning no data was provided to the Catalog API. However, data may still be fetched in subsequent tasks, depending on the nature of the error.',\n },\n );\n this.schedule(options.taskRunner);\n }\n\n /**\n * Returns the name of this entity provider.\n */\n getProviderName(): string {\n return `KeycloakOrgEntityProvider:${this.options.id}`;\n }\n\n /**\n * Connect to Backstage catalog entity provider\n * @param connection - The connection to the catalog API ingestor, which allows the provision of new entities.\n */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one complete ingestion loop. Call this method regularly at some\n * appropriate cadence.\n */\n async read(options: { logger?: LoggerService; taskInstanceId: string }) {\n if (!this.connection) {\n throw new NotFoundError('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const provider = this.options.provider;\n\n const { markReadComplete } = trackProgress(logger);\n const KeyCloakAdminClientModule = await import(\n '@keycloak/keycloak-admin-client'\n );\n const KeyCloakAdminClient = KeyCloakAdminClientModule.default;\n\n const kcAdminClient = new KeyCloakAdminClient({\n baseUrl: provider.baseUrl,\n realmName: provider.loginRealm,\n });\n await authenticate(kcAdminClient, provider, logger);\n\n const pLimitCJSModule = await import('p-limit');\n const limitFunc = pLimitCJSModule.default;\n const concurrency = provider.maxConcurrency ?? 20;\n const limit: LimitFunction = limitFunc(concurrency);\n\n const dataBatchFailureCounter = this.meter.createCounter(\n 'backend_keycloak.fetch.data.batch.failure.count',\n {\n description:\n 'Keycloak data batch fetch failure counter. Incremented for each batch fetch failure. Each failure means that a part of the data was not fetched due to an error, and thus the corresponding data batch was skipped during the current fetch task.',\n },\n );\n const { users, groups } = await readKeycloakRealm(\n kcAdminClient,\n provider,\n logger,\n limit,\n options.taskInstanceId,\n dataBatchFailureCounter,\n {\n userQuerySize: provider.userQuerySize,\n groupQuerySize: provider.groupQuerySize,\n userTransformer: this.options.userTransformer,\n groupTransformer: this.options.groupTransformer,\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: `keycloak-org-provider:${this.options.id}`,\n entity: withLocations(provider.baseUrl, provider.realm, entity),\n })),\n });\n\n markCommitComplete();\n }\n\n /**\n * Periodically schedules a task to read Keycloak user and group information, parse it, and provision it to the Backstage catalog.\n * @param taskRunner - The task runner to use for scheduling tasks.\n */\n schedule(taskRunner: SchedulerServiceTaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async () => {\n const taskInstanceId = uuid.v4();\n const logger = this.options.logger.child({\n class: KeycloakOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: taskInstanceId,\n });\n\n try {\n await this.read({ logger, taskInstanceId });\n } catch (error) {\n this.counter.add(1, { taskInstanceId: taskInstanceId });\n if (isError(error)) {\n // Ensure that we don't log any sensitive internal data:\n logger.error('Error while syncing Keycloak users and groups', {\n // Default Error properties:\n name: error.name,\n cause: error.cause,\n message: error.message,\n stack: error.stack,\n // Additional status code if available:\n status: (error.response as { status?: string })?.status,\n });\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 Keycloak users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\n summary = `${read.users.length} Keycloak users and ${read.groups.length} Keycloak 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"],"names":["KEYCLOAK_ID_ANNOTATION","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","metrics","config","readProviderConfigs","InputError","NotFoundError","authenticate","readKeycloakRealm","uuid","isError"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FO,MAAM,aAAgB,GAAA,CAC3B,OACA,EAAA,KAAA,EACA,MACW,KAAA;AACX,EAAA,MAAM,IAAO,GAAA,MAAA,CAAO,IAAS,KAAA,OAAA,GAAU,QAAW,GAAA,OAAA;AAClD,EAAA,MAAM,QAAW,GAAA,CAAA,IAAA,EAAO,OAAO,CAAA,cAAA,EAAiB,KAAK,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,MAAO,CAAA,QAAA,CAAS,WAAc,GAAAA,gCAAsB,CAAC,CAAA,CAAA;AACtH,EAAO,OAAAC,YAAA;AAAA,IACL;AAAA,MACE,QAAU,EAAA;AAAA,QACR,WAAa,EAAA;AAAA,UACX,CAACC,gCAAmB,GAAG,QAAA;AAAA,UACvB,CAACC,uCAA0B,GAAG;AAAA;AAChC;AACF,KACF;AAAA,IACA;AAAA,GACF;AACF;AAOO,MAAM,yBAAoD,CAAA;AAAA,EAuD/D,YACU,OAQR,EAAA;AARQ,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AASR,IAAK,IAAA,CAAA,KAAA,GAAQC,WAAQ,CAAA,QAAA,CAAS,SAAS,CAAA;AACvC,IAAK,IAAA,CAAA,OAAA,GAAU,KAAK,KAAM,CAAA,aAAA;AAAA,MACxB,2CAAA;AAAA,MACA;AAAA,QACE,WACE,EAAA;AAAA;AACJ,KACF;AACA,IAAK,IAAA,CAAA,QAAA,CAAS,QAAQ,UAAU,CAAA;AAAA;AAClC,EAzEQ,UAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQR,OAAO,UACL,CAAA,IAAA,EAIA,OAO6B,EAAA;AAC7B,IAAM,MAAA,UAAEC,QAAQ,EAAA,MAAA,EAAW,GAAA,IAAA;AAC3B,IAAA,OAAOC,0BAAoB,CAAAD,QAAM,CAAE,CAAA,GAAA,CAAI,CAAkB,cAAA,KAAA;AACvD,MAAI,IAAA,UAAA;AACJ,MAAI,IAAA,WAAA,IAAe,OAAW,IAAA,cAAA,CAAe,QAAU,EAAA;AAErD,QAAA,UAAA,GAAa,QAAQ,SAAU,CAAA,yBAAA;AAAA,UAC7B,cAAe,CAAA;AAAA,SACjB;AAAA,OACF,MAAA,IAAW,cAAc,OAAS,EAAA;AAEhC,QAAA,UAAA,GAAa,OAAQ,CAAA,QAAA;AAAA,OAChB,MAAA;AACL,QAAA,MAAM,IAAIE,iBAAA;AAAA,UACR,CAAA,8DAAA,EAAiE,eAAe,EAAE,CAAA,CAAA;AAAA,SACpF;AAAA;AAGF,MAAM,MAAA,QAAA,GAAW,IAAI,yBAA0B,CAAA;AAAA,QAC7C,IAAI,cAAe,CAAA,EAAA;AAAA,QACnB,QAAU,EAAA,cAAA;AAAA,QACV,MAAA;AAAA,QACA,UAAA;AAAA,QACA,iBAAiB,OAAQ,CAAA,eAAA;AAAA,QACzB,kBAAkB,OAAQ,CAAA;AAAA,OAC3B,CAAA;AAED,MAAO,OAAA,QAAA;AAAA,KACR,CAAA;AAAA;AACH;AAAA;AAAA;AAAA,EA0BA,eAA0B,GAAA;AACxB,IAAO,OAAA,CAAA,0BAAA,EAA6B,IAAK,CAAA,OAAA,CAAQ,EAAE,CAAA,CAAA;AAAA;AACrD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,UAAsC,EAAA;AAClD,IAAA,IAAA,CAAK,UAAa,GAAA,UAAA;AAClB,IAAA,MAAM,KAAK,UAAa,IAAA;AAAA;AAC1B;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAK,OAA6D,EAAA;AACtE,IAAI,IAAA,CAAC,KAAK,UAAY,EAAA;AACpB,MAAM,MAAA,IAAIC,qBAAc,iBAAiB,CAAA;AAAA;AAG3C,IAAA,MAAM,MAAS,GAAA,OAAA,EAAS,MAAU,IAAA,IAAA,CAAK,OAAQ,CAAA,MAAA;AAC/C,IAAM,MAAA,QAAA,GAAW,KAAK,OAAQ,CAAA,QAAA;AAE9B,IAAA,MAAM,EAAE,gBAAA,EAAqB,GAAA,aAAA,CAAc,MAAM,CAAA;AACjD,IAAM,MAAA,yBAAA,GAA4B,MAAM,OACtC,iCACF,CAAA;AACA,IAAA,MAAM,sBAAsB,yBAA0B,CAAA,OAAA;AAEtD,IAAM,MAAA,aAAA,GAAgB,IAAI,mBAAoB,CAAA;AAAA,MAC5C,SAAS,QAAS,CAAA,OAAA;AAAA,MAClB,WAAW,QAAS,CAAA;AAAA,KACrB,CAAA;AACD,IAAM,MAAAC,yBAAA,CAAa,aAAe,EAAA,QAAA,EAAU,MAAM,CAAA;AAElD,IAAM,MAAA,eAAA,GAAkB,MAAM,OAAO,SAAS,CAAA;AAC9C,IAAA,MAAM,YAAY,eAAgB,CAAA,OAAA;AAClC,IAAM,MAAA,WAAA,GAAc,SAAS,cAAkB,IAAA,EAAA;AAC/C,IAAM,MAAA,KAAA,GAAuB,UAAU,WAAW,CAAA;AAElD,IAAM,MAAA,uBAAA,GAA0B,KAAK,KAAM,CAAA,aAAA;AAAA,MACzC,iDAAA;AAAA,MACA;AAAA,QACE,WACE,EAAA;AAAA;AACJ,KACF;AACA,IAAA,MAAM,EAAE,KAAA,EAAO,MAAO,EAAA,GAAI,MAAMC,sBAAA;AAAA,MAC9B,aAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,OAAQ,CAAA,cAAA;AAAA,MACR,uBAAA;AAAA,MACA;AAAA,QACE,eAAe,QAAS,CAAA,aAAA;AAAA,QACxB,gBAAgB,QAAS,CAAA,cAAA;AAAA,QACzB,eAAA,EAAiB,KAAK,OAAQ,CAAA,eAAA;AAAA,QAC9B,gBAAA,EAAkB,KAAK,OAAQ,CAAA;AAAA;AACjC,KACF;AAEA,IAAA,MAAM,EAAE,kBAAmB,EAAA,GAAI,iBAAiB,EAAE,KAAA,EAAO,QAAQ,CAAA;AAEjE,IAAM,MAAA,IAAA,CAAK,WAAW,aAAc,CAAA;AAAA,MAClC,IAAM,EAAA,MAAA;AAAA,MACN,QAAA,EAAU,CAAC,GAAG,KAAA,EAAO,GAAG,MAAM,CAAA,CAAE,IAAI,CAAW,MAAA,MAAA;AAAA,QAC7C,WAAa,EAAA,CAAA,sBAAA,EAAyB,IAAK,CAAA,OAAA,CAAQ,EAAE,CAAA,CAAA;AAAA,QACrD,QAAQ,aAAc,CAAA,QAAA,CAAS,OAAS,EAAA,QAAA,CAAS,OAAO,MAAM;AAAA,OAC9D,CAAA;AAAA,KACH,CAAA;AAED,IAAmB,kBAAA,EAAA;AAAA;AACrB;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,UAAwC,EAAA;AAC/C,IAAA,IAAA,CAAK,aAAa,YAAY;AAC5B,MAAA,MAAM,EAAK,GAAA,CAAA,EAAG,IAAK,CAAA,eAAA,EAAiB,CAAA,QAAA,CAAA;AACpC,MAAA,MAAM,WAAW,GAAI,CAAA;AAAA,QACnB,EAAA;AAAA,QACA,IAAI,YAAY;AACd,UAAM,MAAA,cAAA,GAAiBC,gBAAK,EAAG,EAAA;AAC/B,UAAA,MAAM,MAAS,GAAA,IAAA,CAAK,OAAQ,CAAA,MAAA,CAAO,KAAM,CAAA;AAAA,YACvC,KAAA,EAAO,yBAA0B,CAAA,SAAA,CAAU,WAAY,CAAA,IAAA;AAAA,YACvD,MAAQ,EAAA,EAAA;AAAA,YACR;AAAA,WACD,CAAA;AAED,UAAI,IAAA;AACF,YAAA,MAAM,IAAK,CAAA,IAAA,CAAK,EAAE,MAAA,EAAQ,gBAAgB,CAAA;AAAA,mBACnC,KAAO,EAAA;AACd,YAAA,IAAA,CAAK,OAAQ,CAAA,GAAA,CAAI,CAAG,EAAA,EAAE,gBAAgC,CAAA;AACtD,YAAI,IAAAC,cAAA,CAAQ,KAAK,CAAG,EAAA;AAElB,cAAA,MAAA,CAAO,MAAM,+CAAiD,EAAA;AAAA;AAAA,gBAE5D,MAAM,KAAM,CAAA,IAAA;AAAA,gBACZ,OAAO,KAAM,CAAA,KAAA;AAAA,gBACb,SAAS,KAAM,CAAA,OAAA;AAAA,gBACf,OAAO,KAAM,CAAA,KAAA;AAAA;AAAA,gBAEb,MAAA,EAAS,MAAM,QAAkC,EAAA;AAAA,eAClD,CAAA;AAAA;AACH;AACF;AACF,OACD,CAAA;AAAA,KACH;AAAA;AAEJ;AAGA,SAAS,cAAc,MAAuB,EAAA;AAC5C,EAAI,IAAA,SAAA,GAAY,KAAK,GAAI,EAAA;AACzB,EAAI,IAAA,OAAA;AAEJ,EAAA,MAAA,CAAO,KAAK,mCAAmC,CAAA;AAE/C,EAAA,SAAS,iBAAiB,IAA+C,EAAA;AACvE,IAAA,OAAA,GAAU,GAAG,IAAK,CAAA,KAAA,CAAM,MAAM,CAAuB,oBAAA,EAAA,IAAA,CAAK,OAAO,MAAM,CAAA,gBAAA,CAAA;AACvE,IAAA,MAAM,iBAAiB,IAAK,CAAA,GAAA,KAAQ,SAAa,IAAA,GAAA,EAAM,QAAQ,CAAC,CAAA;AAChE,IAAA,SAAA,GAAY,KAAK,GAAI,EAAA;AACrB,IAAA,MAAA,CAAO,IAAK,CAAA,CAAA,KAAA,EAAQ,OAAO,CAAA,IAAA,EAAO,YAAY,CAAyB,uBAAA,CAAA,CAAA;AACvE,IAAA,OAAO,EAAE,kBAAmB,EAAA;AAAA;AAG9B,EAAA,SAAS,kBAAqB,GAAA;AAC5B,IAAA,MAAM,mBAAmB,IAAK,CAAA,GAAA,KAAQ,SAAa,IAAA,GAAA,EAAM,QAAQ,CAAC,CAAA;AAClE,IAAA,MAAA,CAAO,IAAK,CAAA,CAAA,UAAA,EAAa,OAAO,CAAA,IAAA,EAAO,cAAc,CAAW,SAAA,CAAA,CAAA;AAAA;AAGlE,EAAA,OAAO,EAAE,gBAAiB,EAAA;AAC5B;;;;;"}
|
|
1
|
+
{"version":3,"file":"KeycloakOrgEntityProvider.cjs.js","sources":["../../src/providers/KeycloakOrgEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2024 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 type {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n type Entity,\n} from '@backstage/catalog-model';\nimport type { Config } from '@backstage/config';\nimport { InputError, isError, NotFoundError } from '@backstage/errors';\nimport type {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\n\nimport KeyCloakAdminClient from '@keycloak/keycloak-admin-client';\nimport { Attributes, Counter, Meter, metrics } from '@opentelemetry/api';\n// @ts-ignore\nimport { merge } from 'lodash';\nimport pLimit from 'p-limit';\nimport * as uuid from 'uuid';\n\nimport {\n GroupTransformer,\n KEYCLOAK_ID_ANNOTATION,\n KeycloakProviderConfig,\n UserTransformer,\n} from '../lib';\nimport { readProviderConfigs } from '../lib/config';\nimport { readKeycloakRealm } from '../lib/read';\nimport { authenticate } from '../lib/authenticate';\n\n/**\n * Options for {@link KeycloakOrgEntityProvider}.\n *\n * @public\n */\nexport interface KeycloakOrgEntityProviderOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The refresh schedule to use.\n * @remarks\n *\n * You can pass in the result of\n * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: SchedulerServiceTaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: SchedulerService;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\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// Makes sure that emitted entities have a proper location\nexport const withLocations = (\n baseUrl: string,\n realm: string,\n entity: Entity,\n): Entity => {\n const kind = entity.kind === 'Group' ? 'groups' : 'users';\n const location = `url:${baseUrl}/admin/realms/${realm}/${kind}/${entity.metadata.annotations?.[KEYCLOAK_ID_ANNOTATION]}`;\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/**\n * Ingests org data (users and groups) from GitHub.\n *\n * @public\n */\nexport class KeycloakOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private meter: Meter;\n private counter: Counter<Attributes>;\n private scheduleFn?: () => Promise<void>;\n\n /**\n * Static builder method to create multiple KeycloakOrgEntityProvider instances from a single config.\n * @param deps - The dependencies required for the provider, including the configuration and logger.\n * @param options - Options for scheduling tasks and transforming users and groups.\n * @returns An array of KeycloakOrgEntityProvider instances.\n */\n static fromConfig(\n deps: {\n config: Config;\n logger: LoggerService;\n },\n options: (\n | { schedule: SchedulerServiceTaskRunner }\n | { scheduler: SchedulerService }\n ) & {\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n },\n ): KeycloakOrgEntityProvider[] {\n const { config, logger } = deps;\n return readProviderConfigs(config).map(providerConfig => {\n let taskRunner: SchedulerServiceTaskRunner | string;\n if ('scheduler' in options && providerConfig.schedule) {\n // Create a scheduled task runner using the provided scheduler and schedule configuration\n taskRunner = options.scheduler.createScheduledTaskRunner(\n providerConfig.schedule,\n );\n } else if ('schedule' in options) {\n // Use the provided schedule directly\n taskRunner = options.schedule;\n } else {\n throw new InputError(\n `No schedule provided via config for KeycloakOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const provider = new KeycloakOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: logger,\n taskRunner: taskRunner,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n });\n\n return provider;\n });\n }\n\n constructor(\n private options: {\n id: string;\n provider: KeycloakProviderConfig;\n logger: LoggerService;\n taskRunner: SchedulerServiceTaskRunner;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n },\n ) {\n this.meter = metrics.getMeter('default');\n this.counter = this.meter.createCounter(\n 'backend_keycloak.fetch.task.failure.count',\n {\n description:\n 'Counts the number of failed Keycloak data fetch tasks. Each increment indicates a complete failure of a fetch task, meaning no data was provided to the Catalog API. However, data may still be fetched in subsequent tasks, depending on the nature of the error.',\n },\n );\n this.schedule(options.taskRunner);\n }\n\n /**\n * Returns the name of this entity provider.\n */\n getProviderName(): string {\n return `KeycloakOrgEntityProvider:${this.options.id}`;\n }\n\n /**\n * Connect to Backstage catalog entity provider\n * @param connection - The connection to the catalog API ingestor, which allows the provision of new entities.\n */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one complete ingestion loop. Call this method regularly at some\n * appropriate cadence.\n */\n async read(options: { logger?: LoggerService; taskInstanceId: string }) {\n if (!this.connection) {\n throw new NotFoundError('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const provider = this.options.provider;\n\n const { markReadComplete } = trackProgress(logger);\n\n const kcAdminClient = new KeyCloakAdminClient({\n baseUrl: provider.baseUrl,\n realmName: provider.loginRealm,\n });\n await authenticate(kcAdminClient, provider, logger);\n\n const concurrency = provider.maxConcurrency ?? 20;\n const limit = pLimit(concurrency);\n\n const dataBatchFailureCounter = this.meter.createCounter(\n 'backend_keycloak.fetch.data.batch.failure.count',\n {\n description:\n 'Keycloak data batch fetch failure counter. Incremented for each batch fetch failure. Each failure means that a part of the data was not fetched due to an error, and thus the corresponding data batch was skipped during the current fetch task.',\n },\n );\n const { users, groups } = await readKeycloakRealm(\n kcAdminClient,\n provider,\n logger,\n limit,\n options.taskInstanceId,\n dataBatchFailureCounter,\n {\n userQuerySize: provider.userQuerySize,\n groupQuerySize: provider.groupQuerySize,\n userTransformer: this.options.userTransformer,\n groupTransformer: this.options.groupTransformer,\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: `keycloak-org-provider:${this.options.id}`,\n entity: withLocations(provider.baseUrl, provider.realm, entity),\n })),\n });\n\n markCommitComplete();\n }\n\n /**\n * Periodically schedules a task to read Keycloak user and group information, parse it, and provision it to the Backstage catalog.\n * @param taskRunner - The task runner to use for scheduling tasks.\n */\n schedule(taskRunner: SchedulerServiceTaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async () => {\n const taskInstanceId = uuid.v4();\n const logger = this.options.logger.child({\n class: KeycloakOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: taskInstanceId,\n });\n\n try {\n await this.read({ logger, taskInstanceId });\n } catch (error) {\n this.counter.add(1, { taskInstanceId: taskInstanceId });\n if (isError(error)) {\n // Ensure that we don't log any sensitive internal data:\n logger.error('Error while syncing Keycloak users and groups', {\n // Default Error properties:\n name: error.name,\n cause: error.cause,\n message: error.message,\n stack: error.stack,\n // Additional status code if available:\n status: (error.response as { status?: string })?.status,\n });\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 Keycloak users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\n summary = `${read.users.length} Keycloak users and ${read.groups.length} Keycloak 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"],"names":["KEYCLOAK_ID_ANNOTATION","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","metrics","config","readProviderConfigs","InputError","NotFoundError","KeyCloakAdminClient","authenticate","pLimit","readKeycloakRealm","uuid","isError"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-catalog-backend-module-keycloak",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.18.0",
|
|
4
4
|
"description": "A Backend backend plugin for Keycloak",
|
|
5
5
|
"main": "./dist/index.cjs.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"tsc": "tsc"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@backstage/backend-plugin-api": "^1.
|
|
49
|
+
"@backstage/backend-plugin-api": "^1.7.0",
|
|
50
50
|
"@backstage/catalog-model": "^1.7.6",
|
|
51
51
|
"@backstage/errors": "^1.2.7",
|
|
52
|
-
"@backstage/plugin-catalog-backend-module-logs": "^0.1.
|
|
53
|
-
"@backstage/plugin-catalog-node": "^
|
|
54
|
-
"@keycloak/keycloak-admin-client": "26.
|
|
52
|
+
"@backstage/plugin-catalog-backend-module-logs": "^0.1.19",
|
|
53
|
+
"@backstage/plugin-catalog-node": "^2.0.0",
|
|
54
|
+
"@keycloak/keycloak-admin-client": "26.5.6",
|
|
55
55
|
"@opentelemetry/api": "^1.9.0",
|
|
56
56
|
"jsonwebtoken": "^9.0.0",
|
|
57
57
|
"lodash": "^4.17.21",
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
"uuid": "^9.0.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@backstage/backend-defaults": "^0.15.
|
|
63
|
-
"@backstage/backend-test-utils": "^1.
|
|
64
|
-
"@backstage/cli": "^0.35.
|
|
62
|
+
"@backstage/backend-defaults": "^0.15.2",
|
|
63
|
+
"@backstage/backend-test-utils": "^1.11.0",
|
|
64
|
+
"@backstage/cli": "^0.35.4",
|
|
65
65
|
"@backstage/config": "^1.3.6",
|
|
66
|
-
"@backstage/plugin-catalog-backend": "^3.
|
|
66
|
+
"@backstage/plugin-catalog-backend": "^3.4.0",
|
|
67
67
|
"@backstage/types": "^1.2.2",
|
|
68
|
-
"@types/lodash": "4.17.
|
|
68
|
+
"@types/lodash": "4.17.24",
|
|
69
69
|
"@types/uuid": "10.0.0",
|
|
70
70
|
"deepmerge": "4.3.1",
|
|
71
71
|
"open-cli": "^8.0.0"
|