rename files to match new convention

This commit is contained in:
Felix Grzelka
2026-06-08 11:57:26 +00:00
parent ba3f716e5c
commit 1ec94b961f
2 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,282 @@
# 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 annotations
DOCUMENTATION = r"""
module: keycloak_client_scope_rolemappings
short_description: Allows administration of Keycloak client scope scope mappings to restrict the usage of certain roles to
specific client scopes
# Originally added in community.general 13.1.0
version_added: "3.0.0"
description:
- This module allows you to add or remove Keycloak roles from client scopes using the Keycloak REST API. It requires access
to the REST API using OpenID Connect; the user connecting and the client being used must have the requisite access rights.
In a default Keycloak installation, C(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.
- Attributes are multi-valued in the Keycloak API. All attributes are lists of individual values and are returned that way
by this module. You may pass single values for attributes when calling the module, and this is translated into a list
suitable for the API.
attributes:
check_mode:
support: full
diff_mode:
support: full
action_group:
# Originally added in community.general 13.1.0
version_added: "3.0.0"
options:
state:
description:
- State of the role mapping.
- On V(present), all roles in O(role_names) are mapped if not exist yet.
- On V(absent), all roles mapping in O(role_names) are removed if they exist.
default: 'present'
type: str
choices:
- present
- absent
realm:
type: str
description:
- The Keycloak realm under which clients resides.
default: 'master'
client_scope_id:
required: true
type: str
description:
- Roles provided in O(role_names) will be added to this client scope.
client_id:
type: str
description:
- If the O(role_names) are client roles, the client ID under which it resides.
- If this parameter is absent, the roles are considered realm roles.
role_names:
required: true
type: list
elements: str
description:
- Names of roles to add.
- If O(client_id) is present, all roles must be under this client.
- If O(client_id) is absent, all roles must be under the realm.
extends_documentation_fragment:
- middleware_automation.keycloak.keycloak
- middleware_automation.keycloak.actiongroup_keycloak
- middleware_automation.keycloak.attributes
author:
- Felix Grzelka (@felix-grzelka)
# This module was adapted from keycloak_client_rolescope, which was written by Andre Desrosiers (@desand01).
"""
EXAMPLES = r"""
- name: Add roles to client scope
middleware_automation.keycloak.keycloak_client_scope_rolemappings:
auth_keycloak_url: https://auth.example.com
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
realm: MyCustomRealm
client_id: frontend-client-public
client_scope_id: frontend-client-scope
role_names:
- backend-role-admin
- backend-role-user
- name: Remove roles from client scope
middleware_automation.keycloak.keycloak_client_scope_rolemappings:
auth_keycloak_url: https://auth.example.com
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
realm: MyCustomRealm
client_id: frontend-client-public
client_scope_id: frontend-client-scope
role_names:
- backend-role-admin
state: absent
- name: Add realm roles to client scope
middleware_automation.keycloak.keycloak_client_scope_rolemappings:
auth_keycloak_url: https://auth.example.com
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
realm: MyCustomRealm
client_scope_id: frontend-client-scope
role_names:
- realm-role-admin
- realm-role-user
"""
RETURN = r"""
end_state:
description: Representation of client scope scope mappings after module execution.
returned: on success
type: list
elements: dict
sample:
[
{
"clientRole": false,
"composite": false,
"containerId": "77f9bd4e-13a6-451e-9c72-ee6997299c1f",
"description": "User role",
"id": "9e155ef7-86f5-4def-b507-581ce7b87013",
"name": "realm-role-user"
},
{
"clientRole": false,
"composite": false,
"containerId": "77f9bd4e-13a6-451e-9c72-ee6997299c1f",
"description": "Admin role",
"id": "9e155ef7-86f5-4def-b507-581ce7b87013",
"name": "realm-role-admin"
}
]
"""
import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.middleware_automation.keycloak.plugins.module_utils.identity.keycloak.keycloak import (
KeycloakAPI,
KeycloakError,
get_token,
keycloak_argument_spec,
)
def main():
argument_spec = keycloak_argument_spec()
meta_args = dict(
client_id=dict(type="str"),
client_scope_id=dict(type="str", required=True),
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["realm"]
client_id = module.params["client_id"]
client_scope_id = module.params["client_scope_id"]
role_names = module.params["role_names"]
state = module.params["state"]
realm_object = kc.get_realm_by_id(realm)
if not realm_object:
module.fail_json(msg=f"Failed to retrieve realm '{realm}'")
client_scope_object = kc.get_client_scope_by_name(client_scope_id, realm)
if not client_scope_object:
module.fail_json(msg=f"Failed to retrieve client scope '{client_scope_id}'")
if client_id:
# add client role
client_object = kc.get_client_by_clientid(client_id, realm)
if not client_object:
module.fail_json(msg=f"Failed to retrieve client '{realm}.{client_id}'")
if client_object["fullScopeAllowed"] and state == "present":
module.fail_json(msg=f"FullScopeAllowed is active for Client '{realm}.{client_id}'")
before_roles = kc.get_client_scope_scope_mappings_client(client_scope_object["id"], client_object["id"], realm)
available_roles_by_name = kc.get_client_roles_by_id(client_object["id"], realm)
else:
# add realm role
before_roles = kc.get_client_scope_scope_mappings_realm(client_scope_object["id"], realm)
available_roles_by_name = kc.get_realm_roles(realm)
# convert to indexed Dict by name
available_roles_by_name = {role["name"]: role for role in available_roles_by_name}
before_roles_by_name = {role["name"]: role for role in before_roles}
desired_roles = copy.deepcopy(before_roles)
changed_roles = []
if state == "present":
# update desired
for role_name in role_names:
if role_name not in available_roles_by_name:
if client_id:
module.fail_json(msg=f"Failed to retrieve role '{realm}.{client_id}.{role_name}'")
else:
module.fail_json(msg=f"Failed to retrieve role '{realm}.{role_name}'")
if role_name not in before_roles_by_name:
changed_roles.append(available_roles_by_name[role_name])
desired_roles.append(available_roles_by_name[role_name])
else:
# remove role if present
for role_name in role_names:
if role_name in before_roles_by_name:
changed_roles.append(before_roles_by_name[role_name])
desired_roles.remove(available_roles_by_name[role_name])
before_roles = sorted(before_roles, key=lambda d: d["name"])
desired_role_mapping = sorted(desired_roles, key=lambda d: d["name"])
result["changed"] = bool(changed_roles)
if module._diff:
result["diff"] = dict(before={"roles": before_roles}, after={"roles": desired_role_mapping})
if not result["changed"]:
# no changes
result["end_state"] = before_roles
result["msg"] = f"No changes required for client scope {client_scope_id}."
elif state == "present":
# doing update
if module.check_mode:
result["end_state"] = desired_role_mapping
elif client_id:
result["end_state"] = kc.update_client_scope_scope_mappings_client(
changed_roles, client_scope_object["id"], client_object["id"], realm
)
else:
result["end_state"] = kc.update_client_scope_scope_mappings_realm(
changed_roles, client_scope_object["id"], realm
)
result["msg"] = f"Clientscope scope mappings for {client_scope_id} have been updated"
else:
# doing delete
if module.check_mode:
result["end_state"] = desired_role_mapping
elif client_id:
result["end_state"] = kc.delete_client_scope_scope_mappings_client(
changed_roles, client_scope_object["id"], client_object["id"], realm
)
else:
result["end_state"] = kc.delete_client_scope_scope_mappings_realm(
changed_roles, client_scope_object["id"], realm
)
result["msg"] = f"Clientscope scope mappings for {client_scope_id} have been deleted"
module.exit_json(**result)
if __name__ == "__main__":
main()