keycloak: add support for client_credentials authentication (#10231)
Some checks are pending
EOL CI / EOL Sanity (Ⓐ2.16) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py2.7) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.11) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.6) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/3/) (push) Waiting to run
nox / Run extra sanity tests (push) Waiting to run

* 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 <felix@fontein.de>

* revert keycloak url in test environment

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
divinity666 2025-06-18 07:40:46 +02:00 committed by GitHub
commit f44ca23d7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 190 additions and 50 deletions

View file

@ -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