From 1d4fd21702d9a144ac6ad4fd9e5635700dc7399e Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 20:50:15 +0100 Subject: [PATCH] [PR #11471/34938ca1 backport][stable-12] keycloak_user_rolemapping: handle None response for client role lookup (#11522) keycloak_user_rolemapping: handle None response for client role lookup (#11471) * fix(keycloak_user_rolemapping): handle None response for client role lookup When adding a client role to a user who has no existing roles for that client, get_client_user_rolemapping_by_id() returns None. The existing code indexed directly into the result causing a TypeError. Add the same None check that already existed for realm roles since PR #11256. Fixes #10960 * fix(tests): use dict format for task vars in keycloak_user_rolemapping tests Task-level vars requires a YAML mapping, not a sequence. The leading dash (- roles:) produced a list instead of a dict, which ansible-core 2.20 rejects with "Vars in a Task must be specified as a dictionary". * Update changelogs/fragments/keycloak-user-rolemapping-client-none-check.yml --------- (cherry picked from commit 34938ca1efe24d151c22ff136aa6acede95be2dc) Co-authored-by: Ivan Kokalovic <67540157+koke1997@users.noreply.github.com> Co-authored-by: Felix Fontein --- ...oak-user-rolemapping-client-none-check.yml | 5 ++ plugins/modules/keycloak_user_rolemapping.py | 6 +- .../keycloak_user_rolemapping/tasks/main.yml | 72 ++++++++++++++++--- .../keycloak_user_rolemapping/vars/main.yml | 1 + 4 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 changelogs/fragments/keycloak-user-rolemapping-client-none-check.yml diff --git a/changelogs/fragments/keycloak-user-rolemapping-client-none-check.yml b/changelogs/fragments/keycloak-user-rolemapping-client-none-check.yml new file mode 100644 index 0000000000..d6916c2af8 --- /dev/null +++ b/changelogs/fragments/keycloak-user-rolemapping-client-none-check.yml @@ -0,0 +1,5 @@ +bugfixes: + - keycloak_user_rolemapping - fix ``TypeError`` crash when adding a client + role to a user who has no existing roles for that client + (https://github.com/ansible-collections/community.general/issues/10960, + https://github.com/ansible-collections/community.general/pull/11471). diff --git a/plugins/modules/keycloak_user_rolemapping.py b/plugins/modules/keycloak_user_rolemapping.py index cc3004fca0..95a853913a 100644 --- a/plugins/modules/keycloak_user_rolemapping.py +++ b/plugins/modules/keycloak_user_rolemapping.py @@ -356,9 +356,9 @@ def main(): if role_rep is not None: role["name"] = role_rep["name"] else: - role["name"] = kc.get_client_user_rolemapping_by_id( - uid=uid, cid=cid, rid=role.get("id"), realm=realm - )["name"] + role_rep = kc.get_client_user_rolemapping_by_id(uid=uid, cid=cid, rid=role.get("id"), realm=realm) + if role_rep is not None: + role["name"] = role_rep["name"] if role.get("name") is None: module.fail_json( msg=f"Could not fetch role {role.get('id')} for client_id {client_id} or realm {realm}" diff --git a/tests/integration/targets/keycloak_user_rolemapping/tasks/main.yml b/tests/integration/targets/keycloak_user_rolemapping/tasks/main.yml index ff56371e58..318e47bedd 100644 --- a/tests/integration/targets/keycloak_user_rolemapping/tasks/main.yml +++ b/tests/integration/targets/keycloak_user_rolemapping/tasks/main.yml @@ -37,8 +37,8 @@ - name: Map a realm role to client service account vars: - - roles: - - name: '{{ role }}' + roles: + - name: '{{ role }}' community.general.keycloak_user_rolemapping: auth_keycloak_url: "{{ url }}" auth_realm: "{{ admin_realm }}" @@ -58,8 +58,8 @@ - name: Unmap a realm role from client service account vars: - - roles: - - name: '{{ role }}' + roles: + - name: '{{ role }}' community.general.keycloak_user_rolemapping: auth_keycloak_url: "{{ url }}" auth_realm: "{{ admin_realm }}" @@ -89,6 +89,18 @@ name: "{{ role }}" state: absent +- name: Create second client (for cross-client role mapping test) + community.general.keycloak_client: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_id_2 }}" + service_accounts_enabled: true + state: present + register: client_2 + - name: Create new client role community.general.keycloak_role: auth_keycloak_url: "{{ url }}" @@ -101,10 +113,54 @@ description: "{{ description_1 }}" state: present +- name: Map a client role to a user with no existing roles for that client + vars: + roles: + - name: '{{ role }}' + community.general.keycloak_user_rolemapping: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_id }}" + service_account_user_client_id: "{{ client_id_2 }}" + roles: "{{ roles }}" + state: present + register: result + +- name: Assert client role is assigned to user with no prior roles + assert: + that: + - result is changed + - result.end_state | selectattr("clientRole", "eq", true) | selectattr("name", "eq", role) | list | count > 0 + +- name: Unmap the cross-client role mapping + vars: + roles: + - name: '{{ role }}' + community.general.keycloak_user_rolemapping: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_id }}" + service_account_user_client_id: "{{ client_id_2 }}" + roles: "{{ roles }}" + state: absent + register: result + +- name: Assert cross-client role mapping is removed + assert: + that: + - result is changed + - result.end_state == [] + - name: Map a client role to client service account vars: - - roles: - - name: '{{ role }}' + roles: + - name: '{{ role }}' community.general.keycloak_user_rolemapping: auth_keycloak_url: "{{ url }}" auth_realm: "{{ admin_realm }}" @@ -125,8 +181,8 @@ - name: Unmap a client role from client service account vars: - - roles: - - name: '{{ role }}' + roles: + - name: '{{ role }}' community.general.keycloak_user_rolemapping: auth_keycloak_url: "{{ url }}" auth_realm: "{{ admin_realm }}" diff --git a/tests/integration/targets/keycloak_user_rolemapping/vars/main.yml b/tests/integration/targets/keycloak_user_rolemapping/vars/main.yml index 385dbea44a..90122ba96c 100644 --- a/tests/integration/targets/keycloak_user_rolemapping/vars/main.yml +++ b/tests/integration/targets/keycloak_user_rolemapping/vars/main.yml @@ -9,6 +9,7 @@ admin_user: admin admin_password: password realm: myrealm client_id: myclient +client_id_2: myotherclient role: myrole description_1: desc 1 description_2: desc 2