Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keycloak modules retry request on authentication error, support refresh token parameter #9494

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
31e3791
feat: begin refactor to support refresh token in keycloak modules
armkeh Sep 13, 2024
3fe444a
chore: add start of tests for shared token usage
armkeh Sep 14, 2024
c7341db
feat: progress towards supporting refresh token; token introspection …
armkeh Sep 28, 2024
670db1a
chore: reset to main branch previous state; a different approach is n…
armkeh Oct 16, 2024
016f5fe
Merge remote-tracking branch 'upstream/main'
armkeh Oct 16, 2024
b7fd1e8
feat: add request methods to keycloak class, which will be expanded w…
armkeh Nov 1, 2024
70813f3
chore: Merge remote-tracking branch 'upstream/main' [8857]
armkeh Nov 1, 2024
b73c82b
feat: all requests to keycloak use request methods instead of open_ur…
armkeh Nov 6, 2024
bfe339a
chore: Merge remote-tracking branch 'upstream/main' [8857]
armkeh Nov 9, 2024
d6a2730
fix: data argument is optional in keycloak request methods [8857]
armkeh Nov 9, 2024
8c7684a
feat: add integration test for keycloak module authentication methods…
armkeh Nov 9, 2024
08650d0
chore: refactor get token logic to separate logic using username/pass…
armkeh Nov 9, 2024
ccea7aa
chore: refactor token request logic further to isolate request logic …
armkeh Nov 9, 2024
bd31be4
chore: fix minor lint issues [8857]
armkeh Dec 30, 2024
817c085
test: add (currently failing) test for request with invalid auth toke…
armkeh Dec 30, 2024
6770085
chore: allow realm to be provided to role module with refresh_token, …
armkeh Dec 30, 2024
3b90af5
feat: add retry logic to requests in keycloak module utils [8857]
armkeh Dec 30, 2024
76a95ed
chore: rename keycloak module fail_open_url method to fail_request [8…
armkeh Dec 30, 2024
53eec38
chore: merge remote-tracking branch 'upstream/main' [8857]
armkeh Dec 30, 2024
5b23f10
chore: update all keycloak modules to support refresh token param [8857]
armkeh Dec 30, 2024
a782e11
chore: merge remote-tracking branch 'upstream/main' [8857]
armkeh Dec 30, 2024
a58ea2b
chore: add refresh_token param to keycloak doc_fragments [8857]
armkeh Dec 31, 2024
85296f9
chore: restore dependency between auth_realm and auth_username,auth_p…
armkeh Dec 31, 2024
42dfe5d
chore: rearrange module param checks to reduce future pr size [8857]
armkeh Dec 31, 2024
c7a9207
chore: remove extra comma [8857]
armkeh Dec 31, 2024
28fc381
chore: update version added for refresh token param [8857]
armkeh Jan 1, 2025
1145ae3
chore: merge remote-tracking branch 'upstream/main' [8857]
armkeh Jan 1, 2025
24dbd85
chore: add changelog fragment [8857]
armkeh Jan 3, 2025
f183ab5
chore: merge remote-tracking branch 'upstream/main' [8857]
armkeh Jan 3, 2025
3ebc757
chore: re-add fail_open_url to keycloak module utils for backward com…
armkeh Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions plugins/doc_fragments/keycloak.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ class ModuleDocFragment(object):
type: str
version_added: 3.0.0

refresh_token:
description:
- Authentication refresh token for Keycloak API.
type: str
version_added: 10.2.0
armkeh marked this conversation as resolved.
Show resolved Hide resolved

validate_certs:
description:
- Verify TLS certificates (do not disable this in production).
Expand Down
1,112 changes: 480 additions & 632 deletions plugins/module_utils/identity/keycloak/keycloak.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion plugins/modules/keycloak_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', flow={})
Expand Down
3 changes: 2 additions & 1 deletion plugins/modules/keycloak_authentication_required_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ def main():
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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', end_state={}, diff=dict(before={}, after={}))
Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_authz_authorization_scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ def main():
supports_check_mode=True,
required_one_of=(
[['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', end_state={}, diff=dict(before={}, after={}))

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_authz_custom_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ def main():
supports_check_mode=True,
required_one_of=(
[['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_authz_permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ def main():
supports_check_mode=True,
required_one_of=(
[['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

# Convenience variables
state = module.params.get('state')
Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_authz_permission_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ def main():
supports_check_mode=True,
required_one_of=(
[['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

# Convenience variables
name = module.params.get('name')
Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,9 @@ def main():
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']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_client_rolemapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_clientscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,9 @@ def main():
supports_check_mode=True,
required_one_of=([['id', 'name'],
['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_clientscope_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,13 @@ def keycloak_clientscope_type_module():
['default_clientscopes', 'optional_clientscopes']
]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
mutually_exclusive=[
['token', 'auth_realm'],
['token', 'auth_username'],
['token', 'auth_password']
])
],
)

return module

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_clienttemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ def main():
supports_check_mode=True,
required_one_of=([['id', 'name'],
['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', end_state={}, diff=dict(before={}, after={}))

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,9 @@ def main():
supports_check_mode=True,
required_one_of=([['id', 'name'],
['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, group='')

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_identity_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_realm.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,9 @@ def main():
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']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_realm_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

# Initialize the result object. Only "changed" seems to have special
# meaning for Ansible.
Expand Down
3 changes: 2 additions & 1 deletion plugins/modules/keycloak_realm_keys_metadata_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def main():
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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg="", keys_metadata="")
Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_realm_rolemapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_user_federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,9 @@ def main():
supports_check_mode=True,
required_one_of=([['id', 'name'],
['token', 'auth_realm', 'auth_username', 'auth_password']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_user_rolemapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ def main():
supports_check_mode=True,
required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password'],
['uid', 'target_username', 'service_account_user_client_id']]),
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
required_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})

Expand Down
4 changes: 3 additions & 1 deletion plugins/modules/keycloak_userprofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,9 @@ 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_together=([['auth_realm', 'auth_username', 'auth_password']]),
required_by={'refresh_token': 'auth_realm'},
)

# Initialize the result object. Only "changed" seems to have special
# meaning for Ansible.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!--
Copyright (c) Ansible Project
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
-->
# Running keycloak module authentication integration test

To run the Keycloak module authentication integration test, start a keycloak server using Docker or Podman:

```sh
podman|docker run -d --rm --name mykeycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:latest start-dev --http-relative-path /auth
```

Source Ansible env-setup from ansible github repository.

Run the integration tests:

```sh
ansible-test integration keycloak_role --python 3.10 --allow-unsupported
```

To cleanup, run:

```sh
podman|docker stop mykeycloak
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) Ansible Project
# 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

unsupported
Loading