mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-28 21:31:26 -07:00
Fix Keycloak authentication flow configuration issues (#9987)
* Add delete_authentication_config method and integrate it into create_or_update_executions * typo * Sanity * Add integration tests for keycloak_authentication module with README, tasks, and variables * Add copyright and license information to access_token.yml * Sanity * Refactor Keycloak integration tests: streamline README, update access token task, and enhance variable management * Maj changelogs fragments --------- Co-authored-by: Andre Desrosiers <andre.desrosiers@ssss.gouv.qc.ca>
This commit is contained in:
parent
80252b29f8
commit
a8b977320c
8 changed files with 262 additions and 0 deletions
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- keycloak_authentication - fix authentification config duplication for Keycloak < 26.2.0 (https://github.com/ansible-collections/community.general/pull/9987).
|
|
@ -2224,6 +2224,23 @@ class KeycloakAPI(object):
|
|||
except Exception as e:
|
||||
self.fail_request(e, msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
|
||||
|
||||
def delete_authentication_config(self, configId, realm='master'):
|
||||
""" Delete authenticator config
|
||||
|
||||
:param configId: id of authentication config
|
||||
:param realm: realm of authentication config to be deleted
|
||||
"""
|
||||
try:
|
||||
# Send a DELETE request to remove the specified authentication config from the Keycloak server.
|
||||
self._request(
|
||||
URL_AUTHENTICATION_CONFIG.format(
|
||||
url=self.baseurl,
|
||||
realm=realm,
|
||||
id=configId),
|
||||
method='DELETE')
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg="Unable to delete authentication config %s: %s" % (configId, str(e)))
|
||||
|
||||
def create_subflow(self, subflowName, flowAlias, realm='master', flowType='basic-flow'):
|
||||
""" Create new sublow on the flow
|
||||
|
||||
|
|
|
@ -308,6 +308,8 @@ def create_or_update_executions(kc, config, realm='master'):
|
|||
}
|
||||
# add the execution configuration
|
||||
if new_exec["authenticationConfig"] is not None:
|
||||
if "authenticationConfig" in execution and "id" in execution["authenticationConfig"]:
|
||||
kc.delete_authentication_config(execution["authenticationConfig"]["id"], realm=realm)
|
||||
kc.add_authenticationConfig_to_execution(updated_exec["id"], new_exec["authenticationConfig"], realm=realm)
|
||||
for key in new_exec:
|
||||
# remove unwanted key for the next API call
|
||||
|
|
10
tests/integration/targets/keycloak_authentication/README.md
Normal file
10
tests/integration/targets/keycloak_authentication/README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!--
|
||||
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_authentication module integration test
|
||||
|
||||
Run integration tests:
|
||||
|
||||
ansible-test integration -v keycloak_authentication --allow-unsupported --docker fedora35 --docker-network host
|
|
@ -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
|
|
@ -0,0 +1,25 @@
|
|||
# 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
|
||||
---
|
||||
- name: Get access token
|
||||
ansible.builtin.uri:
|
||||
url: "{{ url }}/realms/{{ admin_realm }}/protocol/openid-connect/token"
|
||||
method: POST
|
||||
status_code: 200
|
||||
headers:
|
||||
Accept: application/json
|
||||
User-agent: Ansible
|
||||
body_format: form-urlencoded
|
||||
body:
|
||||
grant_type: "password"
|
||||
client_id: "admin-cli"
|
||||
username: "{{ admin_user }}"
|
||||
password: "{{ admin_password }}"
|
||||
register: token_response
|
||||
no_log: true
|
||||
|
||||
- name: Extract access token
|
||||
ansible.builtin.set_fact:
|
||||
access_token: "{{ token_response.json['access_token'] }}"
|
||||
no_log: true
|
185
tests/integration/targets/keycloak_authentication/tasks/main.yml
Normal file
185
tests/integration/targets/keycloak_authentication/tasks/main.yml
Normal file
|
@ -0,0 +1,185 @@
|
|||
---
|
||||
# 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
|
||||
- name: Install required packages
|
||||
pip:
|
||||
name:
|
||||
- jmespath
|
||||
- requests
|
||||
register: result
|
||||
until: result is success
|
||||
|
||||
- name: Start container
|
||||
community.docker.docker_container:
|
||||
name: mykeycloak
|
||||
image: "quay.io/keycloak/keycloak:{{ keycloak_version }}"
|
||||
command: start-dev
|
||||
env:
|
||||
KC_HTTP_RELATIVE_PATH: /auth
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: password
|
||||
ports:
|
||||
- "{{ keycloak_port }}:8080"
|
||||
detach: true
|
||||
auto_remove: true
|
||||
memory: 2200M
|
||||
|
||||
- name: Wait for Keycloak
|
||||
uri:
|
||||
url: "{{ url }}/admin/"
|
||||
status_code: 200
|
||||
validate_certs: no
|
||||
register: result
|
||||
until: result.status == 200
|
||||
retries: 10
|
||||
delay: 10
|
||||
|
||||
- name: Delete realm if exists
|
||||
community.general.keycloak_realm:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
state: absent
|
||||
|
||||
- name: Create realm
|
||||
community.general.keycloak_realm:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
id: "{{ realm }}"
|
||||
realm: "{{ realm }}"
|
||||
state: present
|
||||
|
||||
- name: Create an authentication flow from first broker login and add an execution to it.
|
||||
community.general.keycloak_authentication:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
alias: "Test first broker login"
|
||||
copyFrom: "first broker login"
|
||||
authenticationExecutions:
|
||||
- providerId: "idp-review-profile"
|
||||
requirement: "REQUIRED"
|
||||
authenticationConfig:
|
||||
alias: "Test review profile config"
|
||||
config:
|
||||
update.profile.on.first.login: "missing"
|
||||
|
||||
- name: Create auth flow
|
||||
community.general.keycloak_authentication:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
alias: "My conditionnal browser otp"
|
||||
description: "browser based authentication with otp"
|
||||
providerId: "basic-flow"
|
||||
authenticationExecutions:
|
||||
- displayName: Cookie
|
||||
providerId: auth-cookie
|
||||
requirement: ALTERNATIVE
|
||||
- displayName: Kerberos
|
||||
providerId: auth-spnego
|
||||
requirement: DISABLED
|
||||
- displayName: Identity Provider Redirector
|
||||
providerId: identity-provider-redirector
|
||||
requirement: ALTERNATIVE
|
||||
- displayName: My browser otp forms
|
||||
requirement: ALTERNATIVE
|
||||
- displayName: Username Password Form
|
||||
flowAlias: My browser otp forms
|
||||
providerId: auth-username-password-form
|
||||
requirement: REQUIRED
|
||||
- displayName: My browser otp Browser - Conditional OTP
|
||||
flowAlias: My browser otp forms
|
||||
requirement: REQUIRED
|
||||
providerId: "auth-conditional-otp-form"
|
||||
authenticationConfig:
|
||||
alias: my-conditional-otp-config
|
||||
config:
|
||||
defaultOtpOutcome: "force"
|
||||
noOtpRequiredForHeaderPattern: "{{ keycloak_no_otp_required_pattern_orinale }}"
|
||||
state: present
|
||||
|
||||
- name: Modified auth flow with new config
|
||||
community.general.keycloak_authentication:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
alias: "My conditionnal browser otp"
|
||||
description: "browser based authentication with otp"
|
||||
providerId: "basic-flow"
|
||||
authenticationExecutions:
|
||||
- displayName: Cookie
|
||||
providerId: auth-cookie
|
||||
requirement: ALTERNATIVE
|
||||
- displayName: Kerberos
|
||||
providerId: auth-spnego
|
||||
requirement: DISABLED
|
||||
- displayName: Identity Provider Redirector
|
||||
providerId: identity-provider-redirector
|
||||
requirement: ALTERNATIVE
|
||||
- displayName: My browser otp forms
|
||||
requirement: ALTERNATIVE
|
||||
- displayName: Username Password Form
|
||||
flowAlias: My browser otp forms
|
||||
providerId: auth-username-password-form
|
||||
requirement: REQUIRED
|
||||
- displayName: My browser otp Browser - Conditional OTP
|
||||
flowAlias: My browser otp forms
|
||||
requirement: REQUIRED
|
||||
providerId: "auth-conditional-otp-form"
|
||||
authenticationConfig:
|
||||
alias: my-conditional-otp-config
|
||||
config:
|
||||
defaultOtpOutcome: "force"
|
||||
noOtpRequiredForHeaderPattern: "{{ keycloak_no_otp_required_pattern_modifed }}"
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Retrive access
|
||||
ansible.builtin.include_tasks:
|
||||
file: access_token.yml
|
||||
|
||||
- name: Export realm
|
||||
ansible.builtin.uri:
|
||||
url: "{{ url }}/admin/realms/{{ realm }}/partial-export?exportClients=false&exportGroupsAndRoles=false"
|
||||
method: POST
|
||||
headers:
|
||||
Accept: application/json
|
||||
User-agent: Ansible
|
||||
Authorization: "Bearer {{ access_token }}"
|
||||
body_format: form-urlencoded
|
||||
body: {}
|
||||
register: exported_realm
|
||||
no_log: true
|
||||
|
||||
- name: Assert `my-conditional-otp-config` exists only once
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- exported_realm.json | community.general.json_query('authenticatorConfig[?alias==`my-conditional-otp-config`]') | length == 1
|
||||
|
||||
- name: Delete auth flow
|
||||
community.general.keycloak_authentication:
|
||||
auth_keycloak_url: "{{ url }}"
|
||||
auth_realm: "{{ admin_realm }}"
|
||||
auth_username: "{{ admin_user }}"
|
||||
auth_password: "{{ admin_password }}"
|
||||
realm: "{{ realm }}"
|
||||
alias: "My conditionnal browser otp"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Remove container
|
||||
community.docker.docker_container:
|
||||
name: mykeycloak
|
||||
state: absent
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
# 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
|
||||
keycloak_version: latest
|
||||
keycloak_port: 8080
|
||||
|
||||
url: "http://localhost:{{ keycloak_port }}/auth"
|
||||
admin_realm: master
|
||||
admin_user: admin
|
||||
admin_password: password
|
||||
realm: myrealm
|
||||
|
||||
|
||||
keycloak_no_otp_required_pattern_orinale: "X-Forwarded-For: 10\\.[0-9\\.:]+"
|
||||
keycloak_no_otp_required_pattern_modifed: "X-Original-Forwarded-For: 10\\.[0-9\\.:]+"
|
Loading…
Add table
Add a link
Reference in a new issue