diff --git a/changelogs/fragments/4212-fixes-for-keycloak-user-federation.yml b/changelogs/fragments/4212-fixes-for-keycloak-user-federation.yml new file mode 100644 index 0000000000..033add7a90 --- /dev/null +++ b/changelogs/fragments/4212-fixes-for-keycloak-user-federation.yml @@ -0,0 +1,8 @@ +--- +bugfixes: + - keycloak_user_federation - creating a user federation while specifying an + ID (that does not exist yet) no longer fail with a 404 Not Found + (https://github.com/ansible-collections/community.general/pull/4212). + - keycloak_user_federation - mappers auto-created by keycloak are matched and + merged by their name and no longer create duplicated entries + (https://github.com/ansible-collections/community.general/pull/4212). diff --git a/plugins/modules/identity/keycloak/keycloak_user_federation.py b/plugins/modules/identity/keycloak/keycloak_user_federation.py index f8e6d3aea4..4d623a4874 100644 --- a/plugins/modules/identity/keycloak/keycloak_user_federation.py +++ b/plugins/modules/identity/keycloak/keycloak_user_federation.py @@ -845,7 +845,7 @@ def main(): before_comp = {} # if user federation exists, get associated mappers - if cid is not None: + if cid is not None and before_comp: before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name')) # Build a proposed changeset from parameters given to this module @@ -921,12 +921,23 @@ def main(): after_comp = kc.create_component(desired_comp, realm) for mapper in updated_mappers: - if mapper.get('id') is not None: - kc.update_component(mapper, realm) + found = kc.get_components(urlencode(dict(parent=cid, name=mapper['name'])), realm) + if len(found) > 1: + module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=mapper['name'])) + if len(found) == 1: + old_mapper = found[0] else: - if mapper.get('parentId') is None: - mapper['parentId'] = after_comp['id'] - mapper = kc.create_component(mapper, realm) + old_mapper = {} + + new_mapper = old_mapper.copy() + new_mapper.update(mapper) + + if new_mapper.get('id') is not None: + kc.update_component(new_mapper, realm) + else: + if new_mapper.get('parentId') is None: + new_mapper['parentId'] = after_comp['id'] + mapper = kc.create_component(new_mapper, realm) after_comp['mappers'] = updated_mappers result['end_state'] = sanitize(after_comp) diff --git a/tests/unit/plugins/modules/identity/keycloak/test_keycloak_user_federation.py b/tests/unit/plugins/modules/identity/keycloak/test_keycloak_user_federation.py index 674efeb237..a37ea1bb11 100644 --- a/tests/unit/plugins/modules/identity/keycloak/test_keycloak_user_federation.py +++ b/tests/unit/plugins/modules/identity/keycloak/test_keycloak_user_federation.py @@ -342,7 +342,7 @@ class TestKeycloakUserFederation(ModuleTestCase): ] } return_value_components_get = [ - [] + [], [] ] return_value_component_create = [ { @@ -457,7 +457,7 @@ class TestKeycloakUserFederation(ModuleTestCase): with self.assertRaises(AnsibleExitJson) as exec_info: self.module.main() - self.assertEqual(len(mock_get_components.mock_calls), 1) + self.assertEqual(len(mock_get_components.mock_calls), 2) self.assertEqual(len(mock_get_component.mock_calls), 0) self.assertEqual(len(mock_create_component.mock_calls), 2) self.assertEqual(len(mock_update_component.mock_calls), 0)