Uploaded image for project: 'Red Hat Internal Developer Platform'
  1. Red Hat Internal Developer Platform
  2. RHIDP-4793

[janus-idp/backstage-plugins] Keycloak backend plugin leads to DOS of Keycloak server

Prepare for Y ReleasePrepare for Z ReleaseRemove QuarterXMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Blocker Blocker
    • 1.3.2, 1.4
    • None
    • Plugins
    • RHDH Plugins 3266

      [2627201995] Upstream Reporter: JohannesWill
      Upstream issue status: Open
      Upstream description:

      Describe the bug

      I have setup the Keycloak backend plugin by following the steps given on below this link - https://janus-idp.io/plugins/keycloak/ .

      Syncing the users and Groups will overload our Keycloak instance by doing many parrallel requests

      Expected Behavior

      • All users and groups from keyclock realm should be synced
      • The Keycloak server should not experience a DoS (Denial of Service).

      What are the steps to reproduce this bug?

      1. Keycloak with many users and groups (in my case ~2500 users and 850 groups)
      2. Configure the Keycloak plugin for new backup configuration (using steps from https://janus-idp.io/plugins/keycloak/)

      Versions of software used and environment @janus-idp/backstage-plugin-keycloak-backend": "^2.0.8",

      Backstage - 1.30.4 (create-app@0.5.18)

      Temporary Workaround: During investigation of that problem I used patch-package to patch @janus-idp/backstage-plugin-keycloak-backend@2.0.8 for the project I'm working on. With that pacht, where I serialized the calls to Keycloak, the problem is not reproduceable anymore.

      Here is the diff that solved my problem:

      Unable to find source-code formatter for language: diff. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      diff --git a/node_modules/@janus-idp/backstage-plugin-keycloak-backend/dist/index.cjs.js b/node_modules/@janus-idp/backstage-plugin-keycloak-backend/dist/index.cjs.js
      index a0e323e..180abfc 100644
      --- a/node_modules/@janus-idp/backstage-plugin-keycloak-backend/dist/index.cjs.js
      +++ b/node_modules/@janus-idp/backstage-plugin-keycloak-backend/dist/index.cjs.js
      @@ -153,17 +153,19 @@ async function getEntities(entities, config, logger, entityQuerySize = KEYCLOAK_
         const rawEntityCount = await entities.count({ realm: config.realm });
         const entityCount = typeof rawEntityCount === "number" ? rawEntityCount : rawEntityCount.count;
         const pageCount = Math.ceil(entityCount / entityQuerySize);
      -  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)
      -    )
      -  );
      -  const entityResults = (await Promise.all(entityPromises)).flat();
      +  const entityResults = [];
      +  for (let i = 0; i < pageCount; i++) {
      +    try {
      +      const entitiesPage = await entities.find({
      +        realm: config.realm,
      +        max: entityQuerySize,
      +        first: i * entityQuerySize
      +      });
      +      entityResults.push(...entitiesPage);
      +    } catch (err) {
      +      logger.warn("Failed to retrieve Keycloak entities.", err);
      +    }
      +  }
         return entityResults;
       }
       async function getAllGroupMembers(groups, groupId, config, options) {
      @@ -254,35 +256,36 @@ const readKeycloakRealm = async (client, config, logger, options) => {
             []
           );
         }
      -  const kGroups = await Promise.all(
      -    rawKGroups.map(async (g) => {
      -      g.members = await getAllGroupMembers(
      -        client.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;
      -        }
      +  const kGroups = [];
      +  for (const g of rawKGroups) {
      +    g.members = await getAllGroupMembers(
      +      client.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;
      -    })
      -  );
      +    }
      +
      +    kGroups.push(g);
      +  }
         const parsedGroups = await kGroups.reduce(
           async (promise, g) => {
             const partial = await promise;
      

      This issue body was partially generated by patch-package.


      Upstream URL: https://github.com/janus-idp/backstage-plugins/issues/2471

              rh-ee-pknight Patrick Knight
              upstream-sync Upstream Sync
              RHIDP - Plugins
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated: