mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
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:
parent
1877ef1510
commit
7d3e6d1bb7
7 changed files with 796 additions and 9 deletions
2
changelogs/fragments/5814-support-keycloak-subgroups.yml
Normal file
2
changelogs/fragments/5814-support-keycloak-subgroups.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- keycloak_group - add new optional module parameter ``parents`` to properly handle keycloak subgroups (https://github.com/ansible-collections/community.general/pull/5814).
|
|
@ -42,6 +42,7 @@ URL_CLIENTTEMPLATE = "{url}/admin/realms/{realm}/client-templates/{id}"
|
||||||
URL_CLIENTTEMPLATES = "{url}/admin/realms/{realm}/client-templates"
|
URL_CLIENTTEMPLATES = "{url}/admin/realms/{realm}/client-templates"
|
||||||
URL_GROUPS = "{url}/admin/realms/{realm}/groups"
|
URL_GROUPS = "{url}/admin/realms/{realm}/groups"
|
||||||
URL_GROUP = "{url}/admin/realms/{realm}/groups/{groupid}"
|
URL_GROUP = "{url}/admin/realms/{realm}/groups/{groupid}"
|
||||||
|
URL_GROUP_CHILDREN = "{url}/admin/realms/{realm}/groups/{groupid}/children"
|
||||||
|
|
||||||
URL_CLIENTSCOPES = "{url}/admin/realms/{realm}/client-scopes"
|
URL_CLIENTSCOPES = "{url}/admin/realms/{realm}/client-scopes"
|
||||||
URL_CLIENTSCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}"
|
URL_CLIENTSCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}"
|
||||||
|
@ -1249,7 +1250,7 @@ class KeycloakAPI(object):
|
||||||
self.module.fail_json(msg="Could not fetch group %s in realm %s: %s"
|
self.module.fail_json(msg="Could not fetch group %s in realm %s: %s"
|
||||||
% (gid, realm, str(e)))
|
% (gid, realm, str(e)))
|
||||||
|
|
||||||
def get_group_by_name(self, name, realm="master"):
|
def get_group_by_name(self, name, realm="master", parents=None):
|
||||||
""" Fetch a keycloak group within a realm based on its name.
|
""" Fetch a keycloak group within a realm based on its name.
|
||||||
|
|
||||||
The Keycloak API does not allow filtering of the Groups resource by name.
|
The Keycloak API does not allow filtering of the Groups resource by name.
|
||||||
|
@ -1259,9 +1260,18 @@ class KeycloakAPI(object):
|
||||||
If the group does not exist, None is returned.
|
If the group does not exist, None is returned.
|
||||||
:param name: Name of the group to fetch.
|
:param name: Name of the group to fetch.
|
||||||
:param realm: Realm in which the group resides; default 'master'
|
:param realm: Realm in which the group resides; default 'master'
|
||||||
|
:param parents: Optional list of parents when group to look for is a subgroup
|
||||||
"""
|
"""
|
||||||
groups_url = URL_GROUPS.format(url=self.baseurl, realm=realm)
|
groups_url = URL_GROUPS.format(url=self.baseurl, realm=realm)
|
||||||
try:
|
try:
|
||||||
|
if parents:
|
||||||
|
parent = self.get_subgroup_direct_parent(parents, realm)
|
||||||
|
|
||||||
|
if not parent:
|
||||||
|
return None
|
||||||
|
|
||||||
|
all_groups = parent['subGroups']
|
||||||
|
else:
|
||||||
all_groups = self.get_groups(realm=realm)
|
all_groups = self.get_groups(realm=realm)
|
||||||
|
|
||||||
for group in all_groups:
|
for group in all_groups:
|
||||||
|
@ -1274,6 +1284,102 @@ class KeycloakAPI(object):
|
||||||
self.module.fail_json(msg="Could not fetch group %s in realm %s: %s"
|
self.module.fail_json(msg="Could not fetch group %s in realm %s: %s"
|
||||||
% (name, realm, str(e)))
|
% (name, realm, str(e)))
|
||||||
|
|
||||||
|
def _get_normed_group_parent(self, parent):
|
||||||
|
""" Converts parent dict information into a more easy to use form.
|
||||||
|
|
||||||
|
:param parent: parent describing dict
|
||||||
|
"""
|
||||||
|
if parent['id']:
|
||||||
|
return (parent['id'], True)
|
||||||
|
|
||||||
|
return (parent['name'], False)
|
||||||
|
|
||||||
|
def get_subgroup_by_chain(self, name_chain, realm="master"):
|
||||||
|
""" Access a subgroup API object by walking down a given name/id chain.
|
||||||
|
|
||||||
|
Groups can be given either as by name or by ID, the first element
|
||||||
|
must either be a toplvl group or given as ID, all parents must exist.
|
||||||
|
|
||||||
|
If the group cannot be found, None is returned.
|
||||||
|
:param name_chain: Topdown ordered list of subgroup parent (ids or names) + its own name at the end
|
||||||
|
:param realm: Realm in which the group resides; default 'master'
|
||||||
|
"""
|
||||||
|
cp = name_chain[0]
|
||||||
|
|
||||||
|
# for 1st parent in chain we must query the server
|
||||||
|
cp, is_id = self._get_normed_group_parent(cp)
|
||||||
|
|
||||||
|
if is_id:
|
||||||
|
tmp = self.get_group_by_groupid(cp, realm=realm)
|
||||||
|
else:
|
||||||
|
# given as name, assume toplvl group
|
||||||
|
tmp = self.get_group_by_name(cp, realm=realm)
|
||||||
|
|
||||||
|
if not tmp:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for p in name_chain[1:]:
|
||||||
|
for sg in tmp['subGroups']:
|
||||||
|
pv, is_id = self._get_normed_group_parent(p)
|
||||||
|
|
||||||
|
if is_id:
|
||||||
|
cmpkey = "id"
|
||||||
|
else:
|
||||||
|
cmpkey = "name"
|
||||||
|
|
||||||
|
if pv == sg[cmpkey]:
|
||||||
|
tmp = sg
|
||||||
|
break
|
||||||
|
|
||||||
|
if not tmp:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
def get_subgroup_direct_parent(self, parents, realm="master", children_to_resolve=None):
|
||||||
|
""" Get keycloak direct parent group API object for a given chain of parents.
|
||||||
|
|
||||||
|
To succesfully work the API for subgroups we actually dont need
|
||||||
|
to "walk the whole tree" for nested groups but only need to know
|
||||||
|
the ID for the direct predecessor of current subgroup. This
|
||||||
|
method will guarantee us this information getting there with
|
||||||
|
as minimal work as possible.
|
||||||
|
|
||||||
|
Note that given parent list can and might be incomplete at the
|
||||||
|
upper levels as long as it starts with an ID instead of a name
|
||||||
|
|
||||||
|
If the group does not exist, None is returned.
|
||||||
|
:param parents: Topdown ordered list of subgroup parents
|
||||||
|
:param realm: Realm in which the group resides; default 'master'
|
||||||
|
"""
|
||||||
|
if children_to_resolve is None:
|
||||||
|
# start recursion by reversing parents (in optimal cases
|
||||||
|
# we dont need to walk the whole tree upwarts)
|
||||||
|
parents = list(reversed(parents))
|
||||||
|
children_to_resolve = []
|
||||||
|
|
||||||
|
if not parents:
|
||||||
|
# walk complete parents list to the top, all names, no id's,
|
||||||
|
# try to resolve it assuming list is complete and 1st
|
||||||
|
# element is a toplvl group
|
||||||
|
return self.get_subgroup_by_chain(list(reversed(children_to_resolve)), realm=realm)
|
||||||
|
|
||||||
|
cp = parents[0]
|
||||||
|
unused, is_id = self._get_normed_group_parent(cp)
|
||||||
|
|
||||||
|
if is_id:
|
||||||
|
# current parent is given as ID, we can stop walking
|
||||||
|
# upwards searching for an entry point
|
||||||
|
return self.get_subgroup_by_chain([cp] + list(reversed(children_to_resolve)), realm=realm)
|
||||||
|
else:
|
||||||
|
# current parent is given as name, it must be resolved
|
||||||
|
# later, try next parent (recurse)
|
||||||
|
children_to_resolve.append(cp)
|
||||||
|
return self.get_subgroup_direct_parent(
|
||||||
|
parents[1:],
|
||||||
|
realm=realm, children_to_resolve=children_to_resolve
|
||||||
|
)
|
||||||
|
|
||||||
def create_group(self, grouprep, realm="master"):
|
def create_group(self, grouprep, realm="master"):
|
||||||
""" Create a Keycloak group.
|
""" Create a Keycloak group.
|
||||||
|
|
||||||
|
@ -1288,6 +1394,34 @@ class KeycloakAPI(object):
|
||||||
self.module.fail_json(msg="Could not create group %s in realm %s: %s"
|
self.module.fail_json(msg="Could not create group %s in realm %s: %s"
|
||||||
% (grouprep['name'], realm, str(e)))
|
% (grouprep['name'], realm, str(e)))
|
||||||
|
|
||||||
|
def create_subgroup(self, parents, grouprep, realm="master"):
|
||||||
|
""" Create a Keycloak subgroup.
|
||||||
|
|
||||||
|
:param parents: list of one or more parent groups
|
||||||
|
:param grouprep: a GroupRepresentation of the group to be created. Must contain at minimum the field name.
|
||||||
|
:return: HTTPResponse object on success
|
||||||
|
"""
|
||||||
|
parent_id = "---UNDETERMINED---"
|
||||||
|
try:
|
||||||
|
parent_id = self.get_subgroup_direct_parent(parents, realm)
|
||||||
|
|
||||||
|
if not parent_id:
|
||||||
|
raise Exception(
|
||||||
|
"Could not determine subgroup parent ID for given"
|
||||||
|
" parent chain {0}. Assure that all parents exist"
|
||||||
|
" already and the list is complete and properly"
|
||||||
|
" ordered, starts with an ID or starts at the"
|
||||||
|
" top level".format(parents)
|
||||||
|
)
|
||||||
|
|
||||||
|
parent_id = parent_id["id"]
|
||||||
|
url = URL_GROUP_CHILDREN.format(url=self.baseurl, realm=realm, groupid=parent_id)
|
||||||
|
return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
|
||||||
|
data=json.dumps(grouprep), validate_certs=self.validate_certs)
|
||||||
|
except Exception as e:
|
||||||
|
self.module.fail_json(msg="Could not create subgroup %s for parent group %s in realm %s: %s"
|
||||||
|
% (grouprep['name'], parent_id, realm, str(e)))
|
||||||
|
|
||||||
def update_group(self, grouprep, realm="master"):
|
def update_group(self, grouprep, realm="master"):
|
||||||
""" Update an existing group.
|
""" Update an existing group.
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ description:
|
||||||
to your needs and a user having the expected roles.
|
to your needs and a user having the expected roles.
|
||||||
|
|
||||||
- The names of module options are snake_cased versions of the camelCase ones found in the
|
- The names of module options are snake_cased versions of the camelCase ones found in the
|
||||||
Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/8.0/rest-api/index.html).
|
Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/20.0.2/rest-api/index.html).
|
||||||
|
|
||||||
- Attributes are multi-valued in the Keycloak API. All attributes are lists of individual values and will
|
- Attributes are multi-valued in the Keycloak API. All attributes are lists of individual values and will
|
||||||
be returned that way by this module. You may pass single values for attributes when calling the module,
|
be returned that way by this module. You may pass single values for attributes when calling the module,
|
||||||
|
@ -42,7 +42,9 @@ options:
|
||||||
description:
|
description:
|
||||||
- State of the group.
|
- State of the group.
|
||||||
- On C(present), the group will be created if it does not yet exist, or updated with the parameters you provide.
|
- On C(present), the group will be created if it does not yet exist, or updated with the parameters you provide.
|
||||||
- On C(absent), the group will be removed if it exists.
|
- >-
|
||||||
|
On C(absent), the group will be removed if it exists. Be aware that absenting
|
||||||
|
a group with subgroups will automatically delete all its subgroups too.
|
||||||
default: 'present'
|
default: 'present'
|
||||||
type: str
|
type: str
|
||||||
choices:
|
choices:
|
||||||
|
@ -74,6 +76,38 @@ options:
|
||||||
- A dict of key/value pairs to set as custom attributes for the group.
|
- A dict of key/value pairs to set as custom attributes for the group.
|
||||||
- Values may be single values (e.g. a string) or a list of strings.
|
- Values may be single values (e.g. a string) or a list of strings.
|
||||||
|
|
||||||
|
parents:
|
||||||
|
version_added: "6.4.0"
|
||||||
|
type: list
|
||||||
|
description:
|
||||||
|
- List of parent groups for the group to handle sorted top to bottom.
|
||||||
|
- >-
|
||||||
|
Set this to create a group as a subgroup of another group or groups (parents) or
|
||||||
|
when accessing an existing subgroup by name.
|
||||||
|
- >-
|
||||||
|
Not necessary to set when accessing an existing subgroup by its C(ID) because in
|
||||||
|
that case the group can be directly queried without necessarily knowing its parent(s).
|
||||||
|
elements: dict
|
||||||
|
suboptions:
|
||||||
|
id:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Identify parent by ID.
|
||||||
|
- Needs less API calls than using I(name).
|
||||||
|
- A deep parent chain can be started at any point when first given parent is given as ID.
|
||||||
|
- Note that in principle both ID and name can be specified at the same time
|
||||||
|
but current implementation only always use just one of them, with ID
|
||||||
|
being preferred.
|
||||||
|
name:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Identify parent by name.
|
||||||
|
- Needs more internal API calls than using I(id) to map names to ID's under the hood.
|
||||||
|
- When giving a parent chain with only names it must be complete up to the top.
|
||||||
|
- Note that in principle both ID and name can be specified at the same time
|
||||||
|
but current implementation only always use just one of them, with ID
|
||||||
|
being preferred.
|
||||||
|
|
||||||
notes:
|
notes:
|
||||||
- Presently, the I(realmRoles), I(clientRoles) and I(access) attributes returned by the Keycloak API
|
- Presently, the I(realmRoles), I(clientRoles) and I(access) attributes returned by the Keycloak API
|
||||||
are read-only for groups. This limitation will be removed in a later version of this module.
|
are read-only for groups. This limitation will be removed in a later version of this module.
|
||||||
|
@ -97,6 +131,7 @@ EXAMPLES = '''
|
||||||
auth_realm: master
|
auth_realm: master
|
||||||
auth_username: USERNAME
|
auth_username: USERNAME
|
||||||
auth_password: PASSWORD
|
auth_password: PASSWORD
|
||||||
|
register: result_new_kcgrp
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
|
||||||
- name: Create a Keycloak group, authentication with token
|
- name: Create a Keycloak group, authentication with token
|
||||||
|
@ -162,6 +197,64 @@ EXAMPLES = '''
|
||||||
- list
|
- list
|
||||||
- items
|
- items
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Create a Keycloak subgroup of a base group (using parent name)
|
||||||
|
community.general.keycloak_group:
|
||||||
|
name: my-new-kc-group-sub
|
||||||
|
realm: MyCustomRealm
|
||||||
|
state: present
|
||||||
|
auth_client_id: admin-cli
|
||||||
|
auth_keycloak_url: https://auth.example.com/auth
|
||||||
|
auth_realm: master
|
||||||
|
auth_username: USERNAME
|
||||||
|
auth_password: PASSWORD
|
||||||
|
parents:
|
||||||
|
- name: my-new-kc-group
|
||||||
|
register: result_new_kcgrp_sub
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Create a Keycloak subgroup of a base group (using parent id)
|
||||||
|
community.general.keycloak_group:
|
||||||
|
name: my-new-kc-group-sub2
|
||||||
|
realm: MyCustomRealm
|
||||||
|
state: present
|
||||||
|
auth_client_id: admin-cli
|
||||||
|
auth_keycloak_url: https://auth.example.com/auth
|
||||||
|
auth_realm: master
|
||||||
|
auth_username: USERNAME
|
||||||
|
auth_password: PASSWORD
|
||||||
|
parents:
|
||||||
|
- id: "{{ result_new_kcgrp.end_state.id }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Create a Keycloak subgroup of a subgroup (using parent names)
|
||||||
|
community.general.keycloak_group:
|
||||||
|
name: my-new-kc-group-sub-sub
|
||||||
|
realm: MyCustomRealm
|
||||||
|
state: present
|
||||||
|
auth_client_id: admin-cli
|
||||||
|
auth_keycloak_url: https://auth.example.com/auth
|
||||||
|
auth_realm: master
|
||||||
|
auth_username: USERNAME
|
||||||
|
auth_password: PASSWORD
|
||||||
|
parents:
|
||||||
|
- name: my-new-kc-group
|
||||||
|
- name: my-new-kc-group-sub
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Create a Keycloak subgroup of a subgroup (using direct parent id)
|
||||||
|
community.general.keycloak_group:
|
||||||
|
name: my-new-kc-group-sub-sub
|
||||||
|
realm: MyCustomRealm
|
||||||
|
state: present
|
||||||
|
auth_client_id: admin-cli
|
||||||
|
auth_keycloak_url: https://auth.example.com/auth
|
||||||
|
auth_realm: master
|
||||||
|
auth_username: USERNAME
|
||||||
|
auth_password: PASSWORD
|
||||||
|
parents:
|
||||||
|
- id: "{{ result_new_kcgrp_sub.end_state.id }}"
|
||||||
|
delegate_to: localhost
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = '''
|
RETURN = '''
|
||||||
|
@ -240,6 +333,13 @@ def main():
|
||||||
id=dict(type='str'),
|
id=dict(type='str'),
|
||||||
name=dict(type='str'),
|
name=dict(type='str'),
|
||||||
attributes=dict(type='dict'),
|
attributes=dict(type='dict'),
|
||||||
|
parents=dict(
|
||||||
|
type='list', elements='dict',
|
||||||
|
options=dict(
|
||||||
|
id=dict(type='str'),
|
||||||
|
name=dict(type='str')
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
argument_spec.update(meta_args)
|
argument_spec.update(meta_args)
|
||||||
|
@ -266,6 +366,8 @@ def main():
|
||||||
name = module.params.get('name')
|
name = module.params.get('name')
|
||||||
attributes = module.params.get('attributes')
|
attributes = module.params.get('attributes')
|
||||||
|
|
||||||
|
parents = module.params.get('parents')
|
||||||
|
|
||||||
# attributes in Keycloak have their values returned as lists
|
# attributes in Keycloak have their values returned as lists
|
||||||
# via the API. attributes is a dict, so we'll transparently convert
|
# via the API. attributes is a dict, so we'll transparently convert
|
||||||
# the values to lists.
|
# the values to lists.
|
||||||
|
@ -275,12 +377,12 @@ def main():
|
||||||
|
|
||||||
# Filter and map the parameters names that apply to the group
|
# Filter and map the parameters names that apply to the group
|
||||||
group_params = [x for x in module.params
|
group_params = [x for x in module.params
|
||||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] and
|
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'parents'] and
|
||||||
module.params.get(x) is not None]
|
module.params.get(x) is not None]
|
||||||
|
|
||||||
# See if it already exists in Keycloak
|
# See if it already exists in Keycloak
|
||||||
if gid is None:
|
if gid is None:
|
||||||
before_group = kc.get_group_by_name(name, realm=realm)
|
before_group = kc.get_group_by_name(name, realm=realm, parents=parents)
|
||||||
else:
|
else:
|
||||||
before_group = kc.get_group_by_groupid(gid, realm=realm)
|
before_group = kc.get_group_by_groupid(gid, realm=realm)
|
||||||
|
|
||||||
|
@ -323,9 +425,15 @@ def main():
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|
||||||
# create it
|
# create it ...
|
||||||
|
if parents:
|
||||||
|
# ... as subgroup of another parent group
|
||||||
|
kc.create_subgroup(parents, desired_group, realm=realm)
|
||||||
|
else:
|
||||||
|
# ... as toplvl base group
|
||||||
kc.create_group(desired_group, realm=realm)
|
kc.create_group(desired_group, realm=realm)
|
||||||
after_group = kc.get_group_by_name(name, realm)
|
|
||||||
|
after_group = kc.get_group_by_name(name, realm, parents=parents)
|
||||||
|
|
||||||
result['end_state'] = after_group
|
result['end_state'] = after_group
|
||||||
|
|
||||||
|
|
5
tests/integration/targets/keycloak_group/aliases
Normal file
5
tests/integration/targets/keycloak_group/aliases
Normal 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
|
27
tests/integration/targets/keycloak_group/readme.adoc
Normal file
27
tests/integration/targets/keycloak_group/readme.adoc
Normal 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
|
||||||
|
|
501
tests/integration/targets/keycloak_group/tasks/main.yml
Normal file
501
tests/integration/targets/keycloak_group/tasks/main.yml
Normal 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 == {}
|
10
tests/integration/targets/keycloak_group/vars/main.yml
Normal file
10
tests/integration/targets/keycloak_group/vars/main.yml
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
|
||||||
|
|
||||||
|
url: http://localhost:8080/auth
|
||||||
|
admin_realm: master
|
||||||
|
admin_user: admin
|
||||||
|
admin_password: password
|
||||||
|
realm: master
|
Loading…
Reference in a new issue