From 2b4db9057637e215d3d418968cbc5398d623ddee Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 16 Oct 2026 18:34:58 +0200 Subject: [PATCH] fix(web-app-keycloak): bring SAML clients to existing realms too SAML clients were created only by the realm import, and the import runs only for a missing realm, so a SAML app added to a running Keycloak never got its client: SuiteCRM's SAML hop answered 400 and Keycloak logged client_not_found. The existing-realm reconcile now also loops over the clientId of every SAML client in the rendered realm dictionary, the same source the import uses, and creates or updates it through kcadm like the application-declared OIDC clients. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../web-app-keycloak/tasks/03_manager_ops/update_routines.yml | 4 ++-- roles/web-app-keycloak/tasks/update/10_declared_client.yml | 2 +- roles/web-app-keycloak/vars/main.yml | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/roles/web-app-keycloak/tasks/03_manager_ops/update_routines.yml b/roles/web-app-keycloak/tasks/03_manager_ops/update_routines.yml index ff683da6a8..73a2d8a7fe 100644 --- a/roles/web-app-keycloak/tasks/03_manager_ops/update_routines.yml +++ b/roles/web-app-keycloak/tasks/03_manager_ops/update_routines.yml @@ -53,11 +53,11 @@ include_tasks: "{{ role_path }}/tasks/update/08_users/email_verified.yml" when: KEYCLOAK_USER_EMAILS_VERIFIED | bool -- name: "📂 Ensure application-declared clients (existing realms)" +- name: "📂 Ensure application-declared and SAML clients (existing realms)" include_tasks: "{{ role_path }}/tasks/update/10_declared_client.yml" vars: kc_declared_client_id: "{{ declared_client }}" - loop: "{{ KEYCLOAK_DECLARED_CLIENT_IDS }}" + loop: "{{ KEYCLOAK_DECLARED_CLIENT_IDS + KEYCLOAK_SAML_CLIENT_IDS }}" loop_control: loop_var: declared_client diff --git a/roles/web-app-keycloak/tasks/update/10_declared_client.yml b/roles/web-app-keycloak/tasks/update/10_declared_client.yml index 06a5934de8..bd44321fef 100644 --- a/roles/web-app-keycloak/tasks/update/10_declared_client.yml +++ b/roles/web-app-keycloak/tasks/update/10_declared_client.yml @@ -1,6 +1,6 @@ --- # Realm import only runs for a MISSING realm; this kcadm create-or-update brings -# application-declared clients to existing realms too. Desired state is the +# application-declared and SAML clients to existing realms too. Desired state is the # import's own client object, so the realm template stays the one SPOT. - name: "✅ Ensure the '{{ kc_declared_client_id }}' client" vars: diff --git a/roles/web-app-keycloak/vars/main.yml b/roles/web-app-keycloak/vars/main.yml index 9d18f834ae..5981defaca 100644 --- a/roles/web-app-keycloak/vars/main.yml +++ b/roles/web-app-keycloak/vars/main.yml @@ -127,6 +127,7 @@ KEYCLOAK_MOODLE_ENABLED: "{{ 'web-app-moodle' in group_names }}" KEYCLOAK_DECLARED_CLIENT_APPS: "{{ lookup('applications') | kc_declared_client_apps(lookup('deployment').groups) }}" KEYCLOAK_DECLARED_CLIENT_IDS: "{{ lookup('applications') | kc_declared_client_ids(lookup('deployment').groups) }}" +KEYCLOAK_SAML_CLIENT_IDS: "{{ KEYCLOAK_DICTIONARY_REALM.clients | selectattr('protocol', 'equalto', 'saml') | map(attribute='clientId') | list }}" KEYCLOAK_RECAPTCHA_ENABLED: "{{ lookup('config', application_id, 'services.recaptcha.enabled') }}" KEYCLOAK_RECAPTCHA_KEY: "{{ lookup('config', application_id, 'secrets.credentials.recaptcha.key') }}"