1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

[PR #8252/a5697da2 backport][stable-8] Keycloak client role scope (#8266)

Keycloak client role scope (#8252)

* first commit

* minor update

* fixe Copyright

* fixe sanity

* Update plugins/modules/keycloak_client_rolescope.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* fixe sanity 2

* Update plugins/modules/keycloak_client_rolescope.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Andre Desrosiers <andre.desrosiers@ssss.gouv.qc.ca>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit a5697da29c)

Co-authored-by: desand01 <desrosiers.a@hotmail.com>
This commit is contained in:
patchback[bot] 2024-04-21 20:39:47 +02:00 committed by GitHub
parent bc829f64bc
commit aa384be6fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 752 additions and 0 deletions

2
.github/BOTMETA.yml vendored
View file

@ -780,6 +780,8 @@ files:
maintainers: laurpaum maintainers: laurpaum
$modules/keycloak_component_info.py: $modules/keycloak_component_info.py:
maintainers: desand01 maintainers: desand01
$modules/keycloak_client_rolescope.py:
maintainers: desand01
$modules/keycloak_user_rolemapping.py: $modules/keycloak_user_rolemapping.py:
maintainers: bratwurzt maintainers: bratwurzt
$modules/keycloak_realm_rolemapping.py: $modules/keycloak_realm_rolemapping.py:

View file

@ -28,6 +28,9 @@ URL_CLIENT_ROLES = "{url}/admin/realms/{realm}/clients/{id}/roles"
URL_CLIENT_ROLE = "{url}/admin/realms/{realm}/clients/{id}/roles/{name}" URL_CLIENT_ROLE = "{url}/admin/realms/{realm}/clients/{id}/roles/{name}"
URL_CLIENT_ROLE_COMPOSITES = "{url}/admin/realms/{realm}/clients/{id}/roles/{name}/composites" URL_CLIENT_ROLE_COMPOSITES = "{url}/admin/realms/{realm}/clients/{id}/roles/{name}/composites"
URL_CLIENT_ROLE_SCOPE_CLIENTS = "{url}/admin/realms/{realm}/clients/{id}/scope-mappings/clients/{scopeid}"
URL_CLIENT_ROLE_SCOPE_REALM = "{url}/admin/realms/{realm}/clients/{id}/scope-mappings/realm"
URL_REALM_ROLES = "{url}/admin/realms/{realm}/roles" URL_REALM_ROLES = "{url}/admin/realms/{realm}/roles"
URL_REALM_ROLE = "{url}/admin/realms/{realm}/roles/{name}" URL_REALM_ROLE = "{url}/admin/realms/{realm}/roles/{name}"
URL_REALM_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm" URL_REALM_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm"
@ -3049,6 +3052,105 @@ class KeycloakAPI(object):
except Exception: except Exception:
return False return False
def get_client_role_scope_from_client(self, clientid, clientscopeid, realm="master"):
""" Fetch the roles associated with the client's scope for a specific client on the Keycloak server.
:param clientid: ID of the client from which to obtain the associated roles.
:param clientscopeid: ID of the client who owns the roles.
:param realm: Realm from which to obtain the scope.
:return: The client scope of roles from specified client.
"""
client_role_scope_url = URL_CLIENT_ROLE_SCOPE_CLIENTS.format(url=self.baseurl, realm=realm, id=clientid, scopeid=clientscopeid)
try:
return json.loads(to_native(open_url(client_role_scope_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.fail_open_url(e, msg='Could not fetch roles scope for client %s in realm %s: %s' % (clientid, realm, str(e)))
def update_client_role_scope_from_client(self, payload, clientid, clientscopeid, realm="master"):
""" Update and fetch the roles associated with the client's scope on the Keycloak server.
:param payload: List of roles to be added to the scope.
:param clientid: ID of the client to update scope.
:param clientscopeid: ID of the client who owns the roles.
:param realm: Realm from which to obtain the clients.
:return: The client scope of roles from specified client.
"""
client_role_scope_url = URL_CLIENT_ROLE_SCOPE_CLIENTS.format(url=self.baseurl, realm=realm, id=clientid, scopeid=clientscopeid)
try:
open_url(client_role_scope_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(payload), validate_certs=self.validate_certs)
except Exception as e:
self.fail_open_url(e, msg='Could not update roles scope for client %s in realm %s: %s' % (clientid, realm, str(e)))
return self.get_client_role_scope_from_client(clientid, clientscopeid, realm)
def delete_client_role_scope_from_client(self, payload, clientid, clientscopeid, realm="master"):
""" Delete the roles contains in the payload from the client's scope on the Keycloak server.
:param payload: List of roles to be deleted.
:param clientid: ID of the client to delete roles from scope.
:param clientscopeid: ID of the client who owns the roles.
:param realm: Realm from which to obtain the clients.
:return: The client scope of roles from specified client.
"""
client_role_scope_url = URL_CLIENT_ROLE_SCOPE_CLIENTS.format(url=self.baseurl, realm=realm, id=clientid, scopeid=clientscopeid)
try:
open_url(client_role_scope_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(payload), validate_certs=self.validate_certs)
except Exception as e:
self.fail_open_url(e, msg='Could not delete roles scope for client %s in realm %s: %s' % (clientid, realm, str(e)))
return self.get_client_role_scope_from_client(clientid, clientscopeid, realm)
def get_client_role_scope_from_realm(self, clientid, realm="master"):
""" Fetch the realm roles from the client's scope on the Keycloak server.
:param clientid: ID of the client from which to obtain the associated realm roles.
:param realm: Realm from which to obtain the clients.
:return: The client realm roles scope.
"""
client_role_scope_url = URL_CLIENT_ROLE_SCOPE_REALM.format(url=self.baseurl, realm=realm, id=clientid)
try:
return json.loads(to_native(open_url(client_role_scope_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.fail_open_url(e, msg='Could not fetch roles scope for client %s in realm %s: %s' % (clientid, realm, str(e)))
def update_client_role_scope_from_realm(self, payload, clientid, realm="master"):
""" Update and fetch the realm roles from the client's scope on the Keycloak server.
:param payload: List of realm roles to add.
:param clientid: ID of the client to update scope.
:param realm: Realm from which to obtain the clients.
:return: The client realm roles scope.
"""
client_role_scope_url = URL_CLIENT_ROLE_SCOPE_REALM.format(url=self.baseurl, realm=realm, id=clientid)
try:
open_url(client_role_scope_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(payload), validate_certs=self.validate_certs)
except Exception as e:
self.fail_open_url(e, msg='Could not update roles scope for client %s in realm %s: %s' % (clientid, realm, str(e)))
return self.get_client_role_scope_from_realm(clientid, realm)
def delete_client_role_scope_from_realm(self, payload, clientid, realm="master"):
""" Delete the realm roles contains in the payload from the client's scope on the Keycloak server.
:param payload: List of realm roles to delete.
:param clientid: ID of the client to delete roles from scope.
:param realm: Realm from which to obtain the clients.
:return: The client realm roles scope.
"""
client_role_scope_url = URL_CLIENT_ROLE_SCOPE_REALM.format(url=self.baseurl, realm=realm, id=clientid)
try:
open_url(client_role_scope_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(payload), validate_certs=self.validate_certs)
except Exception as e:
self.fail_open_url(e, msg='Could not delete roles scope for client %s in realm %s: %s' % (clientid, realm, str(e)))
return self.get_client_role_scope_from_realm(clientid, realm)
def fail_open_url(self, e, msg, **kwargs): def fail_open_url(self, e, msg, **kwargs):
try: try:
if isinstance(e, HTTPError): if isinstance(e, HTTPError):

View file

@ -0,0 +1,280 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: keycloak_client_rolescope
short_description: Allows administration of Keycloak client roles scope to restrict the usage of certain roles to a other specific client applications.
version_added: 8.6.0
description:
- This module allows you to add or remove Keycloak roles from clients scope via the Keycloak REST API.
It requires access to the REST API via OpenID Connect; the user connecting and the client being
used must have the requisite access rights. In a default Keycloak installation, admin-cli
and an admin user would work, as would a separate client definition with the scope tailored
to your needs and a user having the expected roles.
- Client O(client_id) must have O(community.general.keycloak_client#module:full_scope_allowed) set to V(false).
- 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,
and this will be translated into a list suitable for the API.
attributes:
check_mode:
support: full
diff_mode:
support: full
options:
state:
description:
- State of the role mapping.
- On V(present), all roles in O(role_names) will be mapped if not exists yet.
- On V(absent), all roles mapping in O(role_names) will be removed if it exists.
default: 'present'
type: str
choices:
- present
- absent
realm:
type: str
description:
- The Keycloak realm under which clients resides.
default: 'master'
client_id:
type: str
required: true
description:
- Roles provided in O(role_names) while be added to this client scope.
client_scope_id:
type: str
description:
- If the O(role_names) are client role, the client ID under which it resides.
- If this parameter is absent, the roles are considered a realm role.
role_names:
required: true
type: list
elements: str
description:
- Names of roles to manipulate.
- If O(client_scope_id) is present, all roles must be under this client.
- If O(client_scope_id) is absent, all roles must be under the realm.
extends_documentation_fragment:
- community.general.keycloak
- community.general.attributes
author:
- Andre Desrosiers (@desand01)
'''
EXAMPLES = '''
- name: Add roles to public client scope
community.general.keycloak_client_rolescope:
auth_keycloak_url: https://auth.example.com/auth
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
realm: MyCustomRealm
client_id: frontend-client-public
client_scope_id: backend-client-private
role_names:
- backend-role-admin
- backend-role-user
- name: Remove roles from public client scope
community.general.keycloak_client_rolescope:
auth_keycloak_url: https://auth.example.com/auth
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
realm: MyCustomRealm
client_id: frontend-client-public
client_scope_id: backend-client-private
role_names:
- backend-role-admin
state: absent
- name: Add realm roles to public client scope
community.general.keycloak_client_rolescope:
auth_keycloak_url: https://auth.example.com/auth
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
realm: MyCustomRealm
client_id: frontend-client-public
role_names:
- realm-role-admin
- realm-role-user
'''
RETURN = '''
msg:
description: Message as to what action was taken.
returned: always
type: str
sample: "Client role scope for frontend-client-public has been updated"
end_state:
description: Representation of role role scope after module execution.
returned: on success
type: list
elements: dict
sample: [
{
"clientRole": false,
"composite": false,
"containerId": "MyCustomRealm",
"id": "47293104-59a6-46f0-b460-2e9e3c9c424c",
"name": "backend-role-admin"
},
{
"clientRole": false,
"composite": false,
"containerId": "MyCustomRealm",
"id": "39c62a6d-542c-4715-92d2-41021eb33967",
"name": "backend-role-user"
}
]
'''
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, \
keycloak_argument_spec, get_token, KeycloakError
from ansible.module_utils.basic import AnsibleModule
def main():
"""
Module execution
:return:
"""
argument_spec = keycloak_argument_spec()
meta_args = dict(
client_id=dict(type='str', required=True),
client_scope_id=dict(type='str'),
realm=dict(type='str', default='master'),
role_names=dict(type='list', elements='str', required=True),
state=dict(type='str', default='present', choices=['present', 'absent']),
)
argument_spec.update(meta_args)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
result = dict(changed=False, msg='', diff={}, end_state={})
# Obtain access token, initialize API
try:
connection_header = get_token(module.params)
except KeycloakError as e:
module.fail_json(msg=str(e))
kc = KeycloakAPI(module, connection_header)
realm = module.params.get('realm')
clientid = module.params.get('client_id')
client_scope_id = module.params.get('client_scope_id')
role_names = module.params.get('role_names')
state = module.params.get('state')
objRealm = kc.get_realm_by_id(realm)
if not objRealm:
module.fail_json(msg="Failed to retrive realm '{realm}'".format(realm=realm))
objClient = kc.get_client_by_clientid(clientid, realm)
if not objClient:
module.fail_json(msg="Failed to retrive client '{realm}.{clientid}'".format(realm=realm, clientid=clientid))
if objClient["fullScopeAllowed"] and state == "present":
module.fail_json(msg="FullScopeAllowed is active for Client '{realm}.{clientid}'".format(realm=realm, clientid=clientid))
if client_scope_id:
objClientScope = kc.get_client_by_clientid(client_scope_id, realm)
if not objClientScope:
module.fail_json(msg="Failed to retrive client '{realm}.{client_scope_id}'".format(realm=realm, client_scope_id=client_scope_id))
before_role_mapping = kc.get_client_role_scope_from_client(objClient["id"], objClientScope["id"], realm)
else:
before_role_mapping = kc.get_client_role_scope_from_realm(objClient["id"], realm)
if client_scope_id:
# retrive all role from client_scope
client_scope_roles_by_name = kc.get_client_roles_by_id(objClientScope["id"], realm)
else:
# retrive all role from realm
client_scope_roles_by_name = kc.get_realm_roles(realm)
# convert to indexed Dict by name
client_scope_roles_by_name = {role["name"]: role for role in client_scope_roles_by_name}
role_mapping_by_name = {role["name"]: role for role in before_role_mapping}
role_mapping_to_manipulate = []
if state == "present":
# update desired
for role_name in role_names:
if role_name not in client_scope_roles_by_name:
if client_scope_id:
module.fail_json(msg="Failed to retrive role '{realm}.{client_scope_id}.{role_name}'"
.format(realm=realm, client_scope_id=client_scope_id, role_name=role_name))
else:
module.fail_json(msg="Failed to retrive role '{realm}.{role_name}'".format(realm=realm, role_name=role_name))
if role_name not in role_mapping_by_name:
role_mapping_to_manipulate.append(client_scope_roles_by_name[role_name])
role_mapping_by_name[role_name] = client_scope_roles_by_name[role_name]
else:
# remove role if present
for role_name in role_names:
if role_name in role_mapping_by_name:
role_mapping_to_manipulate.append(role_mapping_by_name[role_name])
del role_mapping_by_name[role_name]
before_role_mapping = sorted(before_role_mapping, key=lambda d: d['name'])
desired_role_mapping = sorted(role_mapping_by_name.values(), key=lambda d: d['name'])
result['changed'] = len(role_mapping_to_manipulate) > 0
if result['changed']:
result['diff'] = dict(before=before_role_mapping, after=desired_role_mapping)
if not result['changed']:
# no changes
result['end_state'] = before_role_mapping
result['msg'] = "No changes required for client role scope {name}.".format(name=clientid)
elif state == "present":
# doing update
if module.check_mode:
result['end_state'] = desired_role_mapping
elif client_scope_id:
result['end_state'] = kc.update_client_role_scope_from_client(role_mapping_to_manipulate, objClient["id"], objClientScope["id"], realm)
else:
result['end_state'] = kc.update_client_role_scope_from_realm(role_mapping_to_manipulate, objClient["id"], realm)
result['msg'] = "Client role scope for {name} has been updated".format(name=clientid)
else:
# doing delete
if module.check_mode:
result['end_state'] = desired_role_mapping
elif client_scope_id:
result['end_state'] = kc.delete_client_role_scope_from_client(role_mapping_to_manipulate, objClient["id"], objClientScope["id"], realm)
else:
result['end_state'] = kc.delete_client_role_scope_from_realm(role_mapping_to_manipulate, objClient["id"], realm)
result['msg'] = "Client role scope for {name} has been deleted".format(name=clientid)
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,20 @@
<!--
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_client_rolescope module integration test
To run Keycloak component info module's integration test, start a keycloak server using Docker:
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
Run integration tests:
ansible-test integration -v keycloak_client_rolescope --allow-unsupported --docker fedora35 --docker-network host
Cleanup:
docker stop mykeycloak

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,317 @@
---
# 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: 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 a Keycloak realm role
community.general.keycloak_role:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: "{{ item }}"
realm: "{{ realm }}"
with_items:
- "{{ realm_role_admin }}"
- "{{ realm_role_user }}"
- name: Client private
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_name_private }}"
state: present
redirect_uris:
- "https://my-backend-api.c.org/"
fullScopeAllowed: True
attributes: '{{client_attributes1}}'
public_client: False
- name: Create a Keycloak client role
community.general.keycloak_role:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: "{{ item }}"
realm: "{{ realm }}"
client_id: "{{ client_name_private }}"
with_items:
- "{{ client_role_admin }}"
- "{{ client_role_user }}"
- name: Client public
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_name_public }}"
redirect_uris:
- "https://my-onepage-app-frontend.c.org/"
attributes: '{{client_attributes1}}'
full_scope_allowed: False
public_client: True
- name: Map roles to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
client_scope_id: "{{ client_name_private }}"
role_names:
- "{{ client_role_admin }}"
- "{{ client_role_user }}"
register: result
- name: Assert mapping created
assert:
that:
- result is changed
- result.end_state | length == 2
- name: remap role user to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
client_scope_id: "{{ client_name_private }}"
role_names:
- "{{ client_role_user }}"
register: result
- name: Assert mapping created
assert:
that:
- result is not changed
- result.end_state | length == 2
- name: Remove Map role admin to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
client_scope_id: "{{ client_name_private }}"
role_names:
- "{{ client_role_admin }}"
state: absent
register: result
- name: Assert mapping deleted
assert:
that:
- result is changed
- result.end_state | length == 1
- result.end_state[0].name == client_role_user
- name: Map missing roles to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
client_scope_id: "{{ client_name_private }}"
role_names:
- "{{ client_role_admin }}"
- "{{ client_role_not_exists }}"
ignore_errors: true
register: result
- name: Assert failed mapping missing role
assert:
that:
- result is failed
- name: Map roles duplicate
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
client_scope_id: "{{ client_name_private }}"
role_names:
- "{{ client_role_admin }}"
- "{{ client_role_admin }}"
register: result
- name: Assert result
assert:
that:
- result is changed
- result.end_state | length == 2
- name: Map roles to private client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_private }}"
role_names:
- "{{ realm_role_admin }}"
ignore_errors: true
register: result
- name: Assert failed mapping role to full scope client
assert:
that:
- result is failed
- name: Map realm role to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
role_names:
- "{{ realm_role_admin }}"
register: result
- name: Assert result
assert:
that:
- result is changed
- result.end_state | length == 1
- name: Map two realm roles to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
role_names:
- "{{ realm_role_admin }}"
- "{{ realm_role_user }}"
register: result
- name: Assert result
assert:
that:
- result is changed
- result.end_state | length == 2
- name: Unmap all realm roles to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
role_names:
- "{{ realm_role_admin }}"
- "{{ realm_role_user }}"
state: absent
register: result
- name: Assert result
assert:
that:
- result is changed
- result.end_state | length == 0
- name: Map missing realm role to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
role_names:
- "{{ realm_role_not_exists }}"
ignore_errors: true
register: result
- name: Assert failed mapping missing realm role
assert:
that:
- result is failed
- name: Check-mode try to Map realm roles to public client
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
role_names:
- "{{ realm_role_admin }}"
- "{{ realm_role_user }}"
check_mode: true
register: result
- name: Assert result
assert:
that:
- result is changed
- result.end_state | length == 2
- name: Check-mode step two, check if change where applied
community.general.keycloak_client_rolescope:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
client_id: "{{ client_name_public }}"
role_names: []
register: result
- name: Assert result
assert:
that:
- result is not changed
- result.end_state | length == 0

View file

@ -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
url: http://localhost:8080/auth
admin_realm: master
admin_user: admin
admin_password: password
realm: myrealm
client_name_private: backend-client-private
client_role_admin: client-role-admin
client_role_user: client-role-user
client_role_not_exists: client-role-missing
client_name_public: frontend-client-public
realm_role_admin: realm-role-admin
realm_role_user: realm-role-user
realm_role_not_exists: client-role-missing
client_attributes1: {"backchannel.logout.session.required": true, "backchannel.logout.revoke.offline.tokens": false, "client.secret.creation.time": 0}