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 4b9a277ac4..0000000000 Binary files a/plugins/keycloak-backend/images/group1.jpg and /dev/null differ diff --git a/plugins/keycloak-backend/images/user-list.jpg b/plugins/keycloak-backend/images/user-list.jpg deleted file mode 100644 index 344fd51353..0000000000 Binary files a/plugins/keycloak-backend/images/user-list.jpg and /dev/null differ diff --git a/plugins/keycloak-backend/images/user2.jpg b/plugins/keycloak-backend/images/user2.jpg deleted file mode 100644 index 95d29b7666..0000000000 Binary files a/plugins/keycloak-backend/images/user2.jpg and /dev/null differ diff --git a/plugins/keycloak-backend/images/users.jpg b/plugins/keycloak-backend/images/users.jpg deleted file mode 100644 index 393f14bdd5..0000000000 Binary files a/plugins/keycloak-backend/images/users.jpg and /dev/null differ diff --git a/plugins/keycloak-backend/package.json b/plugins/keycloak-backend/package.json deleted file mode 100644 index b7b89ffdb3..0000000000 --- a/plugins/keycloak-backend/package.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "name": "@janus-idp/backstage-plugin-keycloak-backend", - "version": "3.1.1", - "description": "A Backend backend plugin for Keycloak", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "publishConfig": { - "access": "public" - }, - "backstage": { - "role": "backend-plugin-module", - "supported-versions": "1.32.5", - "pluginId": "keycloak", - "pluginPackage": "@janus-idp/backstage-plugin-keycloak-backend" - }, - "exports": { - ".": "./src/index.ts", - "./package.json": "./package.json" - }, - "typesVersions": { - "*": { - "package.json": [ - "package.json" - ] - } - }, - "scripts": { - "build": "backstage-cli package build", - "clean": "backstage-cli package clean", - "lint:check": "backstage-cli package lint", - "lint:fix": "backstage-cli package lint --fix", - "postpack": "backstage-cli package postpack", - "prepack": "backstage-cli package prepack", - "start": "opener http://localhost:8080/admin/master/console/#/janus-realm && opener http://localhost:7007/catalog/entities && turbo run start:plugin start:keycloak", - "start:keycloak": "podman run -p 8080:8080 -e 'KEYCLOAK_ADMIN=admin' -e 'KEYCLOAK_ADMIN_PASSWORD=admin' -v ./__fixtures__/keycloak-realm.json:/opt/keycloak/data/import/keycloak-realm.json$([[ $OSTYPE = linux* ]] && echo ':z') quay.io/keycloak/keycloak:22.0.1 start-dev --import-realm", - "start:plugin": "backstage-cli package start", - "test": "backstage-cli package test --passWithNoTests --coverage", - "tsc": "tsc", - "prettier:check": "prettier --ignore-unknown --check .", - "prettier:fix": "prettier --ignore-unknown --write ." - }, - "dependencies": { - "@backstage/backend-plugin-api": "^1.0.1", - "@backstage/catalog-model": "^1.7.0", - "@backstage/errors": "^1.2.4", - "@backstage/plugin-catalog-node": "^1.13.1", - "@keycloak/keycloak-admin-client": "24.0.5", - "inclusion": "^1.0.1", - "lodash": "^4.17.21", - "pg-format": "^1.0.4", - "uuid": "^9.0.1" - }, - "devDependencies": { - "@backstage/backend-defaults": "0.5.2", - "@backstage/backend-test-utils": "1.0.2", - "@backstage/cli": "0.28.2", - "@backstage/config": "1.2.0", - "@backstage/plugin-catalog-backend": "1.27.1", - "@types/lodash": "4.17.5", - "@types/uuid": "9.0.8", - "deepmerge": "4.3.1", - "prettier": "3.3.3" - }, - "files": [ - "dist", - "embedded", - "config.d.ts", - "dist-dynamic/*.*", - "dist-dynamic/dist/**", - "app-config.janus-idp.yaml" - ], - "configSchema": "config.d.ts", - "repository": { - "type": "git", - "url": "https://github.com/janus-idp/backstage-plugins", - "directory": "plugins/keycloak-backend" - }, - "keywords": [ - "support:production", - "lifecycle:active", - "backstage", - "plugin", - "works-with:rhbk:^24", - "works-with:keycloak:~24" - ], - "homepage": "https://red.ht/rhdh", - "bugs": "https://github.com/janus-idp/backstage-plugins/issues", - "maintainers": [ - "@janus-idp/maintainers-plugins" - ], - "author": "Red Hat" -} diff --git a/plugins/keycloak-backend/src/extensions.ts b/plugins/keycloak-backend/src/extensions.ts deleted file mode 100644 index 0a5de58eff..0000000000 --- a/plugins/keycloak-backend/src/extensions.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createExtensionPoint } from '@backstage/backend-plugin-api'; - -import type { GroupTransformer, UserTransformer } from './lib/types'; - -/** - * An extension point that exposes the ability to implement user and group transformer functions for keycloak. - * - * @public - */ -export const keycloakTransformerExtensionPoint = - createExtensionPoint({ - 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"