diff --git a/changelogs/fragments/5732-bugfix-keycloak-userfed-idempotency.yml b/changelogs/fragments/5732-bugfix-keycloak-userfed-idempotency.yml new file mode 100644 index 0000000000..c50a105c3f --- /dev/null +++ b/changelogs/fragments/5732-bugfix-keycloak-userfed-idempotency.yml @@ -0,0 +1,6 @@ +bugfixes: + - > + keycloak_user_federation - fixes idempotency detection issues. In some + cases the module could fail to properly detect already existing user + federations because of a buggy seemingly superflous extra query parameter + (https://github.com/ansible-collections/community.general/pull/5732). diff --git a/plugins/modules/identity/keycloak/keycloak_user_federation.py b/plugins/modules/identity/keycloak/keycloak_user_federation.py index 3e66c577ec..3659d757ac 100644 --- a/plugins/modules/identity/keycloak/keycloak_user_federation.py +++ b/plugins/modules/identity/keycloak/keycloak_user_federation.py @@ -24,7 +24,7 @@ description: to your needs and a user having the expected roles. - The names of module options are snake_cased versions of the camelCase ones found in the - Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/15.0/rest-api/index.html). + Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/20.0.2/rest-api/index.html). options: @@ -835,7 +835,7 @@ def main(): # See if it already exists in Keycloak if cid is None: - found = kc.get_components(urlencode(dict(type='org.keycloak.storage.UserStorageProvider', parent=realm, name=name)), realm) + found = kc.get_components(urlencode(dict(type='org.keycloak.storage.UserStorageProvider', name=name)), realm) if len(found) > 1: module.fail_json(msg='No ID given and found multiple user federations with name `{name}`. Cannot continue.'.format(name=name)) before_comp = next(iter(found), None) diff --git a/tests/integration/targets/keycloak_user_federation/tasks/main.yml b/tests/integration/targets/keycloak_user_federation/tasks/main.yml index 79e21dae03..139d6ee2be 100644 --- a/tests/integration/targets/keycloak_user_federation/tasks/main.yml +++ b/tests/integration/targets/keycloak_user_federation/tasks/main.yml @@ -66,6 +66,59 @@ - result.existing == {} - result.end_state.name == "{{ federation }}" +- name: Create new user federation in admin realm + community.general.keycloak_user_federation: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ admin_realm }}" + name: "{{ federation }}" + state: present + provider_id: ldap + provider_type: org.keycloak.storage.UserStorageProvider + config: + enabled: true + priority: 0 + fullSyncPeriod: -1 + changedSyncPeriod: -1 + cachePolicy: DEFAULT + batchSizeForSync: 1000 + editMode: READ_ONLY + importEnabled: true + syncRegistrations: false + vendor: other + usernameLDAPAttribute: uid + rdnLDAPAttribute: uid + uuidLDAPAttribute: entryUUID + userObjectClasses: "inetOrgPerson, organizationalPerson" + connectionUrl: "ldaps://ldap.example.com:636" + usersDn: "ou=Users,dc=example,dc=com" + authType: simple + bindDn: cn=directory reader + bindCredential: secret + searchScope: 1 + validatePasswordPolicy: false + trustEmail: false + useTruststoreSpi: "ldapsOnly" + connectionPooling: true + pagination: true + allowKerberosAuthentication: false + useKerberosForPasswordAuthentication: false + debug: false + register: result + +- name: Debug + debug: + var: result + +- name: Assert user federation created (admin realm) + assert: + that: + - result is changed + - result.existing == {} + - result.end_state.name == "{{ federation }}" + - name: Update existing user federation (no change) community.general.keycloak_user_federation: auth_keycloak_url: "{{ url }}" @@ -121,6 +174,61 @@ - result.end_state != {} - result.end_state.name == "{{ federation }}" +- name: Update existing user federation (no change, admin realm) + community.general.keycloak_user_federation: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ admin_realm }}" + name: "{{ federation }}" + state: present + provider_id: ldap + provider_type: org.keycloak.storage.UserStorageProvider + config: + enabled: true + priority: 0 + fullSyncPeriod: -1 + changedSyncPeriod: -1 + cachePolicy: DEFAULT + batchSizeForSync: 1000 + editMode: READ_ONLY + importEnabled: true + syncRegistrations: false + vendor: other + usernameLDAPAttribute: uid + rdnLDAPAttribute: uid + uuidLDAPAttribute: entryUUID + userObjectClasses: "inetOrgPerson, organizationalPerson" + connectionUrl: "ldaps://ldap.example.com:636" + usersDn: "ou=Users,dc=example,dc=com" + authType: simple + bindDn: cn=directory reader + bindCredential: "**********" + searchScope: 1 + validatePasswordPolicy: false + trustEmail: false + useTruststoreSpi: "ldapsOnly" + connectionPooling: true + pagination: true + allowKerberosAuthentication: false + useKerberosForPasswordAuthentication: false + debug: false + register: result + +- name: Debug + debug: + var: result + +- name: Assert user federation unchanged (admin realm) + assert: + that: + - result is not changed + - result.existing != {} + - result.existing.name == "{{ federation }}" + - result.end_state != {} + - result.end_state.name == "{{ federation }}" + - name: Update existing user federation (with change) community.general.keycloak_user_federation: auth_keycloak_url: "{{ url }}"