mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Keycloak set client authentification flows by name (#8428)
* first commit * Add change logs * fix sanity * Sanity 2 * Test unset flows * Update plugins/modules/keycloak_client.py Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> * Update plugins/modules/keycloak_client.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update changelogs/fragments/8428-assign-auth-flow-by-name-keycloak-client.yaml Co-authored-by: Felix Fontein <felix@fontein.de> * Remove double traitement from "alias" * Update plugins/modules/keycloak_client.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/keycloak_client.py Co-authored-by: Felix Fontein <felix@fontein.de> --------- Co-authored-by: Andre Desrosiers <andre.desrosiers@ssss.gouv.qc.ca> Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
df7fe19bbe
commit
b11da288d2
3 changed files with 240 additions and 1 deletions
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- keycloak_client - assign auth flow by name (https://github.com/ansible-collections/community.general/pull/8428).
|
|
@ -340,6 +340,42 @@ options:
|
|||
description:
|
||||
- Override realm authentication flow bindings.
|
||||
type: dict
|
||||
suboptions:
|
||||
browser:
|
||||
description:
|
||||
- Flow ID of the browser authentication flow.
|
||||
- O(authentication_flow_binding_overrides.browser)
|
||||
and O(authentication_flow_binding_overrides.browser_name) are mutually exclusive.
|
||||
type: str
|
||||
|
||||
browser_name:
|
||||
description:
|
||||
- Flow name of the browser authentication flow.
|
||||
- O(authentication_flow_binding_overrides.browser)
|
||||
and O(authentication_flow_binding_overrides.browser_name) are mutually exclusive.
|
||||
aliases:
|
||||
- browserName
|
||||
type: str
|
||||
version_added: 9.1.0
|
||||
|
||||
direct_grant:
|
||||
description:
|
||||
- Flow ID of the direct grant authentication flow.
|
||||
- O(authentication_flow_binding_overrides.direct_grant)
|
||||
and O(authentication_flow_binding_overrides.direct_grant_name) are mutually exclusive.
|
||||
aliases:
|
||||
- directGrant
|
||||
type: str
|
||||
|
||||
direct_grant_name:
|
||||
description:
|
||||
- Flow name of the direct grant authentication flow.
|
||||
- O(authentication_flow_binding_overrides.direct_grant)
|
||||
and O(authentication_flow_binding_overrides.direct_grant_name) are mutually exclusive.
|
||||
aliases:
|
||||
- directGrantName
|
||||
type: str
|
||||
version_added: 9.1.0
|
||||
aliases:
|
||||
- authenticationFlowBindingOverrides
|
||||
version_added: 3.4.0
|
||||
|
@ -781,6 +817,64 @@ def sanitize_cr(clientrep):
|
|||
return normalise_cr(result)
|
||||
|
||||
|
||||
def get_authentication_flow_id(flow_name, realm, kc):
|
||||
""" Get the authentication flow ID based on the flow name, realm, and Keycloak client.
|
||||
|
||||
Args:
|
||||
flow_name (str): The name of the authentication flow.
|
||||
realm (str): The name of the realm.
|
||||
kc (KeycloakClient): The Keycloak client instance.
|
||||
|
||||
Returns:
|
||||
str: The ID of the authentication flow.
|
||||
|
||||
Raises:
|
||||
KeycloakAPIException: If the authentication flow with the given name is not found in the realm.
|
||||
"""
|
||||
flow = kc.get_authentication_flow_by_alias(flow_name, realm)
|
||||
if flow:
|
||||
return flow["id"]
|
||||
kc.module.fail_json(msg='Authentification flow %s not found in realm %s' % (flow_name, realm))
|
||||
|
||||
|
||||
def flow_binding_from_dict_to_model(newClientFlowBinding, realm, kc):
|
||||
""" Convert a dictionary representing client flow bindings to a model representation.
|
||||
|
||||
Args:
|
||||
newClientFlowBinding (dict): A dictionary containing client flow bindings.
|
||||
realm (str): The name of the realm.
|
||||
kc (KeycloakClient): An instance of the KeycloakClient class.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary representing the model flow bindings. The dictionary has two keys:
|
||||
- "browser" (str or None): The ID of the browser authentication flow binding, or None if not provided.
|
||||
- "direct_grant" (str or None): The ID of the direct grant authentication flow binding, or None if not provided.
|
||||
|
||||
Raises:
|
||||
KeycloakAPIException: If the authentication flow with the given name is not found in the realm.
|
||||
|
||||
"""
|
||||
|
||||
modelFlow = {
|
||||
"browser": None,
|
||||
"direct_grant": None
|
||||
}
|
||||
|
||||
for k, v in newClientFlowBinding.items():
|
||||
if not v:
|
||||
continue
|
||||
if k == "browser":
|
||||
modelFlow["browser"] = v
|
||||
elif k == "browser_name":
|
||||
modelFlow["browser"] = get_authentication_flow_id(v, realm, kc)
|
||||
elif k == "direct_grant":
|
||||
modelFlow["direct_grant"] = v
|
||||
elif k == "direct_grant_name":
|
||||
modelFlow["direct_grant"] = get_authentication_flow_id(v, realm, kc)
|
||||
|
||||
return modelFlow
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Module execution
|
||||
|
@ -799,6 +893,13 @@ def main():
|
|||
config=dict(type='dict'),
|
||||
)
|
||||
|
||||
authentication_flow_spec = dict(
|
||||
browser=dict(type='str'),
|
||||
browser_name=dict(type='str', aliases=['browserName']),
|
||||
direct_grant=dict(type='str', aliases=['directGrant']),
|
||||
direct_grant_name=dict(type='str', aliases=['directGrantName']),
|
||||
)
|
||||
|
||||
meta_args = dict(
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
realm=dict(type='str', default='master'),
|
||||
|
@ -838,7 +939,13 @@ def main():
|
|||
use_template_scope=dict(type='bool', aliases=['useTemplateScope']),
|
||||
use_template_mappers=dict(type='bool', aliases=['useTemplateMappers']),
|
||||
always_display_in_console=dict(type='bool', aliases=['alwaysDisplayInConsole']),
|
||||
authentication_flow_binding_overrides=dict(type='dict', aliases=['authenticationFlowBindingOverrides']),
|
||||
authentication_flow_binding_overrides=dict(
|
||||
type='dict',
|
||||
aliases=['authenticationFlowBindingOverrides'],
|
||||
options=authentication_flow_spec,
|
||||
required_one_of=[['browser', 'direct_grant', 'browser_name', 'direct_grant_name']],
|
||||
mutually_exclusive=[['browser', 'browser_name'], ['direct_grant', 'direct_grant_name']],
|
||||
),
|
||||
protocol_mappers=dict(type='list', elements='dict', options=protmapper_spec, aliases=['protocolMappers']),
|
||||
authorization_settings=dict(type='dict', aliases=['authorizationSettings']),
|
||||
default_client_scopes=dict(type='list', elements='str', aliases=['defaultClientScopes']),
|
||||
|
@ -900,6 +1007,8 @@ def main():
|
|||
# they are not specified
|
||||
if client_param == 'protocol_mappers':
|
||||
new_param_value = [dict((k, v) for k, v in x.items() if x[k] is not None) for x in new_param_value]
|
||||
elif client_param == 'authentication_flow_binding_overrides':
|
||||
new_param_value = flow_binding_from_dict_to_model(new_param_value, realm, kc)
|
||||
|
||||
changeset[camel(client_param)] = new_param_value
|
||||
|
||||
|
|
|
@ -103,3 +103,131 @@
|
|||
assert:
|
||||
that:
|
||||
- check_client_when_present_and_changed is changed
|
||||
|
||||
- name: Desire client with flow binding overrides
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
state: present
|
||||
redirect_uris: '{{redirect_uris1}}'
|
||||
attributes: '{{client_attributes1}}'
|
||||
protocol_mappers: '{{protocol_mappers1}}'
|
||||
authentication_flow_binding_overrides:
|
||||
browser_name: browser
|
||||
direct_grant_name: direct grant
|
||||
register: desire_client_with_flow_binding_overrides
|
||||
|
||||
- name: Assert flows are set
|
||||
assert:
|
||||
that:
|
||||
- desire_client_with_flow_binding_overrides is changed
|
||||
- "'authenticationFlowBindingOverrides' in desire_client_with_flow_binding_overrides.end_state"
|
||||
- desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.browser | length > 0
|
||||
- desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.direct_grant | length > 0
|
||||
|
||||
- name: Backup flow UUIDs
|
||||
set_fact:
|
||||
flow_browser_uuid: "{{ desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.browser }}"
|
||||
flow_direct_grant_uuid: "{{ desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.direct_grant }}"
|
||||
|
||||
- name: Desire client with flow binding overrides remove direct_grant_name
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
state: present
|
||||
redirect_uris: '{{redirect_uris1}}'
|
||||
attributes: '{{client_attributes1}}'
|
||||
protocol_mappers: '{{protocol_mappers1}}'
|
||||
authentication_flow_binding_overrides:
|
||||
browser_name: browser
|
||||
register: desire_client_with_flow_binding_overrides
|
||||
|
||||
- name: Assert flows are updated
|
||||
assert:
|
||||
that:
|
||||
- desire_client_with_flow_binding_overrides is changed
|
||||
- "'authenticationFlowBindingOverrides' in desire_client_with_flow_binding_overrides.end_state"
|
||||
- desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.browser | length > 0
|
||||
- "'direct_grant' not in desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides"
|
||||
|
||||
- name: Desire client with flow binding overrides remove browser add direct_grant
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
state: present
|
||||
redirect_uris: '{{redirect_uris1}}'
|
||||
attributes: '{{client_attributes1}}'
|
||||
protocol_mappers: '{{protocol_mappers1}}'
|
||||
authentication_flow_binding_overrides:
|
||||
direct_grant_name: direct grant
|
||||
register: desire_client_with_flow_binding_overrides
|
||||
|
||||
- name: Assert flows are updated
|
||||
assert:
|
||||
that:
|
||||
- desire_client_with_flow_binding_overrides is changed
|
||||
- "'authenticationFlowBindingOverrides' in desire_client_with_flow_binding_overrides.end_state"
|
||||
- "'browser' not in desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides"
|
||||
- desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.direct_grant | length > 0
|
||||
|
||||
- name: Desire client with flow binding overrides with UUIDs
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
state: present
|
||||
redirect_uris: '{{redirect_uris1}}'
|
||||
attributes: '{{client_attributes1}}'
|
||||
protocol_mappers: '{{protocol_mappers1}}'
|
||||
authentication_flow_binding_overrides:
|
||||
browser: "{{ flow_browser_uuid }}"
|
||||
direct_grant: "{{ flow_direct_grant_uuid }}"
|
||||
register: desire_client_with_flow_binding_overrides
|
||||
|
||||
- name: Assert flows are updated
|
||||
assert:
|
||||
that:
|
||||
- desire_client_with_flow_binding_overrides is changed
|
||||
- "'authenticationFlowBindingOverrides' in desire_client_with_flow_binding_overrides.end_state"
|
||||
- desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.browser == flow_browser_uuid
|
||||
- desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides.direct_grant == flow_direct_grant_uuid
|
||||
|
||||
- name: Unset flow binding overrides
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
client_id: "{{ client_id }}"
|
||||
state: present
|
||||
redirect_uris: '{{redirect_uris1}}'
|
||||
attributes: '{{client_attributes1}}'
|
||||
protocol_mappers: '{{protocol_mappers1}}'
|
||||
authentication_flow_binding_overrides:
|
||||
browser: "{{ None }}"
|
||||
direct_grant: null
|
||||
register: desire_client_with_flow_binding_overrides
|
||||
|
||||
- name: Assert flows are removed
|
||||
assert:
|
||||
that:
|
||||
- desire_client_with_flow_binding_overrides is changed
|
||||
- "'authenticationFlowBindingOverrides' in desire_client_with_flow_binding_overrides.end_state"
|
||||
- "'browser' not in desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides"
|
||||
- "'direct_grant' not in desire_client_with_flow_binding_overrides.end_state.authenticationFlowBindingOverrides"
|
Loading…
Reference in a new issue