From 792445749d0f988953998c10e8171ff2ec057dbc Mon Sep 17 00:00:00 2001 From: Kashish Mittal <113269381+04kash@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:26:11 -0500 Subject: [PATCH] chore: deprecate keycloak-backend (#2482) * deprecate keycloak-backend Signed-off-by: Kashish Mittal * regen yarn Signed-off-by: Kashish Mittal --------- Signed-off-by: Kashish Mittal --- plugins/keycloak-backend/.eslintignore | 2 - plugins/keycloak-backend/.eslintrc.js | 1 - plugins/keycloak-backend/.lintstagedrc.json | 4 - plugins/keycloak-backend/.prettierignore | 12 - plugins/keycloak-backend/.prettierrc.js | 20 - plugins/keycloak-backend/.versionhistory.md | 1 - plugins/keycloak-backend/CHANGELOG.md | 521 ----- plugins/keycloak-backend/CONTRIBUTING.md | 20 - plugins/keycloak-backend/README.md | 170 +- plugins/keycloak-backend/__fixtures__/data.ts | 221 -- .../keycloak-backend/__fixtures__/helpers.ts | 164 -- .../__fixtures__/keycloak-realm.json | 2052 ----------------- .../app-config.janus-idp.yaml | 11 - plugins/keycloak-backend/catalog-info.yaml | 51 - plugins/keycloak-backend/config.d.ts | 73 - plugins/keycloak-backend/dev/index.ts | 11 - plugins/keycloak-backend/images/group1.jpg | Bin 90280 -> 0 bytes plugins/keycloak-backend/images/user-list.jpg | Bin 84142 -> 0 bytes plugins/keycloak-backend/images/user2.jpg | Bin 69319 -> 0 bytes plugins/keycloak-backend/images/users.jpg | Bin 116726 -> 0 bytes plugins/keycloak-backend/package.json | 93 - plugins/keycloak-backend/src/extensions.ts | 23 - plugins/keycloak-backend/src/index.ts | 22 - .../keycloak-backend/src/lib/config.test.ts | 169 -- plugins/keycloak-backend/src/lib/config.ts | 167 -- plugins/keycloak-backend/src/lib/constants.ts | 20 - plugins/keycloak-backend/src/lib/index.ts | 23 - plugins/keycloak-backend/src/lib/read.test.ts | 326 --- plugins/keycloak-backend/src/lib/read.ts | 363 --- .../keycloak-backend/src/lib/transformers.ts | 27 - plugins/keycloak-backend/src/lib/types.ts | 71 - ...atalogModuleKeycloakEntityProvider.test.ts | 186 -- .../catalogModuleKeycloakEntityProvider.ts | 79 - plugins/keycloak-backend/src/module/index.ts | 17 - .../KeycloakOrgEntityProvider.test.ts | 276 --- .../providers/KeycloakOrgEntityProvider.ts | 314 --- .../KeycloakOrgEntityProvider.test.ts.snap | 641 ----- .../keycloak-backend/src/providers/index.ts | 18 - plugins/keycloak-backend/src/setupTests.ts | 17 - plugins/keycloak-backend/tsconfig.json | 9 - plugins/keycloak-backend/turbo.json | 16 - yarn.lock | 105 +- 42 files changed, 16 insertions(+), 6300 deletions(-) delete mode 100644 plugins/keycloak-backend/.eslintignore delete mode 100644 plugins/keycloak-backend/.eslintrc.js delete mode 100644 plugins/keycloak-backend/.lintstagedrc.json delete mode 100644 plugins/keycloak-backend/.prettierignore delete mode 100644 plugins/keycloak-backend/.prettierrc.js delete mode 100644 plugins/keycloak-backend/.versionhistory.md delete mode 100644 plugins/keycloak-backend/CHANGELOG.md delete mode 100644 plugins/keycloak-backend/CONTRIBUTING.md delete mode 100644 plugins/keycloak-backend/__fixtures__/data.ts delete mode 100644 plugins/keycloak-backend/__fixtures__/helpers.ts delete mode 100644 plugins/keycloak-backend/__fixtures__/keycloak-realm.json delete mode 100644 plugins/keycloak-backend/app-config.janus-idp.yaml delete mode 100644 plugins/keycloak-backend/catalog-info.yaml delete mode 100644 plugins/keycloak-backend/config.d.ts delete mode 100644 plugins/keycloak-backend/dev/index.ts delete mode 100644 plugins/keycloak-backend/images/group1.jpg delete mode 100644 plugins/keycloak-backend/images/user-list.jpg delete mode 100644 plugins/keycloak-backend/images/user2.jpg delete mode 100644 plugins/keycloak-backend/images/users.jpg delete mode 100644 plugins/keycloak-backend/package.json delete mode 100644 plugins/keycloak-backend/src/extensions.ts delete mode 100644 plugins/keycloak-backend/src/index.ts delete mode 100644 plugins/keycloak-backend/src/lib/config.test.ts delete mode 100644 plugins/keycloak-backend/src/lib/config.ts delete mode 100644 plugins/keycloak-backend/src/lib/constants.ts delete mode 100644 plugins/keycloak-backend/src/lib/index.ts delete mode 100644 plugins/keycloak-backend/src/lib/read.test.ts delete mode 100644 plugins/keycloak-backend/src/lib/read.ts delete mode 100644 plugins/keycloak-backend/src/lib/transformers.ts delete mode 100644 plugins/keycloak-backend/src/lib/types.ts delete mode 100644 plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts delete mode 100644 plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts delete mode 100644 plugins/keycloak-backend/src/module/index.ts delete mode 100644 plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.test.ts delete mode 100644 plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.ts delete mode 100644 plugins/keycloak-backend/src/providers/__snapshots__/KeycloakOrgEntityProvider.test.ts.snap delete mode 100644 plugins/keycloak-backend/src/providers/index.ts delete mode 100644 plugins/keycloak-backend/src/setupTests.ts delete mode 100644 plugins/keycloak-backend/tsconfig.json delete mode 100644 plugins/keycloak-backend/turbo.json diff --git a/plugins/keycloak-backend/.eslintignore b/plugins/keycloak-backend/.eslintignore deleted file mode 100644 index 55289f4a23..0000000000 --- a/plugins/keycloak-backend/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist-dynamic -dist-scalprum diff --git a/plugins/keycloak-backend/.eslintrc.js b/plugins/keycloak-backend/.eslintrc.js deleted file mode 100644 index e2a53a6ad2..0000000000 --- a/plugins/keycloak-backend/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/keycloak-backend/.lintstagedrc.json b/plugins/keycloak-backend/.lintstagedrc.json deleted file mode 100644 index 14b2263def..0000000000 --- a/plugins/keycloak-backend/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/plugins/keycloak-backend/.prettierignore b/plugins/keycloak-backend/.prettierignore deleted file mode 100644 index fc8357d99e..0000000000 --- a/plugins/keycloak-backend/.prettierignore +++ /dev/null @@ -1,12 +0,0 @@ -dist -dist-types -coverage -.vscode -CHANGELOG.md -generated -templates -*.hbs -renovate.json -dist-dynamic -dist-scalprum -playwright-report diff --git a/plugins/keycloak-backend/.prettierrc.js b/plugins/keycloak-backend/.prettierrc.js deleted file mode 100644 index 84cbac65b5..0000000000 --- a/plugins/keycloak-backend/.prettierrc.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check - -/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ -module.exports = { - ...require('@spotify/prettier-config'), - plugins: ['@ianvs/prettier-plugin-sort-imports'], - importOrder: [ - '^react(.*)$', - '', - '^@backstage/(.*)$', - '', - '', - '', - '^@janus-idp/(.*)$', - '', - '', - '', - '^[.]', - ], -}; diff --git a/plugins/keycloak-backend/.versionhistory.md b/plugins/keycloak-backend/.versionhistory.md deleted file mode 100644 index 0647f918d5..0000000000 --- a/plugins/keycloak-backend/.versionhistory.md +++ /dev/null @@ -1 +0,0 @@ -- Bumped to 1.9.0 in main branch for next release 1.2.0 diff --git a/plugins/keycloak-backend/CHANGELOG.md b/plugins/keycloak-backend/CHANGELOG.md deleted file mode 100644 index bd00697606..0000000000 --- a/plugins/keycloak-backend/CHANGELOG.md +++ /dev/null @@ -1,521 +0,0 @@ -### Dependencies - -## 3.1.1 - -### Patch Changes - -- 0e6bfd3: feat: update Backstage to the latest version - - Update to Backstage 1.32.5 - -## 3.1.0 - -### Minor Changes - -- 8244f28: chore(deps): update to backstage 1.32 - -## 3.0.1 - -### Patch Changes - -- 7342e9b: chore: remove @janus-idp/cli dep and relink local packages - - This update removes `@janus-idp/cli` from all plugins, as it’s no longer necessary. Additionally, packages are now correctly linked with a specified version. - -## 3.0.0 - -### Major Changes - -- d9551ae: Include embedded folder to release package - -### Minor Changes - -- d9551ae: feat(deps): update to backstage 1.31 - -### Patch Changes - -- d9551ae: Change local package references to a `*` -- d9551ae: pin the @janus-idp/cli package -- d9551ae: upgrade to yarn v3 -- d9551ae: Change the export-dynamic script to no longer use any flags and remove the tracking of the dist-dynamic folder - -* **@janus-idp/cli:** upgraded to 1.15.2 - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.15.1 - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.15.0 - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.14.0 - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.13.2 - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.13.1 - -## @janus-idp/backstage-plugin-keycloak-backend [1.13.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.12.0...@janus-idp/backstage-plugin-keycloak-backend@1.13.0) (2024-07-26) - -### Features - -- **deps:** update to backstage 1.29 ([#1900](https://github.com/janus-idp/backstage-plugins/issues/1900)) ([f53677f](https://github.com/janus-idp/backstage-plugins/commit/f53677fb02d6df43a9de98c43a9f101a6db76802)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.12.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.11.1...@janus-idp/backstage-plugin-keycloak-backend@1.12.0) (2024-07-24) - -### Features - -- **deps:** update to backstage 1.28 ([#1891](https://github.com/janus-idp/backstage-plugins/issues/1891)) ([1ba1108](https://github.com/janus-idp/backstage-plugins/commit/1ba11088e0de60e90d138944267b83600dc446e5)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.11.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.11.0...@janus-idp/backstage-plugin-keycloak-backend@1.11.1) (2024-06-28) - -### Documentation - -- **keycloak-backend:** update keycloak documentation ([#1832](https://github.com/janus-idp/backstage-plugins/issues/1832)) ([e7c59f5](https://github.com/janus-idp/backstage-plugins/commit/e7c59f55449166a853ded7d193db94075d4cd629)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.11.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.10.1...@janus-idp/backstage-plugin-keycloak-backend@1.11.0) (2024-06-19) - -### Features - -- **keycloak:** expose keycloak user/group transformer extension point ([#1825](https://github.com/janus-idp/backstage-plugins/issues/1825)) ([3f85578](https://github.com/janus-idp/backstage-plugins/commit/3f85578c9a7c4c4de796ceab3d2fcc8e8190af1e)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.10.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.10.0...@janus-idp/backstage-plugin-keycloak-backend@1.10.1) (2024-06-19) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.11.1 - -## @janus-idp/backstage-plugin-keycloak-backend [1.10.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.13...@janus-idp/backstage-plugin-keycloak-backend@1.10.0) (2024-06-13) - -### Features - -- **deps:** update to backstage 1.27 ([#1683](https://github.com/janus-idp/backstage-plugins/issues/1683)) ([a14869c](https://github.com/janus-idp/backstage-plugins/commit/a14869c3f4177049cb8d6552b36c3ffd17e7997d)) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.11.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.13](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.12...@janus-idp/backstage-plugin-keycloak-backend@1.9.13) (2024-06-13) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.10.1 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.12](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.11...@janus-idp/backstage-plugin-keycloak-backend@1.9.12) (2024-06-05) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.10.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.11](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.10...@janus-idp/backstage-plugin-keycloak-backend@1.9.11) (2024-06-04) - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.10](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.9...@janus-idp/backstage-plugin-keycloak-backend@1.9.10) (2024-06-03) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.9.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.9](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.8...@janus-idp/backstage-plugin-keycloak-backend@1.9.9) (2024-05-29) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.10 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.8](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.7...@janus-idp/backstage-plugin-keycloak-backend@1.9.8) (2024-05-29) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.9 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.7](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.6...@janus-idp/backstage-plugin-keycloak-backend@1.9.7) (2024-05-16) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.7 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.6](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.5...@janus-idp/backstage-plugin-keycloak-backend@1.9.6) (2024-05-09) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.6 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.5](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.4...@janus-idp/backstage-plugin-keycloak-backend@1.9.5) (2024-05-02) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.5 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.4](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.3...@janus-idp/backstage-plugin-keycloak-backend@1.9.4) (2024-05-02) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.4 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.3](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.2...@janus-idp/backstage-plugin-keycloak-backend@1.9.3) (2024-04-30) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.3 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.2](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.1...@janus-idp/backstage-plugin-keycloak-backend@1.9.2) (2024-04-30) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.2 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.9.0...@janus-idp/backstage-plugin-keycloak-backend@1.9.1) (2024-04-25) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.1 - -## @janus-idp/backstage-plugin-keycloak-backend [1.9.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.11...@janus-idp/backstage-plugin-keycloak-backend@1.9.0) (2024-04-15) - -### Features - -- checkPluginVersion.sh bump plugins for 1.2.0 release ([#1511](https://github.com/janus-idp/backstage-plugins/issues/1511)) ([73c6588](https://github.com/janus-idp/backstage-plugins/commit/73c6588adb7e8c20907b06f2a8ef248cfd4332e4)) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.8.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.11](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.10...@janus-idp/backstage-plugin-keycloak-backend@1.8.11) (2024-04-09) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.10 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.10](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.9...@janus-idp/backstage-plugin-keycloak-backend@1.8.10) (2024-04-09) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.9 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.9](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.8...@janus-idp/backstage-plugin-keycloak-backend@1.8.9) (2024-04-05) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.8 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.8](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.7...@janus-idp/backstage-plugin-keycloak-backend@1.8.8) (2024-04-02) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.7 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.7](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.6...@janus-idp/backstage-plugin-keycloak-backend@1.8.7) (2024-03-29) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.6 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.6](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.5...@janus-idp/backstage-plugin-keycloak-backend@1.8.6) (2024-03-20) - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.5](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.4...@janus-idp/backstage-plugin-keycloak-backend@1.8.5) (2024-03-04) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.5 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.4](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.3...@janus-idp/backstage-plugin-keycloak-backend@1.8.4) (2024-02-27) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.4 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.3](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.2...@janus-idp/backstage-plugin-keycloak-backend@1.8.3) (2024-02-26) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.3 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.2](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.1...@janus-idp/backstage-plugin-keycloak-backend@1.8.2) (2024-02-21) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.2 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.8.0...@janus-idp/backstage-plugin-keycloak-backend@1.8.1) (2024-02-05) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.1 - -## @janus-idp/backstage-plugin-keycloak-backend [1.8.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.13...@janus-idp/backstage-plugin-keycloak-backend@1.8.0) (2024-01-30) - -### Features - -- add new backend system support for existing backend plugins that have not been migrated over yet ([#1132](https://github.com/janus-idp/backstage-plugins/issues/1132)) ([06e16fd](https://github.com/janus-idp/backstage-plugins/commit/06e16fdcf64257dd08297cb727445d9a8a23c522)) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.7.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.13](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.12...@janus-idp/backstage-plugin-keycloak-backend@1.7.13) (2024-01-25) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.6.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.12](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.11...@janus-idp/backstage-plugin-keycloak-backend@1.7.12) (2024-01-16) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.5.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.11](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.10...@janus-idp/backstage-plugin-keycloak-backend@1.7.11) (2023-12-21) - -### Bug Fixes - -- **keycloak:** fix [#591](https://github.com/janus-idp/backstage-plugins/issues/591): Cleanup some small code smells in Keycloak plugin ([#1022](https://github.com/janus-idp/backstage-plugins/issues/1022)) ([74cb7b1](https://github.com/janus-idp/backstage-plugins/commit/74cb7b1ea552e4e52128e3bb87c4713eb22f1d92)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.10](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.9...@janus-idp/backstage-plugin-keycloak-backend@1.7.10) (2023-12-07) - -### Bug Fixes - -- attempt to force a bump of backend plugins ([#1007](https://github.com/janus-idp/backstage-plugins/issues/1007)) ([7a37225](https://github.com/janus-idp/backstage-plugins/commit/7a372254fb7e8107aa794f7900a6511eee096677)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.9](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.8...@janus-idp/backstage-plugin-keycloak-backend@1.7.9) (2023-12-07) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.7 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.8](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.7...@janus-idp/backstage-plugin-keycloak-backend@1.7.8) (2023-11-30) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.6 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.7](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.6...@janus-idp/backstage-plugin-keycloak-backend@1.7.7) (2023-11-22) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.5 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.6](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.5...@janus-idp/backstage-plugin-keycloak-backend@1.7.6) (2023-11-22) - -### Bug Fixes - -- **keycloak:** embed keycloak admin dependency for dynamic export ([#968](https://github.com/janus-idp/backstage-plugins/issues/968)) ([2f005a0](https://github.com/janus-idp/backstage-plugins/commit/2f005a0bbbe16bebaa047ba364b17a4d4453589a)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.5](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.4...@janus-idp/backstage-plugin-keycloak-backend@1.7.5) (2023-11-21) - -### Bug Fixes - -- sync versions in dynamic assets and publish derived packages as additional packages ([#963](https://github.com/janus-idp/backstage-plugins/issues/963)) ([7d0a386](https://github.com/janus-idp/backstage-plugins/commit/7d0a38609b4a18b54c75378a150e8b5c3ba8ff43)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.4](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.3...@janus-idp/backstage-plugin-keycloak-backend@1.7.4) (2023-11-20) - -### Bug Fixes - -- **keycloak:** don't log sensitive authentication data ([#938](https://github.com/janus-idp/backstage-plugins/issues/938)) ([63d0678](https://github.com/janus-idp/backstage-plugins/commit/63d0678a6ea4decfd7677d6e16d1193722ba0f76)) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.4 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.3](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.2...@janus-idp/backstage-plugin-keycloak-backend@1.7.3) (2023-11-16) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.3 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.2](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.1...@janus-idp/backstage-plugin-keycloak-backend@1.7.2) (2023-11-13) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.2 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.7.0...@janus-idp/backstage-plugin-keycloak-backend@1.7.1) (2023-11-13) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.1 - -## @janus-idp/backstage-plugin-keycloak-backend [1.7.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.6.0...@janus-idp/backstage-plugin-keycloak-backend@1.7.0) (2023-11-08) - -### Features - -- update entity provider schedulers ([#827](https://github.com/janus-idp/backstage-plugins/issues/827)) ([19731d1](https://github.com/janus-idp/backstage-plugins/commit/19731d1449a9d8ffa67aec069d2214e45bfe54ff)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.6.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.7...@janus-idp/backstage-plugin-keycloak-backend@1.6.0) (2023-11-07) - -### Features - -- make backend plugins dynamic (first round) ([#910](https://github.com/janus-idp/backstage-plugins/issues/910)) ([60523e5](https://github.com/janus-idp/backstage-plugins/commit/60523e588ba374cdcfd453afa2c17fc1a7a1ca2d)) -- update Keycloak plugin for dynamic backend ([#869](https://github.com/janus-idp/backstage-plugins/issues/869)) ([a68b38d](https://github.com/janus-idp/backstage-plugins/commit/a68b38d7b25cbfaa267fe5bb28777434ebfaaff3)) - -### Dependencies - -- **@janus-idp/cli:** upgraded to 1.4.0 - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.7](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.6...@janus-idp/backstage-plugin-keycloak-backend@1.5.7) (2023-10-24) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.6](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.5...@janus-idp/backstage-plugin-keycloak-backend@1.5.6) (2023-10-19) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.5](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.4...@janus-idp/backstage-plugin-keycloak-backend@1.5.5) (2023-09-28) - -### Bug Fixes - -- **keycloak:** respect fetch size for members ([#806](https://github.com/janus-idp/backstage-plugins/issues/806)) ([759fdb1](https://github.com/janus-idp/backstage-plugins/commit/759fdb199675930fa3a12b6cd8d121bc8e05b9f5)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.4](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.3...@janus-idp/backstage-plugin-keycloak-backend@1.5.4) (2023-09-07) - -### Bug Fixes - -- **keycloak:** fix keycloak user displayname ([#693](https://github.com/janus-idp/backstage-plugins/issues/693)) ([dfef9a3](https://github.com/janus-idp/backstage-plugins/commit/dfef9a3a0adb4ea2b966746da2d041d40b6aea73)) - -### Other changes - -- **keycloak:** add pagination/traversal test cases ([#697](https://github.com/janus-idp/backstage-plugins/issues/697)) ([b2ab403](https://github.com/janus-idp/backstage-plugins/commit/b2ab403d45f43e929d477e008f560c9777ce0f8c)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.3](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.2...@janus-idp/backstage-plugin-keycloak-backend@1.5.3) (2023-08-24) - -### Bug Fixes - -- **keycloak:** fix schedule type in config.d.ts ([#665](https://github.com/janus-idp/backstage-plugins/issues/665)) ([4403ac3](https://github.com/janus-idp/backstage-plugins/commit/4403ac378c424f869a57b7bd3f9dcbd80d3d37bf)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.2](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.1...@janus-idp/backstage-plugin-keycloak-backend@1.5.2) (2023-08-23) - -### Bug Fixes - -- **config types:** inline types in config.d.ts ([#664](https://github.com/janus-idp/backstage-plugins/issues/664)) ([ae1aea1](https://github.com/janus-idp/backstage-plugins/commit/ae1aea1f4890c0034d1c2602223d59463c61206b)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.5.0...@janus-idp/backstage-plugin-keycloak-backend@1.5.1) (2023-08-22) - -### Bug Fixes - -- **keycloak:** fix config loader issue on backstage v1.17 ([#650](https://github.com/janus-idp/backstage-plugins/issues/650)) ([1799a1f](https://github.com/janus-idp/backstage-plugins/commit/1799a1f65fd2c1a9b8cf95fa0aca8b6debebba7b)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.5.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.4.1...@janus-idp/backstage-plugin-keycloak-backend@1.5.0) (2023-08-14) - -### Features - -- **ts:** transpile each plugin separately ([#634](https://github.com/janus-idp/backstage-plugins/issues/634)) ([b94c4dc](https://github.com/janus-idp/backstage-plugins/commit/b94c4dc50ada328e5ce1bed5fb7c76f64607e1ee)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.4.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.4.0...@janus-idp/backstage-plugin-keycloak-backend@1.4.1) (2023-07-26) - -## @janus-idp/backstage-plugin-keycloak-backend [1.4.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.11...@janus-idp/backstage-plugin-keycloak-backend@1.4.0) (2023-07-25) - -### Features - -- **keycloak:** add userTransformer and groupTransformer ([#542](https://github.com/janus-idp/backstage-plugins/issues/542)) ([15a5e8c](https://github.com/janus-idp/backstage-plugins/commit/15a5e8cab5014def95c274d891e5c0e423016424)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.11](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.10...@janus-idp/backstage-plugin-keycloak-backend@1.3.11) (2023-07-25) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.10](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.9...@janus-idp/backstage-plugin-keycloak-backend@1.3.10) (2023-06-21) - -### Documentation - -- **keycloak:** fixes in readme file ([#454](https://github.com/janus-idp/backstage-plugins/issues/454)) ([eeb1333](https://github.com/janus-idp/backstage-plugins/commit/eeb133359cd39e2abefffccd60c5d0355e05995d)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.9](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.8...@janus-idp/backstage-plugin-keycloak-backend@1.3.9) (2023-06-14) - -### Documentation - -- update plugin README formatting ([#396](https://github.com/janus-idp/backstage-plugins/issues/396)) ([9b39056](https://github.com/janus-idp/backstage-plugins/commit/9b39056f6c66e9a6a0a5d0c4059420dff66db263)), closes [#295](https://github.com/janus-idp/backstage-plugins/issues/295) [#369](https://github.com/janus-idp/backstage-plugins/issues/369) [#295](https://github.com/janus-idp/backstage-plugins/issues/295) [#369](https://github.com/janus-idp/backstage-plugins/issues/369) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.8](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.7...@janus-idp/backstage-plugin-keycloak-backend@1.3.8) (2023-06-12) - -### Other changes - -- **keycloak:** add tests ([#437](https://github.com/janus-idp/backstage-plugins/issues/437)) ([1872d7c](https://github.com/janus-idp/backstage-plugins/commit/1872d7c997cb372d4a2501c472698b660a025e49)) -- reorder imports via prettier ([#419](https://github.com/janus-idp/backstage-plugins/issues/419)) ([17f1e6a](https://github.com/janus-idp/backstage-plugins/commit/17f1e6a689bd793a619ec5e42e5cdda0998f78a5)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.7](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.6...@janus-idp/backstage-plugin-keycloak-backend@1.3.7) (2023-05-30) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.6](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.5...@janus-idp/backstage-plugin-keycloak-backend@1.3.6) (2023-05-30) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.5](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.4...@janus-idp/backstage-plugin-keycloak-backend@1.3.5) (2023-05-22) - -### Documentation - -- **Quay:** update user doc ([#353](https://github.com/janus-idp/backstage-plugins/issues/353)) ([f8d143f](https://github.com/janus-idp/backstage-plugins/commit/f8d143f243db069e8877f6b8a053790fabe078cf)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.4](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.3...@janus-idp/backstage-plugin-keycloak-backend@1.3.4) (2023-05-18) - -### Documentation - -- fix misc README issues ([#375](https://github.com/janus-idp/backstage-plugins/issues/375)) ([7ae8876](https://github.com/janus-idp/backstage-plugins/commit/7ae88760c322694b29b558bac78cbc4eb768695c)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.3](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.2...@janus-idp/backstage-plugin-keycloak-backend@1.3.3) (2023-05-18) - -### Documentation - -- update plugin READMEs ([#373](https://github.com/janus-idp/backstage-plugins/issues/373)) ([478560e](https://github.com/janus-idp/backstage-plugins/commit/478560e38cceaa40d976bccf4785956ed58b5221)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.2](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.1...@janus-idp/backstage-plugin-keycloak-backend@1.3.2) (2023-05-11) - -### Documentation - -- **keycloak:** update user doc ([#342](https://github.com/janus-idp/backstage-plugins/issues/342)) ([9cdba4a](https://github.com/janus-idp/backstage-plugins/commit/9cdba4a5652a1b6737ec9fd50b13b4893b51a171)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.3.0...@janus-idp/backstage-plugin-keycloak-backend@1.3.1) (2023-05-04) - -### Documentation - -- review for Keycloak plugin ([#277](https://github.com/janus-idp/backstage-plugins/issues/277)) ([105fc05](https://github.com/janus-idp/backstage-plugins/commit/105fc052f817eaeb976f32a388c0f8fa0a09de89)) - -### Other changes - -- **deps:** update all non-major dependencies ([#127](https://github.com/janus-idp/backstage-plugins/issues/127)) ([a9d359f](https://github.com/janus-idp/backstage-plugins/commit/a9d359f01448d1b9b4b4d3d9b087052fb6ff16b3)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.3.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.2.0...@janus-idp/backstage-plugin-keycloak-backend@1.3.0) (2023-04-25) - -### Features - -- **keycloak:** add support for user and group pagination ([#259](https://github.com/janus-idp/backstage-plugins/issues/259)) ([b6e8a49](https://github.com/janus-idp/backstage-plugins/commit/b6e8a49497c068cb7bd5623bb3d810a5f0323e1a)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.2.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.1.0...@janus-idp/backstage-plugin-keycloak-backend@1.2.0) (2023-04-20) - -### Features - -- **keycloak:** Add support for scheduler in config file ([#247](https://github.com/janus-idp/backstage-plugins/issues/247)) ([dcf345f](https://github.com/janus-idp/backstage-plugins/commit/dcf345f8f0ca27f85cb4bf158a1d223cb706bb60)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.1.0](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.0.4...@janus-idp/backstage-plugin-keycloak-backend@1.1.0) (2023-04-19) - -### Features - -- **keycloak:** Add missing config schema ([#141](https://github.com/janus-idp/backstage-plugins/issues/141)) ([e7f30ea](https://github.com/janus-idp/backstage-plugins/commit/e7f30eaf0a3c2f8ebcd78668342dc51bb8130a5b)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.0.4](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.0.3...@janus-idp/backstage-plugin-keycloak-backend@1.0.4) (2023-03-06) - -### Bug Fixes - -- **metadata:** adding default metadata to current plugins ([06776da](https://github.com/janus-idp/backstage-plugins/commit/06776dafdbab6d4fa85b92d5b676f65d97bbdb44)), closes [#155](https://github.com/janus-idp/backstage-plugins/issues/155) [#155](https://github.com/janus-idp/backstage-plugins/issues/155) - -## @janus-idp/backstage-plugin-keycloak-backend [1.0.3](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.0.2...@janus-idp/backstage-plugin-keycloak-backend@1.0.3) (2023-01-25) - -### Bug Fixes - -- **deps:** update all non-major dependencies ([d971f33](https://github.com/janus-idp/backstage-plugins/commit/d971f33c3f79ac4ec36dfb8b579f07d8dbcef8f1)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.0.2](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.0.1...@janus-idp/backstage-plugin-keycloak-backend@1.0.2) (2022-12-12) - -### Bug Fixes - -- **keycloak:** Downgrade to keycloak client v18 ([#46](https://github.com/janus-idp/backstage-plugins/issues/46)) ([24d40ec](https://github.com/janus-idp/backstage-plugins/commit/24d40ec26ad45681b97df16191be6ac6469a9bc6)) - -## @janus-idp/backstage-plugin-keycloak-backend [1.0.1](https://github.com/janus-idp/backstage-plugins/compare/@janus-idp/backstage-plugin-keycloak-backend@1.0.0...@janus-idp/backstage-plugin-keycloak-backend@1.0.1) (2022-12-08) - -### Bug Fixes - -- **deps:** update dependency @keycloak/keycloak-admin-client to v20 ([2bce9a3](https://github.com/janus-idp/backstage-plugins/commit/2bce9a3c328ed8cc694c42fec437abc2e08c6448)) -- **deps:** update dependency uuid to v9 ([50e01ad](https://github.com/janus-idp/backstage-plugins/commit/50e01ad91af4de530ba16a4d3d33a9dbf86413e0)) - -# @janus-idp/backstage-plugin-keycloak-backend 1.0.0 (2022-12-07) - -### Bug Fixes - -- typo in keycloak annotations ([#9](https://github.com/janus-idp/backstage-plugins/issues/9)) ([07f99cf](https://github.com/janus-idp/backstage-plugins/commit/07f99cff02467a3a627c310d14cdb7105009a67a)) - -### Features - -- rename and release keycloak plugin ([#7](https://github.com/janus-idp/backstage-plugins/issues/7)) ([6b5ff5c](https://github.com/janus-idp/backstage-plugins/commit/6b5ff5c3cf657ce05c6566ae2960cb0fb01fb5a9)) diff --git a/plugins/keycloak-backend/CONTRIBUTING.md b/plugins/keycloak-backend/CONTRIBUTING.md deleted file mode 100644 index 9f9b3b67b0..0000000000 --- a/plugins/keycloak-backend/CONTRIBUTING.md +++ /dev/null @@ -1,20 +0,0 @@ -# Setting up the development environment for Keycloak backend plugin - -## Prerequisites - -- Podman - required to stand up a Keycloak instance - -You can run a development setup using the following command: - -```console -yarn start -``` - -This will provision a new Keycloak instance locally via podman and import realm [`janus-realm`](./__fixtures__/keycloak-realm.json). This realm contains 1 group and 0 users (Keycloak currently doesn't support user export/import). - -Once everything is started, you can access: - -- Backstage catalog API at http://localhost:7007/catalog/entities -- Keycloak Admin UI at http://localhost:8080/admin/master/console/#/janus-realm - - Username: `admin` - - Password: `admin` diff --git a/plugins/keycloak-backend/README.md b/plugins/keycloak-backend/README.md index 492801d740..2f76528963 100644 --- a/plugins/keycloak-backend/README.md +++ b/plugins/keycloak-backend/README.md @@ -1,169 +1 @@ -# Keycloak backend plugin for Backstage - -The Keycloak backend plugin integrates Keycloak into Backstage. - -## Capabilities - -The Keycloak backend plugin has the following capabilities: - -- Synchronization of Keycloak users in a realm -- Synchronization of Keycloak groups and their users in a realm - -## For administrators - -### Installation - -Install the Backstage package into the backend. When not integrating with a published package, clone the repository locally and add the Backstage as follows: - -```console -yarn workspace backend add @janus-idp/backstage-plugin-keycloak-backend -``` - -### Configuration - -#### New Backend Configuration - -1. Add the following configuration to the `app-config.yaml` file. The default schedule is a frequency of 30 minutes and a timeout of 3 minutes, please configure the schedule in the `app-config.yaml` as per your requirement. - - ```yaml title="app-config.yaml" - catalog: - providers: - keycloakOrg: - default: - baseUrl: https:// - loginRealm: ${KEYCLOAK_REALM} - realm: ${KEYCLOAK_REALM} - clientId: ${KEYCLOAK_CLIENTID} - clientSecret: ${KEYCLOAK_CLIENTSECRET} - schedule: # Optional (defaults to the configurations below if not provided); same options as in TaskScheduleDefinition - # supports cron, ISO duration, "human duration" as used in code - frequency: { minutes: 30 } # Customize this to fit your needs - # supports ISO duration, "human duration" as used in code - timeout: { minutes: 3 } # Customize this to fit your needs - ``` - -1. Register the plugin in the `packages/backend/src/index.ts` file: - - ```ts title="packages/backend/src/index.ts" - const backend = createBackend(); - - /* highlight-add-next-line */ - backend.add(import('@janus-idp/backstage-plugin-keycloak-backend')); - - backend.start(); - ``` - -1. Optional: To configure custom transformer function for user/group to mutate the entity generated by the keycloak-backend. Create a new backend module with the `yarn new` command and add your custom user and group transformers to the `keycloakTransformerExtensionPoint`. Then install this new backend module into your backstage backend. Below is an example of how the backend module can be defined: - - ```ts title="plugins//src/module.ts" - /* highlight-add-start */ - import { - GroupTransformer, - keycloakTransformerExtensionPoint, - UserTransformer, - } from '@janus-idp/backstage-plugin-keycloak-backend'; - - const customGroupTransformer: GroupTransformer = async ( - entity, - realm, - groups, - ) => { - /* apply transformations */ - return entity; - }; - const customUserTransformer: UserTransformer = async ( - entity, - user, - realm, - groups, - ) => { - /* apply transformations */ - return entity; - }; - /* highlight-add-end */ - - export const keycloakBackendModuleTransformer = createBackendModule({ - pluginId: 'catalog', - moduleId: 'keycloak-transformer', - register(reg) { - reg.registerInit({ - deps: { - /* highlight-add-start */ - keycloak: keycloakTransformerExtensionPoint, - /* highlight-add-end */ - }, - /* highlight-add-start */ - async init({ keycloak }) { - keycloak.setUserTransformer(customUserTransformer); - keycloak.setGroupTransformer(customGroupTransformer); - /* highlight-add-end */ - }, - }); - }, - }); - ``` - - *** - - **IMPORTANT** - - The `pluginId` for the module **MUST** be set to `catalog` to match the `pluginId` of the `keycloak-backend` or else the module will fail to initialize. - - *** - -Communication between Backstage and Keycloak is enabled by using the Keycloak API. Username/password or client credentials are supported authentication methods. - -The following table describes the parameters that you can configure to enable the plugin under `catalog.providers.keycloakOrg.` object in the `app-config.yaml` file: - -| Name | Description | Default Value | Required | -| ---------------- | ------------------------------------------------------------------ | ------------- | ---------------------------------------------------- | -| `baseUrl` | Location of the Keycloak server, such as `https://localhost:8443`. | "" | Yes | -| `realm` | Realm to synchronize | `master` | No | -| `loginRealm` | Realm used to authenticate | `master` | No | -| `username` | Username to authenticate | "" | Yes if using password based authentication | -| `password` | Password to authenticate | "" | Yes if using password based authentication | -| `clientId` | Client ID to authenticate | "" | Yes if using client credentials based authentication | -| `clientSecret` | Client Secret to authenticate | "" | Yes if using client credentials based authentication | -| `userQuerySize` | Number of users to query at a time | `100` | No | -| `groupQuerySize` | Number of groups to query at a time | `100` | No | - -When using client credentials, the access type must be set to `confidential` and service accounts must be enabled. You must also add the following roles from the `realm-management` client role: - -- `query-groups` -- `query-users` -- `view-users` - -### Limitations - -If you have self-signed or corporate certificate issues, you can set the following environment variable before starting Backstage: - -`NODE_TLS_REJECT_UNAUTHORIZED=0` - ---- - -**NOTE** -The solution of setting the `NODE_TLS_REJECT_UNAUTHORIZED` environment variable is not recommended. - ---- - -## For users - -### Imported users and groups in Backstage using Keycloak plugin - -After configuring the plugin successfully, the plugin imports the users and groups each time when started. - -After the first import is complete, you can select **User** to list the users from the catalog page: - -![catalog-list](./images/users.jpg) - -You can see the list of users on the page: - -![user-list](./images/user-list.jpg) - -When you select a user, you can see the information imported from Keycloak: - -![user-profile](./images/user2.jpg) - -You can also select a group, view the list, and select or view the information imported from Keycloak for a group: - -![group-profile](./images/group1.jpg) +This package has been moved to the [backstage-community/plugins](https://github.com/backstage/community-plugins) repository. Migrate to using `@backstage-community/plugin-catalog-backend-module-keycloak` instead. diff --git a/plugins/keycloak-backend/__fixtures__/data.ts b/plugins/keycloak-backend/__fixtures__/data.ts deleted file mode 100644 index af5ebe3a37..0000000000 --- a/plugins/keycloak-backend/__fixtures__/data.ts +++ /dev/null @@ -1,221 +0,0 @@ -export const topLevelGroups23orHigher = [ - { - id: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - name: 'biggroup', - path: '/biggroup', - subGroupCount: 1, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - }, - { - id: '557501bd-8188-41c0-a2d5-43ff3d5b0258', - name: 'emptygroup', - path: '/emptygroup', - subGroupCount: 0, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - }, -]; - -export const topLevelGroupsLowerThan23 = [ - { - id: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - name: 'biggroup', - path: '/biggroup', - subGroups: [ - { - id: 'eefa5b46-0509-41d8-b8b3-7ddae9c83632', - name: 'subgroup', - path: '/biggroup/subgroup', - subGroups: [], - }, - ], - }, - { - id: '557501bd-8188-41c0-a2d5-43ff3d5b0258', - name: 'emptygroup', - path: '/emptygroup', - subGroups: [], - }, -]; - -export const users = [ - { - id: '59efec15-a00b-4700-8833-5f4cdecc1132', - createdTimestamp: 1686170983010, - username: 'jamesdoe', - enabled: true, - totp: false, - emailVerified: false, - firstName: '', - lastName: '', - email: 'jamesdoe@gmail.com', - disableableCredentialTypes: [], - requiredActions: [], - notBefore: 0, - access: { - manageGroupMembership: false, - view: true, - mapRoles: false, - impersonate: false, - manage: false, - }, - }, - { - id: 'c982b51a-abf6-4f68-bfdf-a1c6257214fc', - createdTimestamp: 1686170953553, - username: 'joedoe', - enabled: true, - totp: false, - emailVerified: false, - firstName: '', - lastName: '', - disableableCredentialTypes: [], - requiredActions: [], - notBefore: 0, - access: { - manageGroupMembership: false, - view: true, - mapRoles: false, - impersonate: false, - manage: false, - }, - }, - { - id: '2bf97dbd-fd6a-47ae-986b-2632fa95e03f', - createdTimestamp: 1686170890908, - username: 'johndoe', - enabled: true, - totp: false, - emailVerified: false, - firstName: 'John', - lastName: 'Doe', - disableableCredentialTypes: [], - requiredActions: [], - notBefore: 0, - access: { - manageGroupMembership: false, - view: true, - mapRoles: false, - impersonate: false, - manage: false, - }, - }, -]; - -export const groupMembers1 = ['jamesdoe']; -export const groupMembers2 = ['jamesdoe', 'joedoe', 'johndoe']; - -export const kGroups23orHigher = [ - { - id: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - name: 'biggroup', - path: '/biggroup', - subGroupCount: 1, - subGroups: [ - { - id: 'eefa5b46-0509-41d8-b8b3-7ddae9c83632', - name: 'subgroup', - path: '/biggroup/subgroup', - parentId: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - subGroupCount: 0, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - members: [], - parent: 'biggroup', - }, - ], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - members: ['jamesdoe'], - }, - { - id: 'eefa5b46-0509-41d8-b8b3-7ddae9c83632', - name: 'subgroup', - path: '/biggroup/subgroup', - parentId: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - subGroupCount: 0, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - members: [], - parent: 'biggroup', - }, - { - id: '557501bd-8188-41c0-a2d5-43ff3d5b0258', - name: 'emptygroup', - path: '/emptygroup', - subGroupCount: 0, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - members: [], - }, -]; - -export const kGroupsLowerThan23 = [ - { - id: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - name: 'biggroup', - path: '/biggroup', - subGroups: [ - { - id: 'eefa5b46-0509-41d8-b8b3-7ddae9c83632', - name: 'subgroup', - path: '/biggroup/subgroup', - subGroups: [], - parent: 'big-group', - members: [], - }, - ], - members: ['jamesdoe'], - }, - { - id: 'eefa5b46-0509-41d8-b8b3-7ddae9c83632', - name: 'subgroup', - path: '/biggroup/subgroup', - subGroups: [], - parent: 'biggroup', - members: [], - }, - { - id: '557501bd-8188-41c0-a2d5-43ff3d5b0258', - name: 'emptygroup', - path: '/emptygroup', - subGroups: [], - members: [], - }, -]; diff --git a/plugins/keycloak-backend/__fixtures__/helpers.ts b/plugins/keycloak-backend/__fixtures__/helpers.ts deleted file mode 100644 index 443f9a1f86..0000000000 --- a/plugins/keycloak-backend/__fixtures__/helpers.ts +++ /dev/null @@ -1,164 +0,0 @@ -import type { LoggerService } from '@backstage/backend-plugin-api'; -import type { ServiceMock } from '@backstage/backend-test-utils'; - -import { - groupMembers1, - groupMembers2, - topLevelGroups23orHigher, - topLevelGroupsLowerThan23, - users, -} from './data'; - -export const CONFIG = { - catalog: { - providers: { - keycloakOrg: { - default: { - baseUrl: 'http://localhost:8080', - }, - }, - }, - }, -} as const; - -export const PASSWORD_CONFIG = { - catalog: { - providers: { - keycloakOrg: { - default: { - baseUrl: 'http://localhost:8080', - username: 'myusername', - password: 'mypassword', // NOSONAR - }, - }, - }, - }, -} as const; - -export const assertLogMustNotInclude = ( - logger: ServiceMock, - secrets: string[], -) => { - const logMethods: (keyof LoggerService)[] = [ - 'debug', - 'error', - 'info', - 'warn', - ]; - logMethods.forEach(methodName => { - const method = logger[methodName]; - if (jest.isMockFunction(method)) { - const json = JSON.stringify(method.mock.calls); - secrets.forEach(secret => { - if (json.includes(secret)) { - throw new Error(`Log must not include secret "${secret}"`); - } - }); - } - }); -}; - -export const authMock = jest.fn(); - -export class KeycloakAdminClientMockServerv18 { - public constructor() { - return; - } - - serverInfo = { - find: jest.fn().mockResolvedValue({ - systemInfo: { - version: '18.0.6.redhat-00001', - }, - }), - }; - - users = { - find: jest.fn().mockResolvedValue(users), - count: jest.fn().mockResolvedValue(users.length), - }; - - groups = { - find: jest.fn().mockResolvedValue(topLevelGroupsLowerThan23), - count: jest.fn().mockResolvedValue(3), - listMembers: jest - .fn() - .mockResolvedValueOnce(groupMembers1.map(username => ({ username }))) - // stop second pagination fetch for groupMembers1 - .mockResolvedValueOnce([]) - // return empty list members - .mockResolvedValueOnce([]) - // return empty list members - .mockResolvedValueOnce([]) - .mockResolvedValueOnce(groupMembers2.map(username => ({ username }))), - }; - - auth = authMock; -} - -export class KeycloakAdminClientMockServerv24 { - public constructor() { - return; - } - - serverInfo = { - find: jest.fn().mockResolvedValue({ - systemInfo: { - version: '24.0.6.redhat-00001', - }, - }), - }; - - users = { - find: jest.fn().mockResolvedValue(users), - count: jest.fn().mockResolvedValue(users.length), - }; - - groups = { - find: jest.fn().mockResolvedValue(topLevelGroups23orHigher), - findOne: jest.fn().mockResolvedValue({ - id: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - name: 'biggroup', - path: '/biggroup', - subGroupCount: 1, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - }), - count: jest.fn().mockResolvedValue(3), - listSubGroups: jest.fn().mockResolvedValue([ - { - id: 'eefa5b46-0509-41d8-b8b3-7ddae9c83632', - name: 'subgroup', - path: '/biggroup/subgroup', - parentId: '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - subGroupCount: 0, - subGroups: [], - access: { - view: true, - viewMembers: true, - manageMembers: false, - manage: false, - manageMembership: false, - }, - }, - ]), - listMembers: jest - .fn() - .mockResolvedValueOnce(groupMembers1.map(username => ({ username }))) - // return empty list for second pagination page of the groupMembers1. - .mockResolvedValueOnce([]) - // return empty list members - .mockResolvedValueOnce([]) - // return empty list members - .mockResolvedValueOnce([]) - .mockResolvedValueOnce(groupMembers2.map(username => ({ username }))), - }; - - auth = authMock; -} diff --git a/plugins/keycloak-backend/__fixtures__/keycloak-realm.json b/plugins/keycloak-backend/__fixtures__/keycloak-realm.json deleted file mode 100644 index bdb4f6970e..0000000000 --- a/plugins/keycloak-backend/__fixtures__/keycloak-realm.json +++ /dev/null @@ -1,2052 +0,0 @@ -{ - "id": "83b8f3da-9878-486e-97de-66d55c20bd84", - "realm": "janus-realm", - "notBefore": 0, - "defaultSignatureAlgorithm": "RS256", - "revokeRefreshToken": false, - "refreshTokenMaxReuse": 0, - "accessTokenLifespan": 300, - "accessTokenLifespanForImplicitFlow": 900, - "ssoSessionIdleTimeout": 1800, - "ssoSessionMaxLifespan": 36000, - "ssoSessionIdleTimeoutRememberMe": 0, - "ssoSessionMaxLifespanRememberMe": 0, - "offlineSessionIdleTimeout": 2592000, - "offlineSessionMaxLifespanEnabled": false, - "offlineSessionMaxLifespan": 5184000, - "clientSessionIdleTimeout": 0, - "clientSessionMaxLifespan": 0, - "clientOfflineSessionIdleTimeout": 0, - "clientOfflineSessionMaxLifespan": 0, - "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, - "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, - "oauth2DeviceCodeLifespan": 600, - "oauth2DevicePollingInterval": 5, - "enabled": true, - "sslRequired": "external", - "registrationAllowed": false, - "registrationEmailAsUsername": false, - "rememberMe": false, - "verifyEmail": false, - "loginWithEmailAllowed": true, - "duplicateEmailsAllowed": false, - "resetPasswordAllowed": false, - "editUsernameAllowed": false, - "bruteForceProtected": false, - "permanentLockout": false, - "maxFailureWaitSeconds": 900, - "minimumQuickLoginWaitSeconds": 60, - "waitIncrementSeconds": 60, - "quickLoginCheckMilliSeconds": 1000, - "maxDeltaTimeSeconds": 43200, - "failureFactor": 30, - "roles": { - "realm": [ - { - "id": "90d976fc-1610-44c5-88a7-90d4691ff9db", - "name": "uma_authorization", - "description": "${role_uma_authorization}", - "composite": false, - "clientRole": false, - "containerId": "83b8f3da-9878-486e-97de-66d55c20bd84", - "attributes": {} - }, - { - "id": "01ac4e96-830b-4a2a-bc16-d1644a39d16f", - "name": "offline_access", - "description": "${role_offline-access}", - "composite": false, - "clientRole": false, - "containerId": "83b8f3da-9878-486e-97de-66d55c20bd84", - "attributes": {} - }, - { - "id": "a33fe2dd-cdb6-4c71-84a7-25de0bf129c8", - "name": "default-roles-janus-realm", - "description": "${role_default-roles}", - "composite": true, - "composites": { - "realm": ["offline_access", "uma_authorization"], - "client": { - "account": ["view-profile", "manage-account"] - } - }, - "clientRole": false, - "containerId": "83b8f3da-9878-486e-97de-66d55c20bd84", - "attributes": {} - } - ], - "client": { - "realm-management": [ - { - "id": "e82af0af-ef7f-4b80-8ef7-dc78b3ea9485", - "name": "manage-authorization", - "description": "${role_manage-authorization}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "a4fce413-4de3-4665-9027-670e67e27066", - "name": "manage-events", - "description": "${role_manage-events}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "002afe79-7855-4138-bd5a-0373f21bd5a3", - "name": "manage-users", - "description": "${role_manage-users}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "d8a24c1c-99b1-4b7d-933b-84b77221ece6", - "name": "view-realm", - "description": "${role_view-realm}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "7cee5057-cb0a-456d-b1c3-ee8d5aa61f0c", - "name": "create-client", - "description": "${role_create-client}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "eff88e4e-7faa-4129-9c6b-6485afd05d36", - "name": "manage-clients", - "description": "${role_manage-clients}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "6a6bd8bb-a58a-4b12-a23e-7f600ce1060b", - "name": "view-identity-providers", - "description": "${role_view-identity-providers}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "3c5044fc-2d57-4e45-b0ec-081a162388c5", - "name": "view-authorization", - "description": "${role_view-authorization}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "1a3371ab-4325-4c53-bcb5-c5f69ba1c038", - "name": "manage-identity-providers", - "description": "${role_manage-identity-providers}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "226ece14-5d78-4801-9274-67ae9c114b95", - "name": "manage-realm", - "description": "${role_manage-realm}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "543ef949-3f49-43c3-8ae8-0a950e3d8820", - "name": "view-clients", - "description": "${role_view-clients}", - "composite": true, - "composites": { - "client": { - "realm-management": ["query-clients"] - } - }, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "091ede21-e501-4ec2-8739-b9437f8760b4", - "name": "query-clients", - "description": "${role_query-clients}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "2ef9fa6b-31d6-4880-a12e-30fd7c09a46c", - "name": "query-groups", - "description": "${role_query-groups}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "b00d0c3a-f148-456a-bb47-28ad7321a0e7", - "name": "query-users", - "description": "${role_query-users}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "2daf19b3-ab08-4e62-a9b4-07f37338ccd4", - "name": "view-users", - "description": "${role_view-users}", - "composite": true, - "composites": { - "client": { - "realm-management": ["query-groups", "query-users"] - } - }, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "9e18cf59-5b92-44d2-b9e6-dc469494f7ff", - "name": "realm-admin", - "description": "${role_realm-admin}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "manage-users", - "manage-events", - "manage-authorization", - "view-realm", - "create-client", - "manage-clients", - "view-identity-providers", - "view-authorization", - "manage-identity-providers", - "manage-realm", - "view-clients", - "query-clients", - "query-groups", - "view-users", - "query-users", - "impersonation", - "query-realms", - "view-events" - ] - } - }, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "a7746d52-f622-4751-ba79-f8ae0fd2445c", - "name": "impersonation", - "description": "${role_impersonation}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "39659b42-dabf-4e27-a719-28fbbbb1bc70", - "name": "query-realms", - "description": "${role_query-realms}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - }, - { - "id": "2afe989f-2c2e-4d8c-9122-3392fe5b0275", - "name": "view-events", - "description": "${role_view-events}", - "composite": false, - "clientRole": true, - "containerId": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "attributes": {} - } - ], - "security-admin-console": [], - "admin-cli": [], - "account-console": [], - "broker": [ - { - "id": "7e53b1a8-b06a-4050-9dad-46c84c9c5fec", - "name": "read-token", - "description": "${role_read-token}", - "composite": false, - "clientRole": true, - "containerId": "bebc89c7-2205-4591-8146-2d589346ec8f", - "attributes": {} - } - ], - "account": [ - { - "id": "db4696c3-6923-4a8d-9def-9ade6ed19d3a", - "name": "view-applications", - "description": "${role_view-applications}", - "composite": false, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "8406e3f3-7925-411e-a0de-65ad7e405fd1", - "name": "view-groups", - "description": "${role_view-groups}", - "composite": false, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "ab9eeb9c-a84d-4ac9-a9ae-9621c22cecd5", - "name": "view-profile", - "description": "${role_view-profile}", - "composite": false, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "e0910d7d-b7eb-46ab-ae69-7ff20149efb8", - "name": "manage-account-links", - "description": "${role_manage-account-links}", - "composite": false, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "39bd1672-d865-4bab-bba9-a8e4b386eb55", - "name": "delete-account", - "description": "${role_delete-account}", - "composite": false, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "59707806-80b8-4988-a091-4bde646744b6", - "name": "view-consent", - "description": "${role_view-consent}", - "composite": false, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "60627597-b333-4516-b266-7c2263ba3c0b", - "name": "manage-consent", - "description": "${role_manage-consent}", - "composite": true, - "composites": { - "client": { - "account": ["view-consent"] - } - }, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - }, - { - "id": "d3c1dc9e-5c1d-48b4-b1df-861efff80fbd", - "name": "manage-account", - "description": "${role_manage-account}", - "composite": true, - "composites": { - "client": { - "account": ["manage-account-links"] - } - }, - "clientRole": true, - "containerId": "e55e7820-963c-4714-bc25-067ee9efcc28", - "attributes": {} - } - ] - } - }, - "groups": [ - { - "id": "c53343db-f8d9-44f6-9ce3-d34df264066a", - "name": "backstage", - "path": "/backstage", - "attributes": {}, - "realmRoles": [], - "clientRoles": {}, - "subGroups": [] - } - ], - "defaultRole": { - "id": "a33fe2dd-cdb6-4c71-84a7-25de0bf129c8", - "name": "default-roles-janus-realm", - "description": "${role_default-roles}", - "composite": true, - "clientRole": false, - "containerId": "83b8f3da-9878-486e-97de-66d55c20bd84" - }, - "requiredCredentials": ["password"], - "otpPolicyType": "totp", - "otpPolicyAlgorithm": "HmacSHA1", - "otpPolicyInitialCounter": 0, - "otpPolicyDigits": 6, - "otpPolicyLookAheadWindow": 1, - "otpPolicyPeriod": 30, - "otpPolicyCodeReusable": false, - "otpSupportedApplications": [ - "totpAppMicrosoftAuthenticatorName", - "totpAppFreeOTPName", - "totpAppGoogleName" - ], - "webAuthnPolicyRpEntityName": "keycloak", - "webAuthnPolicySignatureAlgorithms": ["ES256"], - "webAuthnPolicyRpId": "", - "webAuthnPolicyAttestationConveyancePreference": "not specified", - "webAuthnPolicyAuthenticatorAttachment": "not specified", - "webAuthnPolicyRequireResidentKey": "not specified", - "webAuthnPolicyUserVerificationRequirement": "not specified", - "webAuthnPolicyCreateTimeout": 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister": false, - "webAuthnPolicyAcceptableAaguids": [], - "webAuthnPolicyPasswordlessRpEntityName": "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256"], - "webAuthnPolicyPasswordlessRpId": "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", - "webAuthnPolicyPasswordlessCreateTimeout": 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, - "webAuthnPolicyPasswordlessAcceptableAaguids": [], - "scopeMappings": [ - { - "clientScope": "offline_access", - "roles": ["offline_access"] - } - ], - "clientScopeMappings": { - "account": [ - { - "client": "account-console", - "roles": ["manage-account", "view-groups"] - } - ] - }, - "clients": [ - { - "id": "e55e7820-963c-4714-bc25-067ee9efcc28", - "clientId": "account", - "name": "${client_account}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/janus-realm/account/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": ["/realms/janus-realm/account/*"], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "post.logout.redirect.uris": "+" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "674579cb-6d2f-4a35-9723-3a4232140562", - "clientId": "account-console", - "name": "${client_account-console}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/janus-realm/account/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": ["/realms/janus-realm/account/*"], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "post.logout.redirect.uris": "+", - "pkce.code.challenge.method": "S256" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "protocolMappers": [ - { - "id": "3e521290-0619-4298-ba73-64aa0220e6b9", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - } - ], - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "594ac44f-ef8f-4a21-b4de-27f9dbfee21b", - "clientId": "admin-cli", - "name": "${client_admin-cli}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": false, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "bebc89c7-2205-4591-8146-2d589346ec8f", - "clientId": "broker", - "name": "${client_broker}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": true, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "e510b5e0-d019-4e4a-8f5e-7143a89ea311", - "clientId": "realm-management", - "name": "${client_realm-management}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": true, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "d7d1cb94-ad0c-4c97-9156-d44ee4f3a968", - "clientId": "security-admin-console", - "name": "${client_security-admin-console}", - "rootUrl": "${authAdminUrl}", - "baseUrl": "/admin/janus-realm/console/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": ["/admin/janus-realm/console/*"], - "webOrigins": ["+"], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "post.logout.redirect.uris": "+", - "pkce.code.challenge.method": "S256" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "protocolMappers": [ - { - "id": "2133ebbb-1d8d-4366-ace1-d66ea3e79992", - "name": "locale", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "locale", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "locale", - "jsonType.label": "String" - } - } - ], - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - } - ], - "clientScopes": [ - { - "id": "5d8bc508-3310-4e76-802b-0386e3dfd4e5", - "name": "email", - "description": "OpenID Connect built-in scope: email", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${emailScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "d1019ef0-318c-4199-9dcb-b1ce88ed2f7c", - "name": "email verified", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "emailVerified", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "email_verified", - "jsonType.label": "boolean" - } - }, - { - "id": "21116fc2-1066-4f8b-b9fd-1baf3aaea511", - "name": "email", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "email", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "email", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "bac41b44-abfb-48c4-a9c6-cde0ba6862a9", - "name": "roles", - "description": "OpenID Connect scope for add user roles to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "bed0e621-b996-4ed5-8af9-d033a581a5e0", - "name": "realm roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "realm_access.roles", - "jsonType.label": "String", - "multivalued": "true" - } - }, - { - "id": "1a937cbc-7661-4f91-ab96-3d9ef1a8145d", - "name": "client roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-client-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "resource_access.${client_id}.roles", - "jsonType.label": "String", - "multivalued": "true" - } - }, - { - "id": "b756c0b9-08c8-4ee6-a1ea-c79a461c6035", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - } - ] - }, - { - "id": "1fa9816c-c276-4d33-a0e7-1c66311cae22", - "name": "acr", - "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "false" - }, - "protocolMappers": [ - { - "id": "ae301d21-c843-4681-9e15-4d13b9c44113", - "name": "acr loa level", - "protocol": "openid-connect", - "protocolMapper": "oidc-acr-mapper", - "consentRequired": false, - "config": { - "id.token.claim": "true", - "access.token.claim": "true" - } - } - ] - }, - { - "id": "735e7dff-f609-4e6a-94d8-23e06e74a73a", - "name": "microprofile-jwt", - "description": "Microprofile - JWT built-in scope", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "false" - }, - "protocolMappers": [ - { - "id": "1711c7c6-fa56-40a3-b3a5-4c0661b770b4", - "name": "upn", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "username", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "upn", - "jsonType.label": "String" - } - }, - { - "id": "94d056c6-1bd1-49ba-8cdc-e274bad4029a", - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "user.attribute": "foo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "ff5d3bcc-a82a-469b-b18f-53db23cac20f", - "name": "profile", - "description": "OpenID Connect built-in scope: profile", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${profileScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "0498f8bc-1fbc-40b7-b911-a1aa51c6811e", - "name": "username", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "username", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "preferred_username", - "jsonType.label": "String" - } - }, - { - "id": "1da66160-0125-46c5-bc9c-9e2be12e69b6", - "name": "profile", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "profile", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "profile", - "jsonType.label": "String" - } - }, - { - "id": "d5786d80-b347-4eda-88a0-8a9ec9174a1c", - "name": "zoneinfo", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "zoneinfo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "zoneinfo", - "jsonType.label": "String" - } - }, - { - "id": "3606d0a7-76e9-44dc-a2fe-a5b0c131ac7a", - "name": "picture", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "picture", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "picture", - "jsonType.label": "String" - } - }, - { - "id": "7fb7b613-5a3d-4408-90ad-6b4e0e2e7cb3", - "name": "nickname", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "nickname", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "nickname", - "jsonType.label": "String" - } - }, - { - "id": "1e9c19f9-99cd-4e90-9585-42b121e348db", - "name": "family name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "lastName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "family_name", - "jsonType.label": "String" - } - }, - { - "id": "1605a44c-03ac-4e1b-b62f-8361b0a78a7f", - "name": "updated at", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "updatedAt", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "updated_at", - "jsonType.label": "long" - } - }, - { - "id": "f6a35204-ba0a-4a7f-890f-93e8456b8eea", - "name": "website", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "website", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "website", - "jsonType.label": "String" - } - }, - { - "id": "c0b23749-fcfb-40f9-aeaa-ba9c46816db0", - "name": "locale", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "locale", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "locale", - "jsonType.label": "String" - } - }, - { - "id": "47278987-a011-40e6-a249-8c99633377fd", - "name": "middle name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "middleName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "middle_name", - "jsonType.label": "String" - } - }, - { - "id": "25a4f5b8-d8b0-4a03-acc7-7cb19c5d5a54", - "name": "given name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "firstName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "given_name", - "jsonType.label": "String" - } - }, - { - "id": "81cca8a5-2e61-4bfe-8cf5-caa4d918273c", - "name": "birthdate", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "birthdate", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "birthdate", - "jsonType.label": "String" - } - }, - { - "id": "552e3cc4-db5e-4b19-a392-cbee13de3d31", - "name": "gender", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "gender", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "gender", - "jsonType.label": "String" - } - }, - { - "id": "0105ba7d-9536-4864-9eae-0528ba7f4eae", - "name": "full name", - "protocol": "openid-connect", - "protocolMapper": "oidc-full-name-mapper", - "consentRequired": false, - "config": { - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - } - ] - }, - { - "id": "3ad0127b-86df-43fc-be9b-f2d533061c31", - "name": "address", - "description": "OpenID Connect built-in scope: address", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${addressScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "7dbfd5f9-e83c-4271-93f4-1af3ab4b1fdd", - "name": "address", - "protocol": "openid-connect", - "protocolMapper": "oidc-address-mapper", - "consentRequired": false, - "config": { - "user.attribute.formatted": "formatted", - "user.attribute.country": "country", - "user.attribute.postal_code": "postal_code", - "userinfo.token.claim": "true", - "user.attribute.street": "street", - "id.token.claim": "true", - "user.attribute.region": "region", - "access.token.claim": "true", - "user.attribute.locality": "locality" - } - } - ] - }, - { - "id": "3acb11d3-af64-48ce-9603-9c3b0b9b69ab", - "name": "role_list", - "description": "SAML role list", - "protocol": "saml", - "attributes": { - "consent.screen.text": "${samlRoleListScopeConsentText}", - "display.on.consent.screen": "true" - }, - "protocolMappers": [ - { - "id": "48651b96-f2be-4eef-a496-191c6989cd2b", - "name": "role list", - "protocol": "saml", - "protocolMapper": "saml-role-list-mapper", - "consentRequired": false, - "config": { - "single": "false", - "attribute.nameformat": "Basic", - "attribute.name": "Role" - } - } - ] - }, - { - "id": "f2f5197e-8e28-48c1-983e-48888216002d", - "name": "phone", - "description": "OpenID Connect built-in scope: phone", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${phoneScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "347090cb-fc3e-4012-82bb-2bdd5703f340", - "name": "phone number", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "phoneNumber", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "phone_number", - "jsonType.label": "String" - } - }, - { - "id": "3e55742a-f9ab-47b9-9959-c5da479a9823", - "name": "phone number verified", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "phoneNumberVerified", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "phone_number_verified", - "jsonType.label": "boolean" - } - } - ] - }, - { - "id": "ca6246ea-ad6f-4fab-a3da-154d798e4e44", - "name": "offline_access", - "description": "OpenID Connect built-in scope: offline_access", - "protocol": "openid-connect", - "attributes": { - "consent.screen.text": "${offlineAccessScopeConsentText}", - "display.on.consent.screen": "true" - } - }, - { - "id": "edc3e147-7f74-42d0-b2cc-767f05b1b0de", - "name": "web-origins", - "description": "OpenID Connect scope for add allowed web origins to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "false", - "consent.screen.text": "" - }, - "protocolMappers": [ - { - "id": "fbc82fdb-3afb-4d1d-80b6-3d8865a9beab", - "name": "allowed web origins", - "protocol": "openid-connect", - "protocolMapper": "oidc-allowed-origins-mapper", - "consentRequired": false, - "config": {} - } - ] - } - ], - "defaultDefaultClientScopes": [ - "role_list", - "profile", - "email", - "roles", - "web-origins", - "acr" - ], - "defaultOptionalClientScopes": [ - "offline_access", - "address", - "phone", - "microprofile-jwt" - ], - "browserSecurityHeaders": { - "contentSecurityPolicyReportOnly": "", - "xContentTypeOptions": "nosniff", - "referrerPolicy": "no-referrer", - "xRobotsTag": "none", - "xFrameOptions": "SAMEORIGIN", - "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection": "1; mode=block", - "strictTransportSecurity": "max-age=31536000; includeSubDomains" - }, - "smtpServer": {}, - "eventsEnabled": false, - "eventsListeners": ["jboss-logging"], - "enabledEventTypes": [], - "adminEventsEnabled": false, - "adminEventsDetailsEnabled": false, - "identityProviders": [], - "identityProviderMappers": [], - "components": { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ - { - "id": "07f2f53e-1766-4622-b722-a7ced47ab5b5", - "name": "Trusted Hosts", - "providerId": "trusted-hosts", - "subType": "anonymous", - "subComponents": {}, - "config": { - "host-sending-registration-request-must-match": ["true"], - "client-uris-must-match": ["true"] - } - }, - { - "id": "4bb6dd24-c06b-4274-9075-8c2234c569ed", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "saml-user-property-mapper", - "oidc-address-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-full-name-mapper", - "oidc-usermodel-property-mapper", - "saml-role-list-mapper", - "saml-user-attribute-mapper", - "oidc-sha256-pairwise-sub-mapper" - ] - } - }, - { - "id": "f1497710-4cd9-4266-b6b3-6232610639b4", - "name": "Consent Required", - "providerId": "consent-required", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { - "id": "a0707c32-73e1-4522-8613-8469c46588f3", - "name": "Full Scope Disabled", - "providerId": "scope", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { - "id": "ab5fcca2-c9a1-4ecb-916e-be8986f7e6bd", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allow-default-scopes": ["true"] - } - }, - { - "id": "674d2549-e823-483f-8d8a-23a72f3147bb", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-sha256-pairwise-sub-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-full-name-mapper", - "saml-user-attribute-mapper", - "saml-user-property-mapper", - "oidc-address-mapper", - "oidc-usermodel-property-mapper", - "saml-role-list-mapper" - ] - } - }, - { - "id": "b0436d40-d75e-469e-b465-0868fe748f0b", - "name": "Max Clients Limit", - "providerId": "max-clients", - "subType": "anonymous", - "subComponents": {}, - "config": { - "max-clients": ["200"] - } - }, - { - "id": "0b4a9e7a-2506-469d-9383-53088f64b5b8", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allow-default-scopes": ["true"] - } - } - ], - "org.keycloak.keys.KeyProvider": [ - { - "id": "43f5acd8-edf7-4807-a74c-6ac9cc18c561", - "name": "hmac-generated", - "providerId": "hmac-generated", - "subComponents": {}, - "config": { - "priority": ["100"], - "algorithm": ["HS256"] - } - }, - { - "id": "9807d16d-2a5a-40cd-883e-804bcb840eb7", - "name": "aes-generated", - "providerId": "aes-generated", - "subComponents": {}, - "config": { - "priority": ["100"] - } - }, - { - "id": "069df55d-b827-4435-97a8-999e69299881", - "name": "rsa-generated", - "providerId": "rsa-generated", - "subComponents": {}, - "config": { - "priority": ["100"] - } - }, - { - "id": "e37fff82-0b34-486e-ab05-26542f9f35d5", - "name": "rsa-enc-generated", - "providerId": "rsa-enc-generated", - "subComponents": {}, - "config": { - "priority": ["100"], - "algorithm": ["RSA-OAEP"] - } - } - ] - }, - "internationalizationEnabled": false, - "supportedLocales": [], - "authenticationFlows": [ - { - "id": "a372b56a-09dc-4ec0-8aca-ece69761f714", - "alias": "Account verification options", - "description": "Method with which to verity the existing account", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-email-verification", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "ALTERNATIVE", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Verify Existing Account by Re-authentication", - "userSetupAllowed": false - } - ] - }, - { - "id": "4557499b-08d3-4153-9d7d-e72004883f92", - "alias": "Browser - Conditional OTP", - "description": "Flow to determine if the OTP is required for the authentication", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-otp-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "1b8ece35-84c1-4697-9ee0-671a805ab3f3", - "alias": "Direct Grant - Conditional OTP", - "description": "Flow to determine if the OTP is required for the authentication", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "direct-grant-validate-otp", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "f4731392-5bf6-4a16-9d79-eedd531e596e", - "alias": "First broker login - Conditional OTP", - "description": "Flow to determine if the OTP is required for the authentication", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-otp-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "4872dbc1-7d64-48a9-a87e-aa57e5b9e545", - "alias": "Handle Existing Account", - "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-confirm-link", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Account verification options", - "userSetupAllowed": false - } - ] - }, - { - "id": "61e2c9cf-2602-459d-a51d-f0fb2db54c7d", - "alias": "Reset - Conditional OTP", - "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "reset-otp", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "a715b856-b653-4c6f-8e7f-16e5ef375ef4", - "alias": "User creation or linking", - "description": "Flow for the existing/non-existing user alternatives", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticatorConfig": "create unique user config", - "authenticator": "idp-create-user-if-unique", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "ALTERNATIVE", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Handle Existing Account", - "userSetupAllowed": false - } - ] - }, - { - "id": "c8358901-6bd1-4e9d-ac33-07b948b623b4", - "alias": "Verify Existing Account by Re-authentication", - "description": "Reauthentication of existing account", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-username-password-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "First broker login - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "c7dd2361-1e05-471e-b3e7-70c8057ca43a", - "alias": "browser", - "description": "browser based authentication", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "auth-cookie", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-spnego", - "authenticatorFlow": false, - "requirement": "DISABLED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "identity-provider-redirector", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 25, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "ALTERNATIVE", - "priority": 30, - "autheticatorFlow": true, - "flowAlias": "forms", - "userSetupAllowed": false - } - ] - }, - { - "id": "e4afdae9-c924-43fe-aa9e-c06527b81ae3", - "alias": "clients", - "description": "Base authentication for clients", - "providerId": "client-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "client-secret", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "client-jwt", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "client-secret-jwt", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 30, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "client-x509", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 40, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "15b23070-182d-4a3b-a234-106d678d8799", - "alias": "direct grant", - "description": "OpenID Connect Resource Owner Grant", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "direct-grant-validate-username", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "direct-grant-validate-password", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 30, - "autheticatorFlow": true, - "flowAlias": "Direct Grant - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "7a1a78bd-07bb-4938-9299-e5c0780e5a78", - "alias": "docker auth", - "description": "Used by Docker clients to authenticate against the IDP", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "docker-http-basic-authenticator", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "c2f91902-423e-4f2f-91d3-c8f8b11d3b2a", - "alias": "first broker login", - "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticatorConfig": "review profile config", - "authenticator": "idp-review-profile", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "User creation or linking", - "userSetupAllowed": false - } - ] - }, - { - "id": "ee38a43f-ca36-49d4-b876-bed447420a70", - "alias": "forms", - "description": "Username, password, otp and other auth forms.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "auth-username-password-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Browser - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "04360a9e-6612-4044-8a62-d6be51b6877f", - "alias": "registration", - "description": "registration flow", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "registration-page-form", - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": true, - "flowAlias": "registration form", - "userSetupAllowed": false - } - ] - }, - { - "id": "d1fde771-67f5-4a29-9af3-3c585c32cb3b", - "alias": "registration form", - "description": "registration form", - "providerId": "form-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "registration-user-creation", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "registration-profile-action", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 40, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "registration-password-action", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 50, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "registration-recaptcha-action", - "authenticatorFlow": false, - "requirement": "DISABLED", - "priority": 60, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "d6164e08-aba2-4a17-913b-147c2246e050", - "alias": "reset credentials", - "description": "Reset credentials for a user if they forgot their password or something", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "reset-credentials-choose-user", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "reset-credential-email", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "reset-password", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 30, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 40, - "autheticatorFlow": true, - "flowAlias": "Reset - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "5351cce5-2cac-4149-b893-8de44f377edb", - "alias": "saml ecp", - "description": "SAML ECP Profile Authentication Flow", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "http-basic-authenticator", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - } - ], - "authenticatorConfig": [ - { - "id": "aa05e83c-2ea2-4961-a46d-afdcb886746e", - "alias": "create unique user config", - "config": { - "require.password.update.after.registration": "false" - } - }, - { - "id": "be86a576-a0ad-44a6-a2da-e73eea766a41", - "alias": "review profile config", - "config": { - "update.profile.on.first.login": "missing" - } - } - ], - "requiredActions": [ - { - "alias": "CONFIGURE_TOTP", - "name": "Configure OTP", - "providerId": "CONFIGURE_TOTP", - "enabled": true, - "defaultAction": false, - "priority": 10, - "config": {} - }, - { - "alias": "TERMS_AND_CONDITIONS", - "name": "Terms and Conditions", - "providerId": "TERMS_AND_CONDITIONS", - "enabled": false, - "defaultAction": false, - "priority": 20, - "config": {} - }, - { - "alias": "UPDATE_PASSWORD", - "name": "Update Password", - "providerId": "UPDATE_PASSWORD", - "enabled": true, - "defaultAction": false, - "priority": 30, - "config": {} - }, - { - "alias": "UPDATE_PROFILE", - "name": "Update Profile", - "providerId": "UPDATE_PROFILE", - "enabled": true, - "defaultAction": false, - "priority": 40, - "config": {} - }, - { - "alias": "VERIFY_EMAIL", - "name": "Verify Email", - "providerId": "VERIFY_EMAIL", - "enabled": true, - "defaultAction": false, - "priority": 50, - "config": {} - }, - { - "alias": "delete_account", - "name": "Delete Account", - "providerId": "delete_account", - "enabled": false, - "defaultAction": false, - "priority": 60, - "config": {} - }, - { - "alias": "webauthn-register", - "name": "Webauthn Register", - "providerId": "webauthn-register", - "enabled": true, - "defaultAction": false, - "priority": 70, - "config": {} - }, - { - "alias": "webauthn-register-passwordless", - "name": "Webauthn Register Passwordless", - "providerId": "webauthn-register-passwordless", - "enabled": true, - "defaultAction": false, - "priority": 80, - "config": {} - }, - { - "alias": "update_user_locale", - "name": "Update User Locale", - "providerId": "update_user_locale", - "enabled": true, - "defaultAction": false, - "priority": 1000, - "config": {} - } - ], - "browserFlow": "browser", - "registrationFlow": "registration", - "directGrantFlow": "direct grant", - "resetCredentialsFlow": "reset credentials", - "clientAuthenticationFlow": "clients", - "dockerAuthenticationFlow": "docker auth", - "attributes": { - "cibaBackchannelTokenDeliveryMode": "poll", - "cibaExpiresIn": "120", - "cibaAuthRequestedUserHint": "login_hint", - "oauth2DeviceCodeLifespan": "600", - "oauth2DevicePollingInterval": "5", - "parRequestUriLifespan": "60", - "cibaInterval": "5", - "realmReusableOtpCode": "false" - }, - "keycloakVersion": "22.0.1", - "userManagedAccessAllowed": false, - "clientProfiles": { - "profiles": [] - }, - "clientPolicies": { - "policies": [] - } -} diff --git a/plugins/keycloak-backend/app-config.janus-idp.yaml b/plugins/keycloak-backend/app-config.janus-idp.yaml deleted file mode 100644 index 146f64a1fa..0000000000 --- a/plugins/keycloak-backend/app-config.janus-idp.yaml +++ /dev/null @@ -1,11 +0,0 @@ -enabled: - keycloak: true -catalog: - providers: - keycloakOrg: - default: - baseUrl: '${KEYCLOAK_BASE_URL}' - loginRealm: '${KEYCLOAK_LOGIN_REALM}' - realm: '${KEYCLOAK_REALM}' - clientId: '${KEYCLOAK_CLIENT_ID}' - clientSecret: '${KEYCLOAK_CLIENT_SECRET}' diff --git a/plugins/keycloak-backend/catalog-info.yaml b/plugins/keycloak-backend/catalog-info.yaml deleted file mode 100644 index c14cf116fe..0000000000 --- a/plugins/keycloak-backend/catalog-info.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: janus-idp-keycloak - title: Keycloak plugin - description: Keycloak backend plugin for Backstage - annotations: - backstage.io/source-location: url:https://github.com/janus-idp/backstage-plugins/tree/main/plugins/keycloak-backend - backstage.io/view-url: https://github.com/janus-idp/backstage-plugins/blob/main/plugins/keycloak-backend/catalog-info.yaml - backstage.io/edit-url: https://github.com/janus-idp/backstage-plugins/edit/main/plugins/keycloak-backend/catalog-info.yaml - github.com/project-slug: janus-idp/backstage-plugins - github.com/team-slug: janus-idp/maintainers-plugins - sonarqube.org/project-key: janus-idp_backstage-plugins - links: - - url: https://github.com/janus-idp/backstage-plugins/tree/main/plugins/keycloak-backend - title: GitHub Source - icon: source - type: source -spec: - type: backstage-plugin - lifecycle: production - owner: rhdh-core-team - system: rhdh - subcomponentOf: janus-idp-backstage-plugins ---- -# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: janus-idp-keycloak-backend - title: '@janus-idp/backstage-plugin-keycloak-backend' - description: Keycloak backend plugin for Backstage - annotations: - backstage.io/source-location: url:https://github.com/janus-idp/backstage-plugins/tree/main/plugins/keycloak-backend - backstage.io/view-url: https://github.com/janus-idp/backstage-plugins/blob/main/plugins/keycloak-backend/catalog-info.yaml - backstage.io/edit-url: https://github.com/janus-idp/backstage-plugins/edit/main/plugins/keycloak-backend/catalog-info.yaml - github.com/project-slug: janus-idp/backstage-plugins - github.com/team-slug: janus-idp/maintainers-plugins - sonarqube.org/project-key: janus-idp_backstage-plugins - links: - - url: https://github.com/janus-idp/backstage-plugins/tree/main/plugins/keycloak-backend - title: GitHub Source - icon: source - type: source -spec: - type: backstage-backend-plugin - lifecycle: production - owner: rhdh-core-team - system: rhdh - subcomponentOf: janus-idp-keycloak diff --git a/plugins/keycloak-backend/config.d.ts b/plugins/keycloak-backend/config.d.ts deleted file mode 100644 index f87df74525..0000000000 --- a/plugins/keycloak-backend/config.d.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { SchedulerServiceTaskScheduleDefinitionConfig } from '@backstage/backend-plugin-api'; - -export interface Config { - catalog?: { - providers?: { - keycloakOrg?: { - [key: string]: { - /** - * KeycloakOrgConfig - */ - /** - * Location of the Keycloak instance - */ - baseUrl: string; - /** - * Keycloak realm name. This realm is scraped and entities are - */ - realm?: string; - /** - * Keycloak realm name. This realm is used for authentication using the credentials below. - */ - loginRealm?: string; - /** - * The number of users to query at a time. - * @defaultValue 100 - * @remarks - * This is a performance optimization to avoid querying too many users at once. - * @see https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource - */ - userQuerySize?: number; - /** - * The number of groups to query at a time. - * @defaultValue 100 - * @remarks - * This is a performance optimization to avoid querying too many groups at once. - * @see https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_groups_resource - */ - groupQuerySize?: number; - schedule?: SchedulerServiceTaskScheduleDefinitionConfig; - } & ( - | { - /** - * KeycloakClientCredentials - */ - /** - * Keycloak credentials. Use together with "password". - */ - username: string; - /** - * Keycloak credentials. Use together with "username". - * @visibility secret - */ - password: string; - } - | { - /** - * KeycloakClientCredentials - */ - /** - * Keycloak credentials. Use together with "clientSecret". - */ - clientId: string; - /** - * Keycloak credentials. Use together with "clientId". - * @visibility secret - */ - clientSecret: string; - } - ); - }; - }; - }; -} diff --git a/plugins/keycloak-backend/dev/index.ts b/plugins/keycloak-backend/dev/index.ts deleted file mode 100644 index 78916e9e51..0000000000 --- a/plugins/keycloak-backend/dev/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createBackend } from '@backstage/backend-defaults'; - -import { catalogModuleKeycloakEntityProvider } from '../src/module/catalogModuleKeycloakEntityProvider'; - -const backend = createBackend(); - -// api endpoints from here: https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/service/createRouter.ts -backend.add(import('@backstage/plugin-catalog-backend/alpha')); -backend.add(catalogModuleKeycloakEntityProvider); - -backend.start(); diff --git a/plugins/keycloak-backend/images/group1.jpg b/plugins/keycloak-backend/images/group1.jpg deleted file mode 100644 index 4b9a277ac4d1321e2769af690fcacc1d4593b9a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90280 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 O{*Q7+z@_>&^8WzVjm}5_ diff --git a/plugins/keycloak-backend/images/user-list.jpg b/plugins/keycloak-backend/images/user-list.jpg deleted file mode 100644 index 344fd51353bab77d41b9daa032f33ae29462fbe4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84142 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 edB0Uxa|O2x{EFKF#jGW@KWcsd04G0AV1>`pP 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⁣uc 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 P@4)Yu9w6%K`}qF?2XHw1 diff --git a/plugins/keycloak-backend/images/users.jpg b/plugins/keycloak-backend/images/users.jpg deleted file mode 100644 index 393f14bdd5f2a231c8cfb2202b997547fb21d8b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116726 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 - id: 'keycloak.transformer', - }); - -/** - * The interface for {@link keycloakTransformerExtensionPoint}. - * - * @public - */ -export type KeycloakTransformerExtensionPoint = { - setUserTransformer(userTransformer: UserTransformer): void; - setGroupTransformer(groupTransformer: GroupTransformer): void; -}; diff --git a/plugins/keycloak-backend/src/index.ts b/plugins/keycloak-backend/src/index.ts deleted file mode 100644 index 6a7d694b14..0000000000 --- a/plugins/keycloak-backend/src/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2022 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 * from './providers'; -export type { UserTransformer, GroupTransformer } from './lib'; -export * from './lib/transformers'; -export * from './extensions'; -export * from './lib/types'; -export { catalogModuleKeycloakEntityProvider as default } from './module'; diff --git a/plugins/keycloak-backend/src/lib/config.test.ts b/plugins/keycloak-backend/src/lib/config.test.ts deleted file mode 100644 index 08cf9577bb..0000000000 --- a/plugins/keycloak-backend/src/lib/config.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { mockServices } from '@backstage/backend-test-utils'; - -import deepmerge from 'deepmerge'; - -import { CONFIG } from '../../__fixtures__/helpers'; -import { readProviderConfigs } from './config'; - -describe('readProviderConfigs', () => { - it('should return an empty array if no providers are configured', () => { - const config = mockServices.rootConfig({ data: {} }); - - const result = readProviderConfigs(config); - - expect(result).toEqual([]); - }); - - it('should return an array of provider configs', () => { - const config = mockServices.rootConfig({ data: CONFIG }); - - const result = readProviderConfigs(config); - - expect(result).toEqual([ - { - id: 'default', - baseUrl: 'http://localhost:8080', - loginRealm: 'master', - realm: 'master', - username: undefined, - password: undefined, - clientId: undefined, - clientSecret: undefined, - schedule: undefined, - userQuerySize: undefined, - groupQuerySize: undefined, - }, - ]); - }); - - it('should return an array of provider configs with optional values', () => { - const config = mockServices.rootConfig({ - data: deepmerge(CONFIG, { - catalog: { - providers: { - keycloakOrg: { - default: { - realm: 'myrealm', - loginRealm: 'myloginrealm', - username: 'myusername', - password: 'mypassword', - clientId: 'myclientid', - clientSecret: 'myclientsecret', - userQuerySize: 100, - groupQuerySize: 200, - schedule: { - frequency: { hours: 1 }, - timeout: { minutes: 50 }, - initialDelay: { seconds: 15 }, - }, - }, - }, - }, - }, - }), - }); - - const result = readProviderConfigs(config); - - expect(result).toEqual([ - { - id: 'default', - baseUrl: 'http://localhost:8080', - loginRealm: 'myloginrealm', - realm: 'myrealm', - username: 'myusername', - password: 'mypassword', - clientId: 'myclientid', - clientSecret: 'myclientsecret', - userQuerySize: 100, - groupQuerySize: 200, - schedule: { - scope: undefined, - frequency: { hours: 1 }, - timeout: { minutes: 50 }, - initialDelay: { seconds: 15 }, - }, - }, - ]); - }); - - it('should throw an error if clientId is provided without clientSecret', () => { - const config = mockServices.rootConfig({ - data: deepmerge(CONFIG, { - catalog: { - providers: { - keycloakOrg: { - default: { - clientId: 'myclientid', - }, - }, - }, - }, - }), - }); - - expect(() => readProviderConfigs(config)).toThrow( - `clientSecret must be provided when clientId is defined.`, - ); - }); - - it('should throw an error if clientSecret is provided without clientId', () => { - const config = mockServices.rootConfig({ - data: deepmerge(CONFIG, { - catalog: { - providers: { - keycloakOrg: { - default: { - clientSecret: 'myclientsecret', - }, - }, - }, - }, - }), - }); - - expect(() => readProviderConfigs(config)).toThrow( - `clientId must be provided when clientSecret is defined.`, - ); - }); - - it('should throw an error if username is provided without password', () => { - const config = mockServices.rootConfig({ - data: deepmerge(CONFIG, { - catalog: { - providers: { - keycloakOrg: { - default: { - username: 'myusername', - }, - }, - }, - }, - }), - }); - - expect(() => readProviderConfigs(config)).toThrow( - `password must be provided when username is defined.`, - ); - }); - - it('should throw an error if password is provided without username', () => { - const config = mockServices.rootConfig({ - data: deepmerge(CONFIG, { - catalog: { - providers: { - keycloakOrg: { - default: { - password: 'mypassword', - }, - }, - }, - }, - }), - }); - - expect(() => readProviderConfigs(config)).toThrow( - `username must be provided when password is defined.`, - ); - }); -}); diff --git a/plugins/keycloak-backend/src/lib/config.ts b/plugins/keycloak-backend/src/lib/config.ts deleted file mode 100644 index fadef7abd6..0000000000 --- a/plugins/keycloak-backend/src/lib/config.ts +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2022 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 { readSchedulerServiceTaskScheduleDefinitionFromConfig } from '@backstage/backend-plugin-api'; -import type { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugin-api'; -import type { Config } from '@backstage/config'; -import { InputError } from '@backstage/errors'; - -/** - * The configuration parameters for a single Keycloak provider. - * - * @public - */ -export type KeycloakProviderConfig = { - /** - * Identifier of the provider which will be used i.e. at the location key for ingested entities. - */ - id: string; - - /** - * The Keycloak base URL - */ - baseUrl: string; - - /** - * The username to use for authenticating requests - * If specified, password must also be specified - */ - username?: string; - - /** - * The password to use for authenticating requests - * If specified, username must also be specified - */ - password?: string; - - /** - * The clientId to use for authenticating requests - * If specified, clientSecret must also be specified - */ - clientId?: string; - - /** - * The clientSecret to use for authenticating requests - * If specified, clientId must also be specified - */ - clientSecret?: string; - - /** - * name of the Keycloak realm - */ - realm: string; - - /** - * name of the Keycloak login realm - */ - loginRealm?: string; - - /** - * Schedule configuration for refresh tasks. - */ - schedule?: SchedulerServiceTaskScheduleDefinition; - - /** - * The number of users to query at a time. - * @defaultValue 100 - * @remarks - * This is a performance optimization to avoid querying too many users at once. - * @see https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource - */ - userQuerySize?: number; - - /** - * The number of groups to query at a time. - * @defaultValue 100 - * @remarks - * This is a performance optimization to avoid querying too many groups at once. - * @see https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_groups_resource - */ - groupQuerySize?: number; -}; - -const readProviderConfig = ( - id: string, - providerConfigInstance: Config, -): KeycloakProviderConfig => { - const baseUrl = providerConfigInstance.getString('baseUrl'); - const realm = providerConfigInstance.getOptionalString('realm') ?? 'master'; - const loginRealm = - providerConfigInstance.getOptionalString('loginRealm') ?? 'master'; - const username = providerConfigInstance.getOptionalString('username'); - const password = providerConfigInstance.getOptionalString('password'); - const clientId = providerConfigInstance.getOptionalString('clientId'); - const clientSecret = providerConfigInstance.getOptionalString('clientSecret'); - const userQuerySize = - providerConfigInstance.getOptionalNumber('userQuerySize'); - const groupQuerySize = - providerConfigInstance.getOptionalNumber('groupQuerySize'); - - if (clientId && !clientSecret) { - throw new InputError( - `clientSecret must be provided when clientId is defined.`, - ); - } - - if (clientSecret && !clientId) { - throw new InputError( - `clientId must be provided when clientSecret is defined.`, - ); - } - - if (username && !password) { - throw new InputError(`password must be provided when username is defined.`); - } - - if (password && !username) { - throw new InputError(`username must be provided when password is defined.`); - } - - const schedule = providerConfigInstance.has('schedule') - ? readSchedulerServiceTaskScheduleDefinitionFromConfig( - providerConfigInstance.getConfig('schedule'), - ) - : undefined; - - return { - id, - baseUrl, - loginRealm, - realm, - username, - password, - clientId, - clientSecret, - schedule, - userQuerySize, - groupQuerySize, - }; -}; - -export const readProviderConfigs = ( - config: Config, -): KeycloakProviderConfig[] => { - const providersConfig = config.getOptionalConfig( - 'catalog.providers.keycloakOrg', - ); - if (!providersConfig) { - return []; - } - return providersConfig.keys().map(id => { - const providerConfigInstance = providersConfig.getConfig(id); - return readProviderConfig(id, providerConfigInstance); - }); -}; diff --git a/plugins/keycloak-backend/src/lib/constants.ts b/plugins/keycloak-backend/src/lib/constants.ts deleted file mode 100644 index 46a740ef21..0000000000 --- a/plugins/keycloak-backend/src/lib/constants.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2022 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 const KEYCLOAK_HOST_ANNOTATION = 'keycloak.org/host'; -export const KEYCLOAK_ID_ANNOTATION = 'keycloak.org/id'; -export const KEYCLOAK_REALM_ANNOTATION = 'keycloak.org/realm'; -export const KEYCLOAK_ENTITY_QUERY_SIZE = 100; diff --git a/plugins/keycloak-backend/src/lib/index.ts b/plugins/keycloak-backend/src/lib/index.ts deleted file mode 100644 index 82101014ab..0000000000 --- a/plugins/keycloak-backend/src/lib/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2022 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 type { GroupTransformer, UserTransformer } from './types'; -export type { KeycloakProviderConfig } from './config'; -export { - KEYCLOAK_HOST_ANNOTATION, - KEYCLOAK_ID_ANNOTATION, - KEYCLOAK_REALM_ANNOTATION, -} from './constants'; diff --git a/plugins/keycloak-backend/src/lib/read.test.ts b/plugins/keycloak-backend/src/lib/read.test.ts deleted file mode 100644 index f422208c02..0000000000 --- a/plugins/keycloak-backend/src/lib/read.test.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { mockServices } from '@backstage/backend-test-utils'; - -import type KeycloakAdminClient from '@keycloak/keycloak-admin-client'; - -import { - kGroups23orHigher, - kGroupsLowerThan23, - topLevelGroups23orHigher, - topLevelGroupsLowerThan23, - users as usersFixture, -} from '../../__fixtures__/data'; -import { - KeycloakAdminClientMockServerv18, - KeycloakAdminClientMockServerv24, -} from '../../__fixtures__/helpers'; -import { KeycloakProviderConfig } from './config'; -import { - getEntities, - parseGroup, - parseUser, - processGroupsRecursively, - readKeycloakRealm, - traverseGroups, -} from './read'; -import type { GroupTransformer, UserTransformer } from './types'; - -const config: KeycloakProviderConfig = { - realm: 'myrealm', - id: 'mock_id', - baseUrl: 'http://mock-url', -}; - -const logger = mockServices.logger.mock(); - -describe('readKeycloakRealm', () => { - it('should return the correct number of users and groups (Version 23 or Higher)', async () => { - const client = - new KeycloakAdminClientMockServerv24() as unknown as KeycloakAdminClient; - const { users, groups } = await readKeycloakRealm(client, config, logger); - expect(users).toHaveLength(3); - expect(groups).toHaveLength(3); - }); - - it('should return the correct number of users and groups (Version Less than 23)', async () => { - const client = - new KeycloakAdminClientMockServerv18() as unknown as KeycloakAdminClient; - const { users, groups } = await readKeycloakRealm(client, config, logger); - expect(users).toHaveLength(3); - expect(groups).toHaveLength(3); - }); - - it(`should not contain undefined members when a group member is not found in the fetched user list`, async () => { - const client = - new KeycloakAdminClientMockServerv24() as unknown as KeycloakAdminClient; - client.users.find = jest - .fn() - .mockResolvedValue([usersFixture[1], usersFixture[2]]); - client.users.count = jest.fn().mockResolvedValue(2); - - const { groups } = await readKeycloakRealm(client, config, logger); - - for (const group of groups) { - console.log(group.spec.members); - expect(group.spec.members).not.toContain(undefined); - } - }); - - it('should propagate transformer changes to entities (version 23 or Higher)', async () => { - const groupTransformer: GroupTransformer = async (entity, _g, _r) => { - entity.metadata.name = `${entity.metadata.name}_foo`; - return entity; - }; - const userTransformer: UserTransformer = async (e, _u, _r, _g) => { - e.metadata.name = `${e.metadata.name}_bar`; - return e; - }; - - const client = - new KeycloakAdminClientMockServerv24() as unknown as KeycloakAdminClient; - const { users, groups } = await readKeycloakRealm(client, config, logger, { - userTransformer, - groupTransformer, - }); - expect(groups[0].metadata.name).toBe('biggroup_foo'); - expect(groups[0].spec.children).toEqual(['subgroup_foo']); - expect(groups[0].spec.members).toEqual(['jamesdoe_bar']); - expect(groups[1].spec.parent).toBe('biggroup_foo'); - expect(users[0].metadata.name).toBe('jamesdoe_bar'); - expect(users[0].spec.memberOf).toEqual(['biggroup_foo']); - }); - - it('should propagate transformer changes to entities (version less than 23)', async () => { - const groupTransformer: GroupTransformer = async (entity, _g, _r) => { - entity.metadata.name = `${entity.metadata.name}_foo`; - return entity; - }; - const userTransformer: UserTransformer = async (e, _u, _r, _g) => { - e.metadata.name = `${e.metadata.name}_bar`; - return e; - }; - - const client = - new KeycloakAdminClientMockServerv18() as unknown as KeycloakAdminClient; - const { users, groups } = await readKeycloakRealm(client, config, logger, { - userTransformer, - groupTransformer, - }); - expect(groups[0].metadata.name).toBe('biggroup_foo'); - expect(groups[0].spec.children).toEqual(['subgroup_foo']); - expect(groups[0].spec.members).toEqual(['jamesdoe_bar']); - expect(groups[1].spec.parent).toBe('biggroup_foo'); - expect(users[0].metadata.name).toBe('jamesdoe_bar'); - expect(users[0].spec.memberOf).toEqual(['biggroup_foo']); - }); -}); - -describe('parseGroup', () => { - it('should parse a group (version greater than or equal to 23)', async () => { - const entity = await parseGroup(kGroups23orHigher[0], 'test'); - expect(entity).toEqual({ - apiVersion: 'backstage.io/v1beta1', - kind: 'Group', - metadata: { - annotations: { - 'keycloak.org/id': '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - 'keycloak.org/realm': 'test', - }, - name: 'biggroup', - }, - spec: { - children: ['subgroup'], - members: ['jamesdoe'], - parent: undefined, - profile: { - displayName: 'biggroup', - }, - type: 'group', - }, - }); - }); - - it('should parse a group (version less than 23)', async () => { - const entity = await parseGroup(kGroupsLowerThan23[0], 'test'); - expect(entity).toEqual({ - apiVersion: 'backstage.io/v1beta1', - kind: 'Group', - metadata: { - annotations: { - 'keycloak.org/id': '9cf51b5d-e066-4ed8-940c-dc6da77f81a5', - 'keycloak.org/realm': 'test', - }, - name: 'biggroup', - }, - spec: { - children: ['subgroup'], - members: ['jamesdoe'], - parent: undefined, - profile: { - displayName: 'biggroup', - }, - type: 'group', - }, - }); - }); - - it('should parse a group with a transformer (version greater than or equal to 23)', async () => { - const transformer: GroupTransformer = async (e, _g, r) => { - e.metadata.name = `${e.metadata.name}_${r}`; - return e; - }; - const entity = await parseGroup(kGroups23orHigher[0], 'test', transformer); - - expect(entity).toBeDefined(); - expect(entity?.metadata.name).toEqual('biggroup_test'); - }); - - it('should parse a group with a transformer (version less than 23)', async () => { - const transformer: GroupTransformer = async (e, _g, r) => { - e.metadata.name = `${e.metadata.name}_${r}`; - return e; - }; - const entity = await parseGroup(kGroupsLowerThan23[0], 'test', transformer); - - expect(entity).toBeDefined(); - expect(entity?.metadata.name).toEqual('biggroup_test'); - }); -}); - -describe('parseUser', () => { - it('should parse an user', async () => { - const entity = await parseUser(usersFixture[0], 'test', []); - - expect(entity).toEqual({ - apiVersion: 'backstage.io/v1beta1', - kind: 'User', - metadata: { - annotations: { - 'keycloak.org/id': '59efec15-a00b-4700-8833-5f4cdecc1132', - 'keycloak.org/realm': 'test', - }, - name: 'jamesdoe', - }, - spec: { - memberOf: [], - profile: { - email: 'jamesdoe@gmail.com', - }, - }, - }); - }); - - it('should parse an user with displayName', async () => { - const entity = await parseUser(usersFixture[2], 'test', []); - - expect(entity?.spec.profile?.displayName).toEqual('John Doe'); - }); - - it('should parse an user without displayName', async () => { - const entity = await parseUser(usersFixture[0], 'test', []); - - expect(entity?.spec.profile?.displayName).toBeUndefined(); - }); - - it('should parse an user with transformer', async () => { - const transformer: UserTransformer = async (e, _u, r, _g) => { - e.metadata.name = `${e.metadata.name}_${r}`; - return e; - }; - const entity = await parseUser(usersFixture[0], 'test', [], transformer); - - expect(entity).toBeDefined(); - expect(entity?.metadata.name).toEqual('jamesdoe_test'); - }); -}); - -describe('getEntitiesUser', () => { - it('should fetch all users (version 23 or Higher)', async () => { - const client = - new KeycloakAdminClientMockServerv24() as unknown as KeycloakAdminClient; - - const users = await getEntities( - client.users, - { - id: '', - baseUrl: '', - realm: '', - }, - logger, - ); - - expect(users).toHaveLength(3); - }); - - it('should fetch all users (version less than 23)', async () => { - const client = - new KeycloakAdminClientMockServerv18() as unknown as KeycloakAdminClient; - - const users = await getEntities( - client.users, - { - id: '', - baseUrl: '', - realm: '', - }, - logger, - ); - - expect(users).toHaveLength(3); - }); - - it('should fetch all users with pagination (version greater than or equal to 23)', async () => { - const client = - new KeycloakAdminClientMockServerv24() as unknown as KeycloakAdminClient; - - await getEntities( - client.users, - { - id: '', - baseUrl: '', - realm: '', - }, - logger, - 1, - ); - - expect(client.users.find).toHaveBeenCalledTimes(3); - }); - - it('should fetch all users with pagination (version less than 23)', async () => { - const client = - new KeycloakAdminClientMockServerv18() as unknown as KeycloakAdminClient; - - await getEntities( - client.users, - { - id: '', - baseUrl: '', - realm: '', - }, - logger, - 1, - ); - - expect(client.users.find).toHaveBeenCalledTimes(3); - }); -}); - -describe('fetch subgroups', () => { - it('processGroupsRecursively (Version greater than or equal to 23)', async () => { - const client = - new KeycloakAdminClientMockServerv24() as unknown as KeycloakAdminClient; - const groups = await processGroupsRecursively( - topLevelGroups23orHigher, - client.groups, - config.realm, - ); - - expect(groups).toHaveLength(3); - }); - - it('traverseGroups (Version less than 23)', async () => { - const groups = [...traverseGroups(topLevelGroupsLowerThan23[0])]; - - expect(groups).toHaveLength(2); - }); -}); diff --git a/plugins/keycloak-backend/src/lib/read.ts b/plugins/keycloak-backend/src/lib/read.ts deleted file mode 100644 index 89649f8035..0000000000 --- a/plugins/keycloak-backend/src/lib/read.ts +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 2022 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 type { LoggerService } from '@backstage/backend-plugin-api'; -import type { GroupEntity, UserEntity } from '@backstage/catalog-model'; - -import type KeycloakAdminClient from '@keycloak/keycloak-admin-client'; -import type GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; -import type UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; -import type { Groups } from '@keycloak/keycloak-admin-client/lib/resources/groups'; -import type { Users } from '@keycloak/keycloak-admin-client/lib/resources/users'; - -import { KeycloakProviderConfig } from './config'; -import { - KEYCLOAK_ENTITY_QUERY_SIZE, - KEYCLOAK_ID_ANNOTATION, - KEYCLOAK_REALM_ANNOTATION, -} from './constants'; -import { noopGroupTransformer, noopUserTransformer } from './transformers'; -import { - GroupRepresentationWithParent, - GroupRepresentationWithParentAndEntity, - GroupTransformer, - UserRepresentationWithEntity, - UserTransformer, -} from './types'; - -export const parseGroup = async ( - keycloakGroup: GroupRepresentationWithParent, - realm: string, - groupTransformer?: GroupTransformer, -): Promise => { - const transformer = groupTransformer ?? noopGroupTransformer; - const entity: GroupEntity = { - apiVersion: 'backstage.io/v1beta1', - kind: 'Group', - metadata: { - name: keycloakGroup.name!, - annotations: { - [KEYCLOAK_ID_ANNOTATION]: keycloakGroup.id!, - [KEYCLOAK_REALM_ANNOTATION]: realm, - }, - }, - spec: { - type: 'group', - profile: { - displayName: keycloakGroup.name!, - }, - // children, parent and members are updated again after all group and user transformers applied. - children: keycloakGroup.subGroups?.map(g => g.name!) ?? [], - parent: keycloakGroup.parent, - members: keycloakGroup.members, - }, - }; - - return await transformer(entity, keycloakGroup, realm); -}; - -export const parseUser = async ( - user: UserRepresentation, - realm: string, - keycloakGroups: GroupRepresentationWithParentAndEntity[], - - userTransformer?: UserTransformer, -): Promise => { - const transformer = userTransformer ?? noopUserTransformer; - const entity: UserEntity = { - apiVersion: 'backstage.io/v1beta1', - kind: 'User', - metadata: { - name: user.username!, - annotations: { - [KEYCLOAK_ID_ANNOTATION]: user.id!, - [KEYCLOAK_REALM_ANNOTATION]: realm, - }, - }, - spec: { - profile: { - email: user.email, - ...(user.firstName || user.lastName - ? { - displayName: [user.firstName, user.lastName] - .filter(Boolean) - .join(' '), - } - : {}), - }, - memberOf: keycloakGroups - .filter(g => g.members?.includes(user.username!)) - .map(g => g.entity.metadata.name), - }, - }; - - return await transformer(entity, user, realm, keycloakGroups); -}; - -export async function getEntities( - entities: T, - config: KeycloakProviderConfig, - logger: LoggerService, - entityQuerySize: number = KEYCLOAK_ENTITY_QUERY_SIZE, -): Promise>> { - const rawEntityCount = await entities.count({ realm: config.realm }); - const entityCount = - typeof rawEntityCount === 'number' ? rawEntityCount : rawEntityCount.count; - - const pageCount = Math.ceil(entityCount / entityQuerySize); - - // The next line acts like range in python - const entityPromises = Array.from( - { length: pageCount }, - (_, i) => - entities - .find({ - realm: config.realm, - max: entityQuerySize, - first: i * entityQuerySize, - }) - .catch(err => - logger.warn('Failed to retieve Keycloak entities.', err), - ) as ReturnType, - ); - - const entityResults = (await Promise.all(entityPromises)).flat() as Awaited< - ReturnType - >; - - return entityResults; -} - -async function getAllGroupMembers( - groups: T, - groupId: string, - config: KeycloakProviderConfig, - options?: { userQuerySize?: number }, -): Promise { - const querySize = options?.userQuerySize || 100; - - let allMembers: string[] = []; - let page = 0; - let totalMembers = 0; - - do { - const members = await groups.listMembers({ - id: groupId, - max: querySize, - realm: config.realm, - first: page * querySize, - }); - - if (members.length > 0) { - allMembers = allMembers.concat(members.map(m => m.username!)); - totalMembers = members.length; // Get the number of members retrieved - } else { - totalMembers = 0; // No members retrieved - } - - page++; - } while (totalMembers > 0); - - return allMembers; -} - -export async function processGroupsRecursively( - topLevelGroups: GroupRepresentationWithParent[], - entities: Groups, - realm: string, -) { - const allGroups: GroupRepresentationWithParent[] = []; - for (const group of topLevelGroups) { - allGroups.push(group); - - if (group.subGroupCount! > 0) { - const subgroups = await entities.listSubGroups({ - parentId: group.id!, - first: 0, - max: group.subGroupCount, - briefRepresentation: true, - realm, - }); - const subGroupResults = await processGroupsRecursively( - subgroups, - entities, - realm, - ); - allGroups.push(...subGroupResults); - } - } - - return allGroups; -} - -export function* traverseGroups( - group: GroupRepresentation, -): IterableIterator { - yield group; - for (const g of group.subGroups ?? []) { - (g as GroupRepresentationWithParent).parent = group.name!; - yield* traverseGroups(g); - } -} - -export const readKeycloakRealm = async ( - client: KeycloakAdminClient, - config: KeycloakProviderConfig, - logger: LoggerService, - options?: { - userQuerySize?: number; - groupQuerySize?: number; - userTransformer?: UserTransformer; - groupTransformer?: GroupTransformer; - }, -): Promise<{ - users: UserEntity[]; - groups: GroupEntity[]; -}> => { - const kUsers = await getEntities( - client.users, - config, - logger, - options?.userQuerySize, - ); - - const topLevelKGroups = (await getEntities( - client.groups, - config, - logger, - options?.groupQuerySize, - )) as GroupRepresentationWithParent[]; - - let serverVersion: number; - - try { - const serverInfo = await client.serverInfo.find(); - serverVersion = parseInt( - serverInfo.systemInfo?.version?.slice(0, 2) || '', - 10, - ); - } catch (error) { - throw new Error(`Failed to retrieve Keycloak server information: ${error}`); - } - - const isVersion23orHigher = serverVersion >= 23; - - let rawKGroups: GroupRepresentationWithParent[] = []; - - if (isVersion23orHigher) { - rawKGroups = await processGroupsRecursively( - topLevelKGroups, - client.groups as Groups, - config.realm, - ); - } else { - rawKGroups = topLevelKGroups.reduce( - (acc, g) => acc.concat(...traverseGroups(g)), - [] as GroupRepresentationWithParent[], - ); - } - const kGroups = await Promise.all( - rawKGroups.map(async g => { - g.members = await getAllGroupMembers( - client.groups as Groups, - g.id!, - config, - options, - ); - - if (isVersion23orHigher) { - if (g.subGroupCount! > 0) { - g.subGroups = await client.groups.listSubGroups({ - parentId: g.id!, - first: 0, - max: g.subGroupCount, - briefRepresentation: false, - realm: config.realm, - }); - } - if (g.parentId) { - const groupParent = await client.groups.findOne({ - id: g.parentId, - realm: config.realm, - }); - g.parent = groupParent?.name; - } - } - - return g; - }), - ); - - const parsedGroups = await kGroups.reduce( - async (promise, g) => { - const partial = await promise; - const entity = await parseGroup( - g, - config.realm, - options?.groupTransformer, - ); - if (entity) { - const group = { - ...g, - entity, - } as GroupRepresentationWithParentAndEntity; - partial.push(group); - } - return partial; - }, - Promise.resolve([] as GroupRepresentationWithParentAndEntity[]), - ); - - const parsedUsers = await kUsers.reduce( - async (promise, u) => { - const partial = await promise; - const entity = await parseUser( - u, - config.realm, - parsedGroups, - options?.userTransformer, - ); - if (entity) { - const user = { ...u, entity } as UserRepresentationWithEntity; - partial.push(user); - } - return partial; - }, - Promise.resolve([] as UserRepresentationWithEntity[]), - ); - - const groups = parsedGroups.map(g => { - const entity = g.entity; - entity.spec.members = - g.entity.spec.members?.flatMap(m => { - const name = parsedUsers.find(p => p.username === m)?.entity.metadata - .name; - return name ? [name] : []; - }) ?? []; - entity.spec.children = - g.entity.spec.children?.flatMap(c => { - const child = parsedGroups.find(p => p.name === c)?.entity.metadata - .name; - return child ? [child] : []; - }) ?? []; - entity.spec.parent = parsedGroups.find( - p => p.name === entity.spec.parent, - )?.entity.metadata.name; - return entity; - }); - - return { users: parsedUsers.map(u => u.entity), groups }; -}; diff --git a/plugins/keycloak-backend/src/lib/transformers.ts b/plugins/keycloak-backend/src/lib/transformers.ts deleted file mode 100644 index 6ad1bcdff1..0000000000 --- a/plugins/keycloak-backend/src/lib/transformers.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { GroupTransformer, UserTransformer } from './types'; - -export const noopGroupTransformer: GroupTransformer = async ( - entity, - _user, - _realm, -) => entity; - -export const noopUserTransformer: UserTransformer = async ( - entity, - _user, - _realm, - _groups, -) => entity; - -/** - * User transformer that sanitizes .metadata.name from email address to a valid name - */ -export const sanitizeEmailTransformer: UserTransformer = async ( - entity, - _user, - _realm, - _groups, -) => { - entity.metadata.name = entity.metadata.name.replace(/[^a-zA-Z0-9]/g, '-'); - return entity; -}; diff --git a/plugins/keycloak-backend/src/lib/types.ts b/plugins/keycloak-backend/src/lib/types.ts deleted file mode 100644 index c2508fab56..0000000000 --- a/plugins/keycloak-backend/src/lib/types.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2022 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 type { GroupEntity, UserEntity } from '@backstage/catalog-model'; - -import type GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; -import type UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; - -export interface GroupRepresentationWithParent extends GroupRepresentation { - parentId?: string; - parent?: string; - members?: string[]; -} - -export interface GroupRepresentationWithParentAndEntity - extends GroupRepresentationWithParent { - entity: GroupEntity; -} - -export interface UserRepresentationWithEntity extends UserRepresentation { - entity: UserEntity; -} - -/** - * Customize the ingested User entity - * - * @public - * - * @param {UserEntity} entity The output of the default parser - * @param {UserRepresentation} user Keycloak user representation - * @param {string} realm Realm name - * @param {GroupRepresentationWithParentAndEntity[]} groups Data about available groups (can be used to create additional relationships) - * - * @returns {Promise} Resolve to a modified `UserEntity` object that will be ingested into the catalog or resolve to `undefined` to reject the entity - */ -export type UserTransformer = ( - entity: UserEntity, - user: UserRepresentation, - realm: string, - groups: GroupRepresentationWithParentAndEntity[], -) => Promise; - -/** - * Customize the ingested Group entity - * - * @public - * - * @param {GroupEntity} entity The output of the default parser - * @param {GroupRepresentation} group Keycloak group representation - * @param {string} realm Realm name - * - * @returns {Promise} Resolve to a modified `GroupEntity` object that will be ingested into the catalog or resolve to `undefined` to reject the entity - */ -export type GroupTransformer = ( - entity: GroupEntity, - group: GroupRepresentation, - realm: string, -) => Promise; diff --git a/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts b/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts deleted file mode 100644 index e674d328ed..0000000000 --- a/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 type { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugin-api'; -import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; -import catalogPlugin from '@backstage/plugin-catalog-backend/alpha'; -import type { EntityProvider } from '@backstage/plugin-catalog-node'; -import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; - -import { CONFIG } from '../../__fixtures__/helpers'; -import { catalogModuleKeycloakEntityProvider } from './catalogModuleKeycloakEntityProvider'; - -describe('catalogModuleKeycloakEntityProvider', () => { - let addedProviders: EntityProvider[] | EntityProvider[][] | undefined; - - const extensionPoint = { - addEntityProvider: ( - ...providers: EntityProvider[] | EntityProvider[][] - ) => { - addedProviders = providers; - }, - }; - - it('should return an empty array if no providers are configured', async () => { - await startTestBackend({ - extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - features: [ - catalogModuleKeycloakEntityProvider, - mockServices.rootConfig.factory({ data: {} }), - ], - }); - - // Only the Keycloak provider should be in the array - expect((addedProviders as EntityProvider[][]).length).toEqual(1); - // Keycloak returns an array of entity providers - expect((addedProviders as EntityProvider[][])[0].length).toEqual(0); - }); - - it('should not run without a baseUrl', async () => { - await expect( - startTestBackend({ - features: [ - catalogPlugin, - catalogModuleKeycloakEntityProvider, - mockServices.rootConfig.factory({ - data: { - catalog: { - providers: { - keycloakOrg: { - dev: {}, - }, - }, - }, - }, - }), - ], - }), - ).rejects.toThrow( - "Module 'catalog-backend-module-keycloak' for plugin 'catalog' startup failed; caused by Error: Missing required config value at 'catalog.providers.keycloakOrg.dev.baseUrl' in 'mock-config'", - ); - }); - - it('should return a single provider with the default schedule', async () => { - let usedSchedule: SchedulerServiceTaskScheduleDefinition | undefined; - const runner = jest.fn(); - const scheduler = mockServices.scheduler.mock({ - createScheduledTaskRunner(schedule) { - usedSchedule = schedule; - return { run: runner }; - }, - }); - - await startTestBackend({ - features: [ - catalogPlugin, - catalogModuleKeycloakEntityProvider, - mockServices.rootConfig.factory({ data: CONFIG }), - scheduler.factory, - ], - }); - - expect(usedSchedule?.frequency).toEqual({ minutes: 30 }); - expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); - }); - - it('should return a single provider with a specified schedule', async () => { - let usedSchedule: SchedulerServiceTaskScheduleDefinition | undefined; - const runner = jest.fn(); - const scheduler = mockServices.scheduler.mock({ - createScheduledTaskRunner(schedule) { - usedSchedule = schedule; - return { run: runner }; - }, - }); - - await startTestBackend({ - features: [ - catalogPlugin, - catalogModuleKeycloakEntityProvider, - mockServices.rootConfig.factory({ - data: { - catalog: { - providers: { - keycloakOrg: { - dev: { - baseUrl: 'https://example.com/auth', - schedule: { - frequency: 'P1M', - timeout: 'PT5M', - }, - }, - }, - }, - }, - }, - }), - scheduler.factory, - ], - }); - - expect(usedSchedule?.frequency).toEqual({ months: 1 }); - expect(usedSchedule?.timeout).toEqual({ minutes: 5 }); - }); - - it('should return multiple providers', async () => { - await startTestBackend({ - extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - features: [ - catalogModuleKeycloakEntityProvider, - mockServices.rootConfig.factory({ - data: { - catalog: { - providers: { - keycloakOrg: { - dev: { - baseUrl: 'https://example1.com/auth', - }, - production: { - baseUrl: 'https://example2.com/auth', - }, - }, - }, - }, - }, - }), - ], - }); - - // Only the Keycloak provider should be in the array - expect((addedProviders as EntityProvider[][]).length).toEqual(1); - // Keycloak returns an array of entity providers - expect((addedProviders as EntityProvider[][])[0].length).toEqual(2); - }); - - it('should return provider name', async () => { - await startTestBackend({ - extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - features: [ - catalogModuleKeycloakEntityProvider, - mockServices.rootConfig.factory({ - data: CONFIG, - }), - ], - }); - - // Only the Keycloak provider should be in the array - expect((addedProviders as EntityProvider[][]).length).toEqual(1); - // Keycloak returns an array of entity providers - expect( - (addedProviders as EntityProvider[][])[0][0].getProviderName(), - ).toEqual('KeycloakOrgEntityProvider:default'); - }); -}); diff --git a/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts b/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts deleted file mode 100644 index 25a9359a09..0000000000 --- a/plugins/keycloak-backend/src/module/catalogModuleKeycloakEntityProvider.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 { - coreServices, - createBackendModule, -} from '@backstage/backend-plugin-api'; -import { InputError } from '@backstage/errors'; -import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; - -import { keycloakTransformerExtensionPoint } from '../extensions'; -import type { GroupTransformer, UserTransformer } from '../lib/types'; -import { KeycloakOrgEntityProvider } from '../providers'; - -/** - * Registers the `KeycloakEntityProvider` with the catalog processing extension point. - * - * @alpha - */ -export const catalogModuleKeycloakEntityProvider = createBackendModule({ - pluginId: 'catalog', - moduleId: 'catalog-backend-module-keycloak', - register(env) { - let userTransformer: UserTransformer | undefined; - let groupTransformer: GroupTransformer | undefined; - - env.registerExtensionPoint(keycloakTransformerExtensionPoint, { - setUserTransformer(transformer) { - if (userTransformer) { - throw new InputError('User transformer may only be set once'); - } - userTransformer = transformer; - }, - setGroupTransformer(transformer) { - if (groupTransformer) { - throw new InputError('Group transformer may only be set once'); - } - groupTransformer = transformer; - }, - }); - 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, logger }, - { - scheduler: scheduler, - schedule: scheduler.createScheduledTaskRunner({ - frequency: { minutes: 30 }, - timeout: { minutes: 3 }, - }), - userTransformer: userTransformer, - groupTransformer: groupTransformer, - }, - ), - ); - }, - }); - }, -}); diff --git a/plugins/keycloak-backend/src/module/index.ts b/plugins/keycloak-backend/src/module/index.ts deleted file mode 100644 index 859f5d5799..0000000000 --- a/plugins/keycloak-backend/src/module/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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 } from './catalogModuleKeycloakEntityProvider'; diff --git a/plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.test.ts b/plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.test.ts deleted file mode 100644 index 4150661a61..0000000000 --- a/plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.test.ts +++ /dev/null @@ -1,276 +0,0 @@ -import type { - LoggerService, - SchedulerServiceTaskInvocationDefinition, - SchedulerServiceTaskRunner, - SchedulerServiceTaskScheduleDefinition, -} from '@backstage/backend-plugin-api'; -import { mockServices, ServiceMock } from '@backstage/backend-test-utils'; -import { ErrorLike } from '@backstage/errors'; -import type { EntityProviderConnection } from '@backstage/plugin-catalog-node'; -import type { JsonObject } from '@backstage/types'; - -// @ts-ignore -import inclusion from 'inclusion'; - -import { - assertLogMustNotInclude, - authMock, - CONFIG, - KeycloakAdminClientMockServerv18, - KeycloakAdminClientMockServerv24, - PASSWORD_CONFIG, -} from '../../__fixtures__/helpers'; -import { KeycloakOrgEntityProvider } from './KeycloakOrgEntityProvider'; - -jest.mock('inclusion', () => jest.fn()); - -const connection = { - applyMutation: jest.fn(), - refresh: jest.fn(), -} as unknown as EntityProviderConnection; - -class SchedulerServiceTaskRunnerMock implements SchedulerServiceTaskRunner { - private tasks: SchedulerServiceTaskInvocationDefinition[] = []; - async run(task: SchedulerServiceTaskInvocationDefinition) { - this.tasks.push(task); - } - async runAll() { - const abortSignal = jest.fn() as unknown as AbortSignal; - for await (const task of this.tasks) { - await task.fn(abortSignal); - } - } -} - -const scheduler = mockServices.scheduler.mock({ - createScheduledTaskRunner() { - return new SchedulerServiceTaskRunnerMock(); - }, -}); - -describe.each([ - ['v24', KeycloakAdminClientMockServerv24], - ['v18', KeycloakAdminClientMockServerv18], -])('KeycloakOrgEntityProvider with %s', (_version, mockImplementation) => { - let logger: ServiceMock; - let keycloakLogger: ServiceMock; - let schedule: SchedulerServiceTaskRunnerMock; - - beforeEach(() => { - jest.clearAllMocks(); - authMock.mockReset(); - keycloakLogger = mockServices.logger.mock(); - logger = mockServices.logger.mock({ - child: () => keycloakLogger, - }); - inclusion.mockImplementation(() => ({ default: mockImplementation })); // Return the correct mock based on the version - schedule = scheduler.createScheduledTaskRunner( - '' as unknown as SchedulerServiceTaskScheduleDefinition, - ) as SchedulerServiceTaskRunnerMock; - }); - - afterEach(() => { - for (const log of [logger, keycloakLogger]) { - assertLogMustNotInclude(log, ['myclientsecret', 'mypassword']); // NOSONAR - } - }); - - const createProvider = (configData: JsonObject) => - KeycloakOrgEntityProvider.fromConfig( - { - config: mockServices.rootConfig({ data: configData }), - logger, - }, - { - schedule, - }, - ); - - const runProvider = async (configData: JsonObject) => { - const keycloak = createProvider(configData); - for await (const k of keycloak) { - await k.connect(connection); - await schedule.runAll(); - } - }; - - it('should mock inclusion', async () => { - const KeyCloakAdminClient = await inclusion( - '@keycloak/keycloak-admin-client', - ); - expect(KeyCloakAdminClient).toEqual({ default: mockImplementation }); - }); - - it('should connect', async () => { - const keycloak = createProvider(CONFIG); - const result = await Promise.all( - keycloak.map(async k => await k.connect(connection)), - ); - expect(result).toEqual([undefined]); - }); - - it('should not read without a connection', async () => { - const keycloak = createProvider(CONFIG); - - for await (const k of keycloak) { - await expect(() => k.read()).rejects.toThrow('Not initialized'); - } - expect(authMock).toHaveBeenCalledTimes(0); - }); - - it('should fail with grantType client_credential, but without client secret', async () => { - const invalidConfig = { - catalog: { - providers: { - keycloakOrg: { - default: { - baseUrl: 'http://localhost:8080', - clientId: 'myclientid', - }, - }, - }, - }, - }; - - expect(() => createProvider(invalidConfig)).toThrow( - 'clientSecret must be provided when clientId is defined.', - ); - expect(authMock).toHaveBeenCalledTimes(0); - }); - - it('should read with grantType client_credential', async () => { - const validConfig = { - catalog: { - providers: { - keycloakOrg: { - default: { - baseUrl: 'http://localhost:8080', - clientId: 'myclientid', - clientSecret: 'myclientsecret', - }, - }, - }, - }, - }; - - await runProvider(validConfig); - - expect(authMock).toHaveBeenCalledTimes(1); - expect(authMock).toHaveBeenCalledWith({ - grantType: 'client_credentials', - clientId: 'myclientid', - clientSecret: 'myclientsecret', - }); - expect(connection.applyMutation).toHaveBeenCalledTimes(1); - expect( - (connection.applyMutation as jest.Mock).mock.calls, - ).toMatchSnapshot(); - }); - - it('should fail read with grantType username, but without password', async () => { - const invalidConfig = { - catalog: { - providers: { - keycloakOrg: { - default: { - baseUrl: 'http://localhost:8080', - username: 'myusername', - }, - }, - }, - }, - }; - - expect(() => createProvider(invalidConfig)).toThrow( - 'password must be provided when username is defined.', - ); - expect(authMock).toHaveBeenCalledTimes(0); - }); - - it('should read with grantType password', async () => { - await runProvider(PASSWORD_CONFIG); - - expect(authMock).toHaveBeenCalledTimes(1); - expect(authMock).toHaveBeenCalledWith({ - grantType: 'password', - clientId: 'admin-cli', - username: 'myusername', - password: 'mypassword', // NOSONAR - }); - expect(connection.applyMutation).toHaveBeenCalledTimes(1); - expect( - (connection.applyMutation as jest.Mock).mock.calls, - ).toMatchSnapshot(); - }); - - it('should log a proper error when network connection was refused', async () => { - // Create an error that contains sensitive information. - // The afterEach call ensure that this information aren't logged. - const error = new Error('connect ECONNREFUSED ::1:8080') as ErrorLike; - error.code = 'ECONNREFUSED'; - error.config = { - data: 'username=myusername&password=mypassword', // NOSONAR - }; - error.status = null; - authMock.mockRejectedValue(error); - - await runProvider(PASSWORD_CONFIG); - - expect(authMock).toHaveBeenCalledTimes(1); - expect(authMock).toHaveBeenCalledWith({ - grantType: 'password', - clientId: 'admin-cli', - username: 'myusername', - password: 'mypassword', // NOSONAR - }); - expect(connection.applyMutation).toHaveBeenCalledTimes(0); - - expect(logger.child).toHaveBeenCalledTimes(1); - expect(keycloakLogger.info).toHaveBeenCalledWith( - 'Reading Keycloak users and groups', - ); - expect(keycloakLogger.error).toHaveBeenCalledWith( - 'Error while syncing Keycloak users and groups', - { - name: 'Error', - message: 'connect ECONNREFUSED ::1:8080', - stack: expect.any(String), - }, - ); - }); - - it('should log a proper error when network connection was forbidden', async () => { - // Create an error that contains sensitive information. - // The afterEach call ensure that this information aren't logged. - const error = new Error('Request failed with status code 401') as ErrorLike; - error.config = { - data: 'username=myusername&password=mypassword', // NOSONAR - }; - error.status = 401; - authMock.mockRejectedValue(error); - - await runProvider(PASSWORD_CONFIG); - - expect(authMock).toHaveBeenCalledTimes(1); - expect(authMock).toHaveBeenCalledWith({ - grantType: 'password', - clientId: 'admin-cli', - username: 'myusername', - password: 'mypassword', // NOSONAR - }); - expect(connection.applyMutation).toHaveBeenCalledTimes(0); - - expect(logger.child).toHaveBeenCalledTimes(1); - expect(keycloakLogger.info).toHaveBeenCalledWith( - 'Reading Keycloak users and groups', - ); - expect(keycloakLogger.error).toHaveBeenCalledWith( - 'Error while syncing Keycloak users and groups', - { - name: 'Error', - message: 'Request failed with status code 401', - stack: expect.any(String), - }, - ); - }); -}); diff --git a/plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.ts b/plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.ts deleted file mode 100644 index 37076788ac..0000000000 --- a/plugins/keycloak-backend/src/providers/KeycloakOrgEntityProvider.ts +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright 2022 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 type { - LoggerService, - SchedulerService, - SchedulerServiceTaskRunner, -} from '@backstage/backend-plugin-api'; -import { - ANNOTATION_LOCATION, - ANNOTATION_ORIGIN_LOCATION, - type Entity, -} from '@backstage/catalog-model'; -import type { Config } from '@backstage/config'; -import { InputError, isError, NotFoundError } from '@backstage/errors'; -import type { - EntityProvider, - EntityProviderConnection, -} from '@backstage/plugin-catalog-node'; - -import type { Credentials } from '@keycloak/keycloak-admin-client/lib/utils/auth'; -// @ts-ignore -import inclusion from 'inclusion'; -import { merge } from 'lodash'; -import * as uuid from 'uuid'; - -import { - GroupTransformer, - KEYCLOAK_ID_ANNOTATION, - KeycloakProviderConfig, - UserTransformer, -} from '../lib'; -import { readProviderConfigs } from '../lib/config'; -import { readKeycloakRealm } from '../lib/read'; - -/** - * Options for {@link KeycloakOrgEntityProvider}. - * - * @public - */ -export interface KeycloakOrgEntityProviderOptions { - /** - * A unique, stable identifier for this provider. - * - * @example "production" - */ - id: string; - - /** - * The refresh schedule to use. - * @remarks - * - * You can pass in the result of - * {@link @backstage/backend-plugin-api#SchedulerService.createScheduledTaskRunner} - * to enable automatic scheduling of tasks. - */ - schedule?: SchedulerServiceTaskRunner; - - /** - * Scheduler used to schedule refreshes based on - * the schedule config. - */ - scheduler?: SchedulerService; - - /** - * The logger to use. - */ - logger: LoggerService; - - /** - * The function that transforms a user entry in LDAP to an entity. - */ - userTransformer?: UserTransformer; - - /** - * The function that transforms a group entry in LDAP to an entity. - */ - groupTransformer?: GroupTransformer; -} - -// Makes sure that emitted entities have a proper location -export const withLocations = ( - baseUrl: string, - realm: string, - entity: Entity, -): Entity => { - const kind = entity.kind === 'Group' ? 'groups' : 'users'; - const location = `url:${baseUrl}/admin/realms/${realm}/${kind}/${entity.metadata.annotations?.[KEYCLOAK_ID_ANNOTATION]}`; - return merge( - { - metadata: { - annotations: { - [ANNOTATION_LOCATION]: location, - [ANNOTATION_ORIGIN_LOCATION]: location, - }, - }, - }, - entity, - ) as Entity; -}; - -/** - * Ingests org data (users and groups) from GitHub. - * - * @public - */ -export class KeycloakOrgEntityProvider implements EntityProvider { - private connection?: EntityProviderConnection; - private scheduleFn?: () => Promise; - - static fromConfig( - deps: { - config: Config; - logger: LoggerService; - }, - options: ( - | { schedule: SchedulerServiceTaskRunner } - | { scheduler: SchedulerService } - ) & { - userTransformer?: UserTransformer; - groupTransformer?: GroupTransformer; - }, - ): KeycloakOrgEntityProvider[] { - const { config, logger } = deps; - return readProviderConfigs(config).map(providerConfig => { - let taskRunner: SchedulerServiceTaskRunner | string; - if ('scheduler' in options && providerConfig.schedule) { - // Create a scheduled task runner using the provided scheduler and schedule configuration - taskRunner = options.scheduler.createScheduledTaskRunner( - providerConfig.schedule, - ); - } else if ('schedule' in options) { - // Use the provided schedule directly - taskRunner = options.schedule; - } else { - throw new InputError( - `No schedule provided via config for KeycloakOrgEntityProvider:${providerConfig.id}.`, - ); - } - - const provider = new KeycloakOrgEntityProvider({ - id: providerConfig.id, - provider: providerConfig, - logger: logger, - taskRunner: taskRunner, - userTransformer: options.userTransformer, - groupTransformer: options.groupTransformer, - }); - - return provider; - }); - } - - constructor( - private options: { - id: string; - provider: KeycloakProviderConfig; - logger: LoggerService; - taskRunner: SchedulerServiceTaskRunner; - userTransformer?: UserTransformer; - groupTransformer?: GroupTransformer; - }, - ) { - this.schedule(options.taskRunner); - } - - getProviderName(): string { - return `KeycloakOrgEntityProvider:${this.options.id}`; - } - - async connect(connection: EntityProviderConnection) { - this.connection = connection; - await this.scheduleFn?.(); - } - - /** - * Runs one complete ingestion loop. Call this method regularly at some - * appropriate cadence. - */ - async read(options?: { logger?: LoggerService }) { - if (!this.connection) { - throw new NotFoundError('Not initialized'); - } - - const logger = options?.logger ?? this.options.logger; - const provider = this.options.provider; - - const { markReadComplete } = trackProgress(logger); - const KeyCloakAdminClientModule = await inclusion( - '@keycloak/keycloak-admin-client', - ); - const KeyCloakAdminClient = KeyCloakAdminClientModule.default; - - const kcAdminClient = new KeyCloakAdminClient({ - baseUrl: provider.baseUrl, - realmName: provider.loginRealm, - }); - - let credentials: Credentials; - - if (provider.username && provider.password) { - credentials = { - grantType: 'password', - clientId: provider.clientId ?? 'admin-cli', - username: provider.username, - password: provider.password, - }; - } else if (provider.clientId && provider.clientSecret) { - credentials = { - grantType: 'client_credentials', - clientId: provider.clientId, - clientSecret: provider.clientSecret, - }; - } else { - throw new InputError( - `username and password or clientId and clientSecret must be provided.`, - ); - } - - await kcAdminClient.auth(credentials); - - const { users, groups } = await readKeycloakRealm( - kcAdminClient, - provider, - logger, - { - userQuerySize: provider.userQuerySize, - groupQuerySize: provider.groupQuerySize, - userTransformer: this.options.userTransformer, - groupTransformer: this.options.groupTransformer, - }, - ); - - const { markCommitComplete } = markReadComplete({ users, groups }); - - await this.connection.applyMutation({ - type: 'full', - entities: [...users, ...groups].map(entity => ({ - locationKey: `keycloak-org-provider:${this.options.id}`, - entity: withLocations(provider.baseUrl, provider.realm, entity), - })), - }); - - markCommitComplete(); - } - - schedule(taskRunner: SchedulerServiceTaskRunner) { - this.scheduleFn = async () => { - const id = `${this.getProviderName()}:refresh`; - await taskRunner.run({ - id, - fn: async () => { - const logger = this.options.logger.child({ - class: KeycloakOrgEntityProvider.prototype.constructor.name, - taskId: id, - taskInstanceId: uuid.v4(), - }); - - try { - await this.read({ logger }); - } catch (error) { - if (isError(error)) { - // Ensure that we don't log any sensitive internal data: - logger.error('Error while syncing Keycloak users and groups', { - // Default Error properties: - name: error.name, - cause: error.cause, - message: error.message, - stack: error.stack, - // Additional status code if available: - status: (error.response as { status?: string })?.status, - }); - } - } - }, - }); - }; - } -} - -// Helps wrap the timing and logging behaviors -function trackProgress(logger: LoggerService) { - let timestamp = Date.now(); - let summary: string; - - logger.info('Reading Keycloak users and groups'); - - function markReadComplete(read: { users: unknown[]; groups: unknown[] }) { - summary = `${read.users.length} Keycloak users and ${read.groups.length} Keycloak groups`; - const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1); - timestamp = Date.now(); - logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`); - return { markCommitComplete }; - } - - function markCommitComplete() { - const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1); - logger.info(`Committed ${summary} in ${commitDuration} seconds.`); - } - - return { markReadComplete }; -} diff --git a/plugins/keycloak-backend/src/providers/__snapshots__/KeycloakOrgEntityProvider.test.ts.snap b/plugins/keycloak-backend/src/providers/__snapshots__/KeycloakOrgEntityProvider.test.ts.snap deleted file mode 100644 index 9d7184971e..0000000000 --- a/plugins/keycloak-backend/src/providers/__snapshots__/KeycloakOrgEntityProvider.test.ts.snap +++ /dev/null @@ -1,641 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`KeycloakOrgEntityProvider with v18 should read with grantType client_credential 1`] = ` -[ - [ - { - "entities": [ - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/id": "59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/realm": "master", - }, - "name": "jamesdoe", - }, - "spec": { - "memberOf": [ - "biggroup", - ], - "profile": { - "email": "jamesdoe@gmail.com", - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/id": "c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/realm": "master", - }, - "name": "joedoe", - }, - "spec": { - "memberOf": [], - "profile": { - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/id": "2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/realm": "master", - }, - "name": "johndoe", - }, - "spec": { - "memberOf": [], - "profile": { - "displayName": "John Doe", - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/id": "9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/realm": "master", - }, - "name": "biggroup", - }, - "spec": { - "children": [ - "subgroup", - ], - "members": [ - "jamesdoe", - ], - "parent": undefined, - "profile": { - "displayName": "biggroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/id": "eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/realm": "master", - }, - "name": "subgroup", - }, - "spec": { - "children": [], - "members": [], - "parent": "biggroup", - "profile": { - "displayName": "subgroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/id": "557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/realm": "master", - }, - "name": "emptygroup", - }, - "spec": { - "children": [], - "members": [], - "parent": undefined, - "profile": { - "displayName": "emptygroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - ], - "type": "full", - }, - ], -] -`; - -exports[`KeycloakOrgEntityProvider with v18 should read with grantType password 1`] = ` -[ - [ - { - "entities": [ - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/id": "59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/realm": "master", - }, - "name": "jamesdoe", - }, - "spec": { - "memberOf": [ - "biggroup", - ], - "profile": { - "email": "jamesdoe@gmail.com", - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/id": "c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/realm": "master", - }, - "name": "joedoe", - }, - "spec": { - "memberOf": [], - "profile": { - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/id": "2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/realm": "master", - }, - "name": "johndoe", - }, - "spec": { - "memberOf": [], - "profile": { - "displayName": "John Doe", - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/id": "9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/realm": "master", - }, - "name": "biggroup", - }, - "spec": { - "children": [ - "subgroup", - ], - "members": [ - "jamesdoe", - ], - "parent": undefined, - "profile": { - "displayName": "biggroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/id": "eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/realm": "master", - }, - "name": "subgroup", - }, - "spec": { - "children": [], - "members": [], - "parent": "biggroup", - "profile": { - "displayName": "subgroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/id": "557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/realm": "master", - }, - "name": "emptygroup", - }, - "spec": { - "children": [], - "members": [], - "parent": undefined, - "profile": { - "displayName": "emptygroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - ], - "type": "full", - }, - ], -] -`; - -exports[`KeycloakOrgEntityProvider with v24 should read with grantType client_credential 1`] = ` -[ - [ - { - "entities": [ - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/id": "59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/realm": "master", - }, - "name": "jamesdoe", - }, - "spec": { - "memberOf": [ - "biggroup", - ], - "profile": { - "email": "jamesdoe@gmail.com", - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/id": "c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/realm": "master", - }, - "name": "joedoe", - }, - "spec": { - "memberOf": [], - "profile": { - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/id": "2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/realm": "master", - }, - "name": "johndoe", - }, - "spec": { - "memberOf": [], - "profile": { - "displayName": "John Doe", - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/id": "9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/realm": "master", - }, - "name": "biggroup", - }, - "spec": { - "children": [ - "subgroup", - ], - "members": [ - "jamesdoe", - ], - "parent": undefined, - "profile": { - "displayName": "biggroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/id": "eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/realm": "master", - }, - "name": "subgroup", - }, - "spec": { - "children": [], - "members": [], - "parent": "biggroup", - "profile": { - "displayName": "subgroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/id": "557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/realm": "master", - }, - "name": "emptygroup", - }, - "spec": { - "children": [], - "members": [], - "parent": undefined, - "profile": { - "displayName": "emptygroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - ], - "type": "full", - }, - ], -] -`; - -exports[`KeycloakOrgEntityProvider with v24 should read with grantType password 1`] = ` -[ - [ - { - "entities": [ - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/id": "59efec15-a00b-4700-8833-5f4cdecc1132", - "keycloak.org/realm": "master", - }, - "name": "jamesdoe", - }, - "spec": { - "memberOf": [ - "biggroup", - ], - "profile": { - "email": "jamesdoe@gmail.com", - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/id": "c982b51a-abf6-4f68-bfdf-a1c6257214fc", - "keycloak.org/realm": "master", - }, - "name": "joedoe", - }, - "spec": { - "memberOf": [], - "profile": { - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "User", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/users/2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/id": "2bf97dbd-fd6a-47ae-986b-2632fa95e03f", - "keycloak.org/realm": "master", - }, - "name": "johndoe", - }, - "spec": { - "memberOf": [], - "profile": { - "displayName": "John Doe", - "email": undefined, - }, - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/id": "9cf51b5d-e066-4ed8-940c-dc6da77f81a5", - "keycloak.org/realm": "master", - }, - "name": "biggroup", - }, - "spec": { - "children": [ - "subgroup", - ], - "members": [ - "jamesdoe", - ], - "parent": undefined, - "profile": { - "displayName": "biggroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/id": "eefa5b46-0509-41d8-b8b3-7ddae9c83632", - "keycloak.org/realm": "master", - }, - "name": "subgroup", - }, - "spec": { - "children": [], - "members": [], - "parent": "biggroup", - "profile": { - "displayName": "subgroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - { - "entity": { - "apiVersion": "backstage.io/v1beta1", - "kind": "Group", - "metadata": { - "annotations": { - "backstage.io/managed-by-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "backstage.io/managed-by-origin-location": "url:http://localhost:8080/admin/realms/master/groups/557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/id": "557501bd-8188-41c0-a2d5-43ff3d5b0258", - "keycloak.org/realm": "master", - }, - "name": "emptygroup", - }, - "spec": { - "children": [], - "members": [], - "parent": undefined, - "profile": { - "displayName": "emptygroup", - }, - "type": "group", - }, - }, - "locationKey": "keycloak-org-provider:default", - }, - ], - "type": "full", - }, - ], -] -`; diff --git a/plugins/keycloak-backend/src/providers/index.ts b/plugins/keycloak-backend/src/providers/index.ts deleted file mode 100644 index a3dba7fb2b..0000000000 --- a/plugins/keycloak-backend/src/providers/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2022 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 { KeycloakOrgEntityProvider } from './KeycloakOrgEntityProvider'; -export type { KeycloakOrgEntityProviderOptions } from './KeycloakOrgEntityProvider'; diff --git a/plugins/keycloak-backend/src/setupTests.ts b/plugins/keycloak-backend/src/setupTests.ts deleted file mode 100644 index 134b7d101b..0000000000 --- a/plugins/keycloak-backend/src/setupTests.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2022 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 {}; diff --git a/plugins/keycloak-backend/tsconfig.json b/plugins/keycloak-backend/tsconfig.json deleted file mode 100644 index c15a033320..0000000000 --- a/plugins/keycloak-backend/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src", "dev", "migrations"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/keycloak-backend", - "rootDir": "." - } -} diff --git a/plugins/keycloak-backend/turbo.json b/plugins/keycloak-backend/turbo.json deleted file mode 100644 index db5f530e5b..0000000000 --- a/plugins/keycloak-backend/turbo.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "start:plugin": { - "cache": false, - "persistent": true - }, - "start:keycloak": { - "cache": false, - "persistent": true - }, - "tsc": { - "outputs": ["../../dist-types/plugins/keycloak-backend/**"] - } - } -} diff --git a/yarn.lock b/yarn.lock index c124c3f52c..c543b9cee7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8268,31 +8268,6 @@ __metadata: languageName: unknown linkType: soft -"@janus-idp/backstage-plugin-keycloak-backend@workspace:plugins/keycloak-backend": - version: 0.0.0-use.local - resolution: "@janus-idp/backstage-plugin-keycloak-backend@workspace:plugins/keycloak-backend" - dependencies: - "@backstage/backend-defaults": 0.5.2 - "@backstage/backend-plugin-api": ^1.0.1 - "@backstage/backend-test-utils": 1.0.2 - "@backstage/catalog-model": ^1.7.0 - "@backstage/cli": 0.28.2 - "@backstage/config": 1.2.0 - "@backstage/errors": ^1.2.4 - "@backstage/plugin-catalog-backend": 1.27.1 - "@backstage/plugin-catalog-node": ^1.13.1 - "@keycloak/keycloak-admin-client": 24.0.5 - "@types/lodash": 4.17.5 - "@types/uuid": 9.0.8 - deepmerge: 4.3.1 - inclusion: ^1.0.1 - lodash: ^4.17.21 - pg-format: ^1.0.4 - prettier: 3.3.3 - uuid: ^9.0.1 - languageName: unknown - linkType: soft - "@janus-idp/backstage-plugin-kiali-backend@workspace:plugins/kiali-backend": version: 0.0.0-use.local resolution: "@janus-idp/backstage-plugin-kiali-backend@workspace:plugins/kiali-backend" @@ -9695,17 +9670,6 @@ __metadata: languageName: node linkType: hard -"@keycloak/keycloak-admin-client@npm:24.0.5": - version: 24.0.5 - resolution: "@keycloak/keycloak-admin-client@npm:24.0.5" - dependencies: - camelize-ts: ^3.0.0 - url-join: ^5.0.0 - url-template: ^3.1.1 - checksum: bafbf888c2974ef09fcf2a97dd3d06aa3f8cba663befe35a1379962336a229ac55b6152b9e784ea591d765e23611858f87e786e5d3e75d6e33b69215ff343291 - languageName: node - linkType: hard - "@keyv/memcache@npm:^1.3.5": version: 1.4.1 resolution: "@keyv/memcache@npm:1.4.1" @@ -19427,13 +19391,6 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:9.0.8, @types/uuid@npm:^9.0.1": - version: 9.0.8 - resolution: "@types/uuid@npm:9.0.8" - checksum: b8c60b7ba8250356b5088302583d1704a4e1a13558d143c549c408bf8920535602ffc12394ede77f8a8083511b023704bc66d1345792714002bfa261b17c5275 - languageName: node - linkType: hard - "@types/uuid@npm:^10.0.0": version: 10.0.0 resolution: "@types/uuid@npm:10.0.0" @@ -19441,6 +19398,13 @@ __metadata: languageName: node linkType: hard +"@types/uuid@npm:^9.0.1": + version: 9.0.8 + resolution: "@types/uuid@npm:9.0.8" + checksum: b8c60b7ba8250356b5088302583d1704a4e1a13558d143c549c408bf8920535602ffc12394ede77f8a8083511b023704bc66d1345792714002bfa261b17c5275 + languageName: node + linkType: hard + "@types/webpack-env@npm:^1.15.2": version: 1.18.5 resolution: "@types/webpack-env@npm:1.18.5" @@ -22405,7 +22369,7 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0, callsites@npm:^3.1.0": +"callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 @@ -22450,13 +22414,6 @@ __metadata: languageName: node linkType: hard -"camelize-ts@npm:^3.0.0": - version: 3.0.0 - resolution: "camelize-ts@npm:3.0.0" - checksum: 835f7f79ddec6e6e0364c6a8294ce82586bca5d9443001f28077169181801cb126d8bc608c85504aa6c877de6fe5f7c9533f80996dc81117d865ff92c676d680 - languageName: node - linkType: hard - "caniuse-api@npm:^3.0.0": version: 3.0.0 resolution: "caniuse-api@npm:3.0.0" @@ -25055,13 +25012,6 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:4.3.1, deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.0, deepmerge@npm:^4.3.1, deepmerge@npm:~4.3.0": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 - languageName: node - linkType: hard - "deepmerge@npm:^2.1.1": version: 2.2.1 resolution: "deepmerge@npm:2.2.1" @@ -25069,6 +25019,13 @@ __metadata: languageName: node linkType: hard +"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.0, deepmerge@npm:^4.3.1, deepmerge@npm:~4.3.0": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 + languageName: node + linkType: hard + "default-browser-id@npm:3.0.0": version: 3.0.0 resolution: "default-browser-id@npm:3.0.0" @@ -30445,15 +30402,6 @@ __metadata: languageName: node linkType: hard -"inclusion@npm:^1.0.1": - version: 1.0.1 - resolution: "inclusion@npm:1.0.1" - dependencies: - parent-module: ^2.0.0 - checksum: 1ee1d829d4f354797b3c7ccca2a5fb669e7d4dafb83aaa96837265bbb6041eb4f7a6cab075730ba77c6b7b78c2918124411ba48092fa1bd13ee18c4b408ef36c - languageName: node - linkType: hard - "indent-string@npm:^4.0.0": version: 4.0.0 resolution: "indent-string@npm:4.0.0" @@ -38277,15 +38225,6 @@ __metadata: languageName: node linkType: hard -"parent-module@npm:^2.0.0": - version: 2.0.0 - resolution: "parent-module@npm:2.0.0" - dependencies: - callsites: ^3.1.0 - checksum: f131f13d687a938556a01033561fb1b274b39921eb4425c7a691f0d91dcfbe9b19759c2b8d425a3ee7c8a46874e57fa418a690643880c3c7c56827aba12f78dd - languageName: node - linkType: hard - "parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.7": version: 5.1.7 resolution: "parse-asn1@npm:5.1.7" @@ -46514,13 +46453,6 @@ __metadata: languageName: node linkType: hard -"url-join@npm:^5.0.0": - version: 5.0.0 - resolution: "url-join@npm:5.0.0" - checksum: 5921384a8ad4395b49ce4b50aa26efbc429cebe0bc8b3660ad693dd12fd859747b5369be0443e60e53a7850b2bc9d7d0687bcb94386662b40e743596bbf38101 - languageName: node - linkType: hard - "url-parse@npm:^1.5.10, url-parse@npm:^1.5.3": version: 1.5.10 resolution: "url-parse@npm:1.5.10" @@ -46531,13 +46463,6 @@ __metadata: languageName: node linkType: hard -"url-template@npm:^3.1.1": - version: 3.1.1 - resolution: "url-template@npm:3.1.1" - checksum: ac09daaeaec55a6b070b838ed161d66b050a46fc12ac251cb2db1ce356e786cfb117ee4391d943aaaa757971c509a0142b3cd83dfd8cc3d7b6d90a99d001a5f9 - languageName: node - linkType: hard - "url@npm:^0.11.0, url@npm:^0.11.3": version: 0.11.4 resolution: "url@npm:0.11.4"