[PR #11503/85a0deee backport][stable-12] keycloak module utils: group search optimization (#11511)

keycloak module utils: group search optimization (#11503)

* Updated get_group_by_name with a query based lookup for improved speed

* Add changelog fragment for keycloak group search optimization

* Address review feedback: update changelog text and reformat code with ruff

* improved changelog fragment

* Update changelogs/fragments/11503-keycloak-group-search-optimization.yml



---------


(cherry picked from commit 85a0deeeba)

Co-authored-by: Andreas Wegmann <andreas.we9mann@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
patchback[bot]
2026-02-14 21:14:52 +01:00
committed by GitHub
parent 6437fe15c8
commit a0c4308bed
2 changed files with 18 additions and 6 deletions

View File

@@ -0,0 +1,3 @@
---
minor_changes:
- keycloak_client_rolemapping, keycloak_realm_rolemapping, keycloak_group - optimize retrieval of groups by name to use Keycloak search API with exact matching instead of fetching all groups (https://github.com/ansible-collections/community.general/pull/11503).

View File

@@ -1637,9 +1637,8 @@ class KeycloakAPI:
def get_group_by_name(self, name, realm: str = "master", parents=None): def get_group_by_name(self, name, realm: str = "master", parents=None):
"""Fetch a keycloak group within a realm based on its name. """Fetch a keycloak group within a realm based on its name.
The Keycloak API does not allow filtering of the Groups resource by name. Uses the Keycloak search API with exact matching for efficient lookup
As a result, this method first retrieves the entire list of groups - name and ID - instead of fetching all groups.
then performs a second query to fetch the group.
If the group does not exist, None is returned. If the group does not exist, None is returned.
:param name: Name of the group to fetch. :param name: Name of the group to fetch.
@@ -1653,11 +1652,21 @@ class KeycloakAPI:
if not parent: if not parent:
return None return None
all_groups = self.get_subgroups(parent, realm) # For subgroups: use children endpoint with search parameter
search_url = "{url}?search={name}&exact=true".format(
url=URL_GROUP_CHILDREN.format(url=self.baseurl, realm=realm, groupid=parent["id"]),
name=quote(name, safe=""),
)
else: else:
all_groups = self.get_groups(realm=realm) # For top-level groups: use groups endpoint with search parameter
search_url = "{url}?search={name}&exact=true".format(
url=URL_GROUPS.format(url=self.baseurl, realm=realm), name=quote(name, safe="")
)
for group in all_groups: groups = self._request_and_deserialize(search_url, method="GET")
# exact=true should return only exact matches, but verify the name
for group in groups:
if group["name"] == name: if group["name"] == name:
return self.get_group_by_groupid(group["id"], realm=realm) return self.get_group_by_groupid(group["id"], realm=realm)