From f44ca23d7a5aec7c38f397d7a77803deb89ce920 Mon Sep 17 00:00:00 2001 From: divinity666 <65871511+divinity666@users.noreply.github.com> Date: Wed, 18 Jun 2025 07:40:46 +0200 Subject: [PATCH] keycloak: add support for client_credentials authentication (#10231) * add client_credentials authentication for keycloak tasks incl. test case * support client credentials in all keycloak modules * Add changelog fragment * fix typos in required list * Update changelogs/fragments/10231-keycloak-add-client-credentials-authentication.yml Co-authored-by: Felix Fontein * revert keycloak url in test environment --------- Co-authored-by: Felix Fontein --- ...-add-client-credentials-authentication.yml | 2 + .../identity/keycloak/keycloak.py | 46 ++++++++- plugins/modules/keycloak_authentication.py | 4 +- ...eycloak_authentication_required_actions.py | 4 +- .../keycloak_authz_authorization_scope.py | 4 +- .../modules/keycloak_authz_custom_policy.py | 4 +- plugins/modules/keycloak_authz_permission.py | 4 +- .../modules/keycloak_authz_permission_info.py | 4 +- plugins/modules/keycloak_client.py | 4 +- .../modules/keycloak_client_rolemapping.py | 4 +- plugins/modules/keycloak_clientscope.py | 4 +- plugins/modules/keycloak_clientscope_type.py | 4 +- plugins/modules/keycloak_clienttemplate.py | 4 +- plugins/modules/keycloak_component.py | 4 +- plugins/modules/keycloak_group.py | 4 +- plugins/modules/keycloak_identity_provider.py | 4 +- plugins/modules/keycloak_realm.py | 4 +- plugins/modules/keycloak_realm_key.py | 4 +- .../keycloak_realm_keys_metadata_info.py | 4 +- plugins/modules/keycloak_realm_rolemapping.py | 4 +- plugins/modules/keycloak_role.py | 4 +- plugins/modules/keycloak_user.py | 4 +- plugins/modules/keycloak_user_federation.py | 4 +- plugins/modules/keycloak_user_rolemapping.py | 4 +- plugins/modules/keycloak_userprofile.py | 4 +- .../tasks/main.yml | 99 ++++++++++++++++++- .../vars/main.yml | 1 + 27 files changed, 190 insertions(+), 50 deletions(-) create mode 100644 changelogs/fragments/10231-keycloak-add-client-credentials-authentication.yml diff --git a/changelogs/fragments/10231-keycloak-add-client-credentials-authentication.yml b/changelogs/fragments/10231-keycloak-add-client-credentials-authentication.yml new file mode 100644 index 0000000000..eec12e8669 --- /dev/null +++ b/changelogs/fragments/10231-keycloak-add-client-credentials-authentication.yml @@ -0,0 +1,2 @@ +minor_changes: + - keycloak - add support for ``grant_type=client_credentials`` to all keycloak modules, so that specifying ``auth_client_id`` and ``auth_client_secret`` is sufficient for authentication (https://github.com/ansible-collections/community.general/pull/10231). diff --git a/plugins/module_utils/identity/keycloak/keycloak.py b/plugins/module_utils/identity/keycloak/keycloak.py index 45216a9302..40fd249b5c 100644 --- a/plugins/module_utils/identity/keycloak/keycloak.py +++ b/plugins/module_utils/identity/keycloak/keycloak.py @@ -248,6 +248,29 @@ def _request_token_using_refresh_token(module_params): return _token_request(module_params, payload) +def _request_token_using_client_credentials(module_params): + """ Obtains connection header with token for the authentication, + using the provided auth_client_id and auth_client_secret by grant_type + client_credentials. Ensure that the used client uses client authorization + with service account roles enabled and required service roles assigned. + :param module_params: parameters of the module. Must include 'auth_client_id' + and 'auth_client_secret'.. + :return: connection header + """ + client_id = module_params.get('auth_client_id') + client_secret = module_params.get('auth_client_secret') + + temp_payload = { + 'grant_type': 'client_credentials', + 'client_id': client_id, + 'client_secret': client_secret, + } + # Remove empty items, for instance missing client_secret + payload = {k: v for k, v in temp_payload.items() if v is not None} + + return _token_request(module_params, payload) + + def get_token(module_params): """ Obtains connection header with token for the authentication, token already given or obtained from credentials @@ -257,7 +280,13 @@ def get_token(module_params): token = module_params.get('token') if token is None: - token = _request_token_using_credentials(module_params) + auth_client_id = module_params.get('auth_client_id') + auth_client_secret = module_params.get('auth_client_secret') + auth_username = module_params.get('auth_username') + if auth_client_id is not None and auth_client_secret is not None and auth_username is None: + token = _request_token_using_client_credentials(module_params) + else: + token = _request_token_using_credentials(module_params) return { 'Authorization': 'Bearer ' + token, @@ -387,6 +416,21 @@ class KeycloakAPI(object): r = make_request_catching_401() + if isinstance(r, Exception): + # Try to re-auth with client_id and client_secret, if available + auth_client_id = self.module.params.get('auth_client_id') + auth_client_secret = self.module.params.get('auth_client_secret') + if auth_client_id is not None and auth_client_secret is not None: + try: + token = _request_token_using_client_credentials(self.module.params) + self.restheaders['Authorization'] = 'Bearer ' + token + + r = make_request_catching_401() + except KeycloakError as e: + # Token refresh returns 400 if token is expired/invalid, so continue on if we get a 400 + if e.authError is not None and e.authError.code != 400: + raise e + if isinstance(r, Exception): # Either no re-auth options were available, or they all failed raise r diff --git a/plugins/modules/keycloak_authentication.py b/plugins/modules/keycloak_authentication.py index fddff7a324..ae6d24958c 100644 --- a/plugins/modules/keycloak_authentication.py +++ b/plugins/modules/keycloak_authentication.py @@ -367,8 +367,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_authentication_required_actions.py b/plugins/modules/keycloak_authentication_required_actions.py index 147acf9a1e..246963202f 100644 --- a/plugins/modules/keycloak_authentication_required_actions.py +++ b/plugins/modules/keycloak_authentication_required_actions.py @@ -237,8 +237,8 @@ def main(): module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_authz_authorization_scope.py b/plugins/modules/keycloak_authz_authorization_scope.py index 6b2e3c30f6..ef094830f5 100644 --- a/plugins/modules/keycloak_authz_authorization_scope.py +++ b/plugins/modules/keycloak_authz_authorization_scope.py @@ -153,8 +153,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=( - [['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + [['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_authz_custom_policy.py b/plugins/modules/keycloak_authz_custom_policy.py index 5e1a2a6a2d..132119f53f 100644 --- a/plugins/modules/keycloak_authz_custom_policy.py +++ b/plugins/modules/keycloak_authz_custom_policy.py @@ -139,8 +139,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=( - [['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + [['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_authz_permission.py b/plugins/modules/keycloak_authz_permission.py index 683b5f8c18..e931fd72f9 100644 --- a/plugins/modules/keycloak_authz_permission.py +++ b/plugins/modules/keycloak_authz_permission.py @@ -253,8 +253,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=( - [['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + [['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_authz_permission_info.py b/plugins/modules/keycloak_authz_permission_info.py index 0271dfd4c4..af7318315f 100644 --- a/plugins/modules/keycloak_authz_permission_info.py +++ b/plugins/modules/keycloak_authz_permission_info.py @@ -134,8 +134,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=( - [['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + [['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_client.py b/plugins/modules/keycloak_client.py index e7a2de7c85..0a7f3fe73f 100644 --- a/plugins/modules/keycloak_client.py +++ b/plugins/modules/keycloak_client.py @@ -941,8 +941,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['client_id', 'id'], - ['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_client_rolemapping.py b/plugins/modules/keycloak_client_rolemapping.py index cb1cad8291..ff41486873 100644 --- a/plugins/modules/keycloak_client_rolemapping.py +++ b/plugins/modules/keycloak_client_rolemapping.py @@ -268,8 +268,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_clientscope.py b/plugins/modules/keycloak_clientscope.py index 4c452d4f2e..ed9fe97043 100644 --- a/plugins/modules/keycloak_clientscope.py +++ b/plugins/modules/keycloak_clientscope.py @@ -354,8 +354,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'name'], - ['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_clientscope_type.py b/plugins/modules/keycloak_clientscope_type.py index 0e742f676c..493363f391 100644 --- a/plugins/modules/keycloak_clientscope_type.py +++ b/plugins/modules/keycloak_clientscope_type.py @@ -145,10 +145,10 @@ def keycloak_clientscope_type_module(): argument_spec=argument_spec, supports_check_mode=True, required_one_of=([ - ['token', 'auth_realm', 'auth_username', 'auth_password'], + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret'], ['default_clientscopes', 'optional_clientscopes'] ]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, mutually_exclusive=[ ['token', 'auth_realm'], diff --git a/plugins/modules/keycloak_clienttemplate.py b/plugins/modules/keycloak_clienttemplate.py index a6af59b5ac..53b1266c7c 100644 --- a/plugins/modules/keycloak_clienttemplate.py +++ b/plugins/modules/keycloak_clienttemplate.py @@ -311,8 +311,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'name'], - ['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_component.py b/plugins/modules/keycloak_component.py index d5a3be2a8e..15c3c8e731 100644 --- a/plugins/modules/keycloak_component.py +++ b/plugins/modules/keycloak_component.py @@ -155,8 +155,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_group.py b/plugins/modules/keycloak_group.py index 08d2555745..865b52213a 100644 --- a/plugins/modules/keycloak_group.py +++ b/plugins/modules/keycloak_group.py @@ -334,8 +334,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'name'], - ['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_identity_provider.py b/plugins/modules/keycloak_identity_provider.py index 2107e273a8..eea168a14b 100644 --- a/plugins/modules/keycloak_identity_provider.py +++ b/plugins/modules/keycloak_identity_provider.py @@ -500,8 +500,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_realm.py b/plugins/modules/keycloak_realm.py index 6d896d4141..c2d4dceb21 100644 --- a/plugins/modules/keycloak_realm.py +++ b/plugins/modules/keycloak_realm.py @@ -705,8 +705,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'realm', 'enabled'], - ['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_realm_key.py b/plugins/modules/keycloak_realm_key.py index 97e0af6da5..4f6caa4464 100644 --- a/plugins/modules/keycloak_realm_key.py +++ b/plugins/modules/keycloak_realm_key.py @@ -263,8 +263,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_realm_keys_metadata_info.py b/plugins/modules/keycloak_realm_keys_metadata_info.py index 9946bd88ba..8340c8f2a5 100644 --- a/plugins/modules/keycloak_realm_keys_metadata_info.py +++ b/plugins/modules/keycloak_realm_keys_metadata_info.py @@ -104,8 +104,8 @@ def main(): module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([["token", "auth_realm", "auth_username", "auth_password"]]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_realm_rolemapping.py b/plugins/modules/keycloak_realm_rolemapping.py index 2937ed0ec0..2e3366d422 100644 --- a/plugins/modules/keycloak_realm_rolemapping.py +++ b/plugins/modules/keycloak_realm_rolemapping.py @@ -252,8 +252,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_role.py b/plugins/modules/keycloak_role.py index 9444140f06..c9979653c5 100644 --- a/plugins/modules/keycloak_role.py +++ b/plugins/modules/keycloak_role.py @@ -266,8 +266,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_user.py b/plugins/modules/keycloak_user.py index 71e793ae21..83bf8f5d02 100644 --- a/plugins/modules/keycloak_user.py +++ b/plugins/modules/keycloak_user.py @@ -410,8 +410,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_user_federation.py b/plugins/modules/keycloak_user_federation.py index 13428ddeb3..b3b86111c0 100644 --- a/plugins/modules/keycloak_user_federation.py +++ b/plugins/modules/keycloak_user_federation.py @@ -841,8 +841,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=([['id', 'name'], - ['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + ['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_user_rolemapping.py b/plugins/modules/keycloak_user_rolemapping.py index c15bf09410..794ea369d7 100644 --- a/plugins/modules/keycloak_user_rolemapping.py +++ b/plugins/modules/keycloak_user_rolemapping.py @@ -242,9 +242,9 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password'], + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret'], ['uid', 'target_username', 'service_account_user_client_id']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/plugins/modules/keycloak_userprofile.py b/plugins/modules/keycloak_userprofile.py index f637271497..a79ca93890 100644 --- a/plugins/modules/keycloak_userprofile.py +++ b/plugins/modules/keycloak_userprofile.py @@ -533,8 +533,8 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, - required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]), - required_together=([['auth_realm', 'auth_username', 'auth_password']]), + required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password', 'auth_client_id', 'auth_client_secret']]), + required_together=([['auth_username', 'auth_password']]), required_by={'refresh_token': 'auth_realm'}, ) diff --git a/tests/integration/targets/keycloak_modules_authentication/tasks/main.yml b/tests/integration/targets/keycloak_modules_authentication/tasks/main.yml index 1553e29c1c..b788865de9 100644 --- a/tests/integration/targets/keycloak_modules_authentication/tasks/main.yml +++ b/tests/integration/targets/keycloak_modules_authentication/tasks/main.yml @@ -3,6 +3,19 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later +- name: Reset public login in master admin-cli (if potentially previous test failed) + community.general.keycloak_client: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + auth_client_id: "admin-cli" + auth_client_secret: "{{ client_secret }}" + client_id: "admin-cli" + secret: "{{ client_secret }}" + public_client: true + state: present + - name: Create realm community.general.keycloak_realm: auth_keycloak_url: "{{ url }}" @@ -201,6 +214,89 @@ debug: var: result +- name: PREPARE - Temporarily disable public login in master admin-cli + community.general.keycloak_client: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + auth_client_id: "admin-cli" + auth_client_secret: "{{ client_secret }}" + client_id: "admin-cli" + secret: "{{ client_secret }}" + public_client: false + service_accounts_enabled: true + client_authenticator_type: "client-secret" + state: present + +- name: PREPARE - Get admin role id + community.general.keycloak_role: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + auth_client_id: "admin-cli" + auth_client_secret: "{{ client_secret }}" + name: "admin" + register: admin_role + +- name: PREPARE - Assign admin role to admin-cli in master + community.general.keycloak_user_rolemapping: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + auth_client_id: "admin-cli" + auth_client_secret: "{{ client_secret }}" + realm: "master" + roles: + - name: "admin" + service_account_user_client_id: "admin-cli" + +- name: Create new realm role with valid client_id and client_secret + community.general.keycloak_role: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_client_id: "admin-cli" + auth_client_secret: "{{ client_secret }}" + realm: "{{ realm }}" + name: "{{ role }}" + description: "{{ keycloak_role_description }}" + state: present + register: result + +- name: Debug + debug: + var: result + +- name: Reset temporarily disabled public login in master admin-cli + community.general.keycloak_client: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + auth_client_id: "admin-cli" + auth_client_secret: "{{ client_secret }}" + client_id: "admin-cli" + secret: "{{ client_secret }}" + public_client: true + state: present + +- name: Remove created realm role + community.general.keycloak_role: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + name: "{{ role }}" + state: absent + register: result + +- name: Debug + debug: + var: result + ### Unhappy path tests - name: Fail to create new realm role with invalid username/password @@ -215,7 +311,6 @@ state: present register: result failed_when: > - (result.exception is not defined) or ("HTTP Error 401: Unauthorized" not in result.msg) - name: Fail to create new realm role with invalid auth token @@ -228,7 +323,6 @@ state: present register: result failed_when: > - (result.exception is not defined) or ("HTTP Error 401: Unauthorized" not in result.msg) - name: Fail to create new realm role with invalid auth and refresh tokens, and invalid username/password @@ -245,5 +339,4 @@ state: present register: result failed_when: > - (result.exception is not defined) or ("HTTP Error 401: Unauthorized" not in result.msg) diff --git a/tests/integration/targets/keycloak_modules_authentication/vars/main.yml b/tests/integration/targets/keycloak_modules_authentication/vars/main.yml index 02ad618e1b..f57d791d86 100644 --- a/tests/integration/targets/keycloak_modules_authentication/vars/main.yml +++ b/tests/integration/targets/keycloak_modules_authentication/vars/main.yml @@ -9,6 +9,7 @@ admin_user: admin admin_password: password realm: myrealm client_id: myclient +client_secret: myclientsecret role: myrole keycloak_role_name: test