keycloak_group: support keycloak subgroups (#5814)

* feat(module/keycloak_group): add support for ...

... handling subgroups

* added changelog fragment and fixing sanity ...

... test issues

* more sanity fixes

* fix missing version and review issues

* added missing licence header

* fix docu

* fix line beeing too long

* replaced suboptimal string type prefixing ...

... with better subdict based approach

* fix sanity issues

* more sanity fixing

* fixed more review issues

* fix argument list too long

* why is it failing? something wrong with the docu?

* is it this line then?

* undid group attribute removing, it does not ...

... belong into this PR

* fix version_added for parents parameter

---------

Co-authored-by: Mirko Wilhelmi <Mirko.Wilhelmi@sma.de>
This commit is contained in:
morco 2023-02-25 11:12:35 +01:00 committed by GitHub
parent 1877ef1510
commit 7d3e6d1bb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 796 additions and 9 deletions

View file

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

View file

@ -0,0 +1,27 @@
// 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
To be able to run these integration tests a keycloak server must be
reachable under a specific url with a specific admin user and password.
The exact values expected for these parameters can be found in
'vars/main.yml' file. A simple way to do this is to use the official
keycloak docker images like this:
----
docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=<url-path> -e KEYCLOAK_ADMIN=<admin_user> -e KEYCLOAK_ADMIN_PASSWORD=<admin_password> quay.io/keycloak/keycloak:20.0.2 start-dev
----
Example with concrete values inserted:
----
docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=/auth -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:20.0.2 start-dev
----
This test suite can run against a fresh unconfigured server instance
(no preconfiguration required) and cleans up after itself (undoes all
its config changes) as long as it runs through completly. While its active
it changes the server configuration in the following ways:
* creating, modifying and deleting some keycloak groups

View file

@ -0,0 +1,501 @@
---
# 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: Create a keycloak group
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: test-group
state: present
register: result
- name: Assert group was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "test-group"
- result.end_state.path == "/test-group"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- set_fact:
test_group_id: "{{ result.end_state.id }}"
- name: Group creation rerun (test for idempotency)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: test-group
state: present
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state != {}
- result.end_state.name == "test-group"
- result.end_state.path == "/test-group"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: Update the name of a keycloak group
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ test_group_id }}"
name: new-test-group
state: present
register: result
- name: Assert that group name was updated
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "new-test-group"
- result.end_state.path == "/new-test-group"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: Delete a keycloak group by id
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ test_group_id }}"
state: absent
register: result
- name: Assert that group was deleted
assert:
that:
- result is changed
- result.end_state == {}
- name: Redo group deletion (check for idempotency)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ test_group_id }}"
state: absent
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state == {}
- name: Create a keycloak group with some custom attributes
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: my-new_group
attributes:
attrib1: value1
attrib2: value2
attrib3:
- item1
- item2
register: result
- name: Assert that group was correctly created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "my-new_group"
- result.end_state.path == "/my-new_group"
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- result.end_state.attributes != {}
- result.end_state.attributes.attrib1 == ["value1"]
- result.end_state.attributes.attrib2 == ["value2"]
- result.end_state.attributes.attrib3 == ["item1", "item2"]
- name: Delete a keycloak group based on name
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: my-new_group
state: absent
register: result
- name: Assert that group was deleted
assert:
that:
- result is changed
- result.end_state == {}
## subgroup tests
## we already testet this so no asserts for this
- name: Create a new base group for subgroup testing (test setup)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: rootgrp
register: subgrp_basegrp_result
- name: Create a subgroup using parent id
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subgrp1
parents:
- id: "{{ subgrp_basegrp_result.end_state.id }}"
register: result
- name: Assert that subgroup was correctly created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "subgrp1"
- result.end_state.path == "/rootgrp/subgrp1"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: Recreate a subgroup using parent id (test idempotency)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subgrp1
parents:
- id: "{{ subgrp_basegrp_result.end_state.id }}"
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state != {}
- result.end_state.name == "subgrp1"
- result.end_state.path == "/rootgrp/subgrp1"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: Changing name of existing group
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ result.end_state.id }}"
name: new-subgrp1
parents:
- id: "{{ subgrp_basegrp_result.end_state.id }}"
register: result
- name: Assert that subgroup name has changed correctly
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "new-subgrp1"
- result.end_state.path == "/rootgrp/new-subgrp1"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: Create a subgroup using parent name
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subgrp2
parents:
- name: rootgrp
register: result
- name: Assert that subgroup was correctly created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "subgrp2"
- result.end_state.path == "/rootgrp/subgrp2"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: Recreate a subgroup using parent name (test idempotency)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subgrp2
parents:
- name: rootgrp
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state != {}
- result.end_state.name == "subgrp2"
- result.end_state.path == "/rootgrp/subgrp2"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
## subgroup of subgroup tests
- name: Create a subgroup of a subgroup using parent names (complete parent chain)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subsubgrp
parents:
- name: rootgrp
- name: subgrp2
register: result
- name: Assert subgroup of subgroup was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "subsubgrp"
- result.end_state.path == "/rootgrp/subgrp2/subsubgrp"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: ReCreate a subgroup of a subgroup using parent names (test idempotency)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subsubgrp
parents:
- name: rootgrp
- name: subgrp2
register: result_subsubgrp
- name: Assert that nothing has changed
assert:
that:
- result_subsubgrp is not changed
- result_subsubgrp.end_state != {}
- result_subsubgrp.end_state.name == "subsubgrp"
- result_subsubgrp.end_state.path == "/rootgrp/subgrp2/subsubgrp"
- result_subsubgrp.end_state.attributes == {}
- result_subsubgrp.end_state.clientRoles == {}
- result_subsubgrp.end_state.realmRoles == []
- result_subsubgrp.end_state.subGroups == []
- name: Create a subgroup of a subgroup using direct parent id (incomplete parent chain)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subsubsubgrp
parents:
- id: "{{ result_subsubgrp.end_state.id }}"
register: result
- name: Assert subgroup of subgroup was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "subsubsubgrp"
- result.end_state.path == "/rootgrp/subgrp2/subsubgrp/subsubsubgrp"
- result.end_state.attributes == {}
- result.end_state.clientRoles == {}
- result.end_state.realmRoles == []
- result.end_state.subGroups == []
- name: ReCreate a subgroup of a subgroup using direct parent id (test idempotency)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: subsubsubgrp
parents:
- id: "{{ result_subsubgrp.end_state.id }}"
register: result_subsubsubgrp
- name: Assert that nothing changed
assert:
that:
- result_subsubsubgrp is not changed
- result_subsubsubgrp.end_state != {}
- result_subsubsubgrp.end_state.name == "subsubsubgrp"
- result_subsubsubgrp.end_state.path == "/rootgrp/subgrp2/subsubgrp/subsubsubgrp"
- result_subsubsubgrp.end_state.attributes == {}
- result_subsubsubgrp.end_state.clientRoles == {}
- result_subsubsubgrp.end_state.realmRoles == []
- result_subsubsubgrp.end_state.subGroups == []
## subgroup deletion tests
## note: in principle we already have tested group deletion in general
## enough already, but what makes it interesting here again is to
## see it works also properly for subgroups and groups with subgroups
- name: Deleting a subgroup by id (no parents needed)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ result_subsubsubgrp.end_state.id }}"
state: absent
register: result
- name: Assert that subgroup was deleted
assert:
that:
- result is changed
- result.end_state == {}
- name: Redo subgroup deletion (idempotency test)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ result_subsubsubgrp.end_state.id }}"
state: absent
register: result
- name: Assert that nothing changed
assert:
that:
- result is not changed
- result.end_state == {}
- name: Deleting a subgroup by name
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: new-subgrp1
parents:
- name: rootgrp
state: absent
register: result
- name: Assert that subgroup was deleted
assert:
that:
- result is changed
- result.end_state == {}
- name: Redo deleting a subgroup by name (idempotency test)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: new-subgrp1
parents:
- name: rootgrp
state: absent
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state == {}
- name: Delete keycloak group which has subgroups
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: rootgrp
state: absent
register: result
- name: Assert that group was deleted
assert:
that:
- result is changed
- result.end_state == {}
- name: Redo delete keycloak group which has subgroups (idempotency test)
community.general.keycloak_group:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
name: rootgrp
state: absent
register: result
- name: Assert that group was deleted
assert:
that:
- result is not changed
- result.end_state == {}

View 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
url: http://localhost:8080/auth
admin_realm: master
admin_user: admin
admin_password: password
realm: master