diff --git a/README.md b/README.md index 7ea01bb..55474ed 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ All Keycloak administration modules from `community.general` are provided in thi * `keycloak_client_rolemapping`: manage client role mappings for users and groups. * `keycloak_client_rolescope`: manage client role scope mappings. * `keycloak_client_scope`: manage client scopes and protocol mappers (replaces `community.general.keycloak_clientscope`). -* `keycloak_clientscope_type`: manage default and optional client scope assignments. +* `keycloak_client_scopeee_type`: manage default and optional client scope assignments. * `keycloak_clientsecret_info`: retrieve client secret information. * `keycloak_clientsecret_regenerate`: regenerate a client secret. * `keycloak_clienttemplate`: manage legacy client templates. diff --git a/meta/runtime.yml b/meta/runtime.yml index e2907d9..2e2fc5d 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -14,8 +14,8 @@ action_groups: - keycloak_client_rolemapping - keycloak_client_rolescope - keycloak_client_scope - - keycloak_clientscope_type - - keycloak_clientscope_rolemappings + - keycloak_client_scope_type + - keycloak_client_scope_rolemappings - keycloak_clientsecret_info - keycloak_clientsecret_regenerate - keycloak_clienttemplate @@ -44,3 +44,19 @@ plugin_routing: warning_text: >- The module has been renamed to keycloak_client_scope for Keycloak 17+ (Quarkus). Update playbooks to use middleware_automation.keycloak.keycloak_client_scope. + + keycloak_clientscope_type: + redirect: middleware_automation.keycloak.keycloak_client_scope_type + deprecation: + removal_version: 5.0.0 + warning_text: >- + The module has been renamed to keycloak_client_scope_type for Keycloak 17+ (Quarkus). + Update playbooks to use middleware_automation.keycloak.keycloak_client_scope_type. + + keycloak_clientscope_rolemappings: + redirect: middleware_automation.keycloak.keycloak_client_scope_rolemappings + deprecation: + removal_version: 5.0.0 + warning_text: >- + The module has been renamed to keycloak_client_scope_rolemappings for Keycloak 17+ (Quarkus). + Update playbooks to use middleware_automation.keycloak.keycloak_client_scope_rolemappings. diff --git a/molecule/keycloak_modules/verify.yml b/molecule/keycloak_modules/verify.yml index 867f687..a313b24 100644 --- a/molecule/keycloak_modules/verify.yml +++ b/molecule/keycloak_modules/verify.yml @@ -37,8 +37,8 @@ - keycloak_client_rolemapping - keycloak_client_rolescope - keycloak_client_scope - - keycloak_clientscope_type - - keycloak_clientscope_rolemappings + - keycloak_client_scope_type + - keycloak_client_scope_rolemappings - keycloak_clientsecret_info - keycloak_clientsecret_regenerate - keycloak_clienttemplate @@ -265,10 +265,10 @@ - "'404' not in (clienttemplate_result.msg | default(''))" - "'Not Found' not in (clienttemplate_result.msg | default(''))" - - name: keycloak_clientscope_type — attach scope as optional on realm - middleware_automation.keycloak.keycloak_clientscope_type: + - name: keycloak_client_scope_type — attach scope as optional on realm + middleware_automation.keycloak.keycloak_client_scope_type: realm: "{{ target_realm }}" - optional_clientscopes: + optional_client_scopes: - "{{ scope }}" - name: keycloak_user_rolemapping — assign realm role to user @@ -304,49 +304,49 @@ - "{{ role }}" state: present - - name: keycloak_clientscope_rolemappings — map client roles to clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: + - name: keycloak_client_scope_rolemappings — map client roles to client scope + middleware_automation.keycloak.keycloak_client_scope_rolemappings: realm: "{{ target_realm }}" client_id: "{{ client }}" - clientscope_id: "{{ scope }}" + client_scope_id: "{{ scope }}" role_names: - "{{ client_role }}" - register: clientscope_rolemappings_result + register: client_scope_rolemappings_result - - name: Assert clientscope role mappings were created + - name: Assert client scope role mappings were created ansible.builtin.assert: that: - - clientscope_rolemappings_result is changed - - clientscope_rolemappings_result.end_state | length == 1 + - client_scope_rolemappings_result is changed + - client_scope_rolemappings_result.end_state | length == 1 - - name: keycloak_clientscope_rolemappings — remap client role (idempotency) - middleware_automation.keycloak.keycloak_clientscope_rolemappings: + - name: keycloak_client_scope_rolemappings — remap client role (idempotency) + middleware_automation.keycloak.keycloak_client_scope_rolemappings: realm: "{{ target_realm }}" client_id: "{{ client }}" - clientscope_id: "{{ scope }}" + client_scope_id: "{{ scope }}" role_names: - "{{ client_role }}" - register: clientscope_rolemappings_idempotent_result + register: client_scope_rolemappings_idempotent_result - - name: Assert clientscope role mappings are idempotent + - name: Assert client scope role mappings are idempotent ansible.builtin.assert: that: - - clientscope_rolemappings_idempotent_result is not changed - - clientscope_rolemappings_idempotent_result.end_state | length == 1 + - client_scope_rolemappings_idempotent_result is not changed + - client_scope_rolemappings_idempotent_result.end_state | length == 1 - - name: keycloak_clientscope_rolemappings — map realm role to clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: + - name: keycloak_client_scope_rolemappings — map realm role to client scope + middleware_automation.keycloak.keycloak_client_scope_rolemappings: realm: "{{ target_realm }}" - clientscope_id: "{{ scope }}" + client_scope_id: "{{ scope }}" role_names: - "{{ role }}" - register: clientscope_realm_rolemappings_result + register: client_scope_realm_rolemappings_result - - name: Assert realm role was mapped to clientscope + - name: Assert realm role was mapped to client_scope ansible.builtin.assert: that: - - clientscope_realm_rolemappings_result is changed - - clientscope_realm_rolemappings_result.end_state | length == 1 + - client_scope_realm_rolemappings_result is changed + - client_scope_realm_rolemappings_result.end_state | length == 1 - name: keycloak_user — set email_verified explicitly middleware_automation.keycloak.keycloak_user: @@ -517,19 +517,19 @@ name: "{{ authz_scope }}" state: absent - - name: keycloak_clientscope_rolemappings — remove realm role from clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: + - name: keycloak_client_scope_rolemappings — remove realm role from client scope + middleware_automation.keycloak.keycloak_client_scope_rolemappings: realm: "{{ target_realm }}" - clientscope_id: "{{ scope }}" + client_scope_id: "{{ scope }}" role_names: - "{{ role }}" state: absent - - name: keycloak_clientscope_rolemappings — remove client role from clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: + - name: keycloak_client_scope_rolemappings — remove client role from client scope + middleware_automation.keycloak.keycloak_client_scope_rolemappings: realm: "{{ target_realm }}" client_id: "{{ client }}" - clientscope_id: "{{ scope }}" + client_scope_id: "{{ scope }}" role_names: - "{{ client_role }}" state: absent diff --git a/plugins/module_utils/identity/keycloak/keycloak.py b/plugins/module_utils/identity/keycloak/keycloak.py index b0be79e..e2e9da3 100644 --- a/plugins/module_utils/identity/keycloak/keycloak.py +++ b/plugins/module_utils/identity/keycloak/keycloak.py @@ -57,23 +57,23 @@ URL_GROUPS = "{url}/admin/realms/{realm}/groups" 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_CLIENTSCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}" -URL_CLIENTSCOPE_SCOPE_MAPPINGS = "{url}/admin/realms/{realm}/client-scopes/{id}/scope-mappings" -URL_CLIENTSCOPE_SCOPE_MAPPINGS_REALM = "{url}/admin/realms/{realm}/client-scopes/{id}/scope-mappings/realm" -URL_CLIENTSCOPE_SCOPE_MAPPINGS_CLIENT = "{url}/admin/realms/{realm}/client-scopes/{id}/scope-mappings/clients/{client}" -URL_CLIENTSCOPE_PROTOCOLMAPPERS = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models" -URL_CLIENTSCOPE_PROTOCOLMAPPER = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models/{mapper_id}" +URL_CLIENT_SCOPES = "{url}/admin/realms/{realm}/client-scopes" +URL_CLIENT_SCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}" +URL_CLIENT_SCOPE_SCOPE_MAPPINGS = "{url}/admin/realms/{realm}/client-scopes/{id}/scope-mappings" +URL_CLIENT_SCOPE_SCOPE_MAPPINGS_REALM = "{url}/admin/realms/{realm}/client-scopes/{id}/scope-mappings/realm" +URL_CLIENT_SCOPE_SCOPE_MAPPINGS_CLIENT = "{url}/admin/realms/{realm}/client-scopes/{id}/scope-mappings/clients/{client}" +URL_CLIENT_SCOPE_PROTOCOLMAPPERS = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models" +URL_CLIENT_SCOPE_PROTOCOLMAPPER = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models/{mapper_id}" -URL_DEFAULT_CLIENTSCOPES = "{url}/admin/realms/{realm}/default-default-client-scopes" -URL_DEFAULT_CLIENTSCOPE = "{url}/admin/realms/{realm}/default-default-client-scopes/{id}" -URL_OPTIONAL_CLIENTSCOPES = "{url}/admin/realms/{realm}/default-optional-client-scopes" -URL_OPTIONAL_CLIENTSCOPE = "{url}/admin/realms/{realm}/default-optional-client-scopes/{id}" +URL_DEFAULT_CLIENT_SCOPES = "{url}/admin/realms/{realm}/default-default-client-scopes" +URL_DEFAULT_CLIENT_SCOPE = "{url}/admin/realms/{realm}/default-default-client-scopes/{id}" +URL_OPTIONAL_CLIENT_SCOPES = "{url}/admin/realms/{realm}/default-optional-client-scopes" +URL_OPTIONAL_CLIENT_SCOPE = "{url}/admin/realms/{realm}/default-optional-client-scopes/{id}" -URL_CLIENT_DEFAULT_CLIENTSCOPES = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes" -URL_CLIENT_DEFAULT_CLIENTSCOPE = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes/{id}" -URL_CLIENT_OPTIONAL_CLIENTSCOPES = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes" -URL_CLIENT_OPTIONAL_CLIENTSCOPE = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes/{id}" +URL_CLIENT_DEFAULT_CLIENT_SCOPES = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes" +URL_CLIENT_DEFAULT_CLIENT_SCOPE = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes/{id}" +URL_CLIENT_OPTIONAL_CLIENT_SCOPES = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes" +URL_CLIENT_OPTIONAL_CLIENT_SCOPE = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes/{id}" URL_CLIENT_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}" URL_CLIENT_GROUP_ROLEMAPPINGS_AVAILABLE = ( @@ -1289,99 +1289,99 @@ class KeycloakAPI: except Exception as e: self.fail_request(e, msg=f"Could not delete client template {id} in realm {realm}: {e}") - def get_clientscopes(self, realm: str = "master"): - """Fetch the name and ID of all clientscopes on the Keycloak server. + def get_client_scopes(self, realm: str = "master"): + """Fetch the name and ID of all client scopes on the Keycloak server. To fetch the full data of the group, make a subsequent call to - get_clientscope_by_clientscopeid, passing in the ID of the group you wish to return. + get_client_scope_by_client_scopeid, passing in the ID of the group you wish to return. - :param realm: Realm in which the clientscope resides; default 'master'. - :return The clientscopes of this realm (default "master") + :param realm: Realm in which the client scope resides; default 'master'. + :return The client scopes of this realm (default "master") """ - clientscopes_url = URL_CLIENTSCOPES.format(url=self.baseurl, realm=realm) + client_scopes_url = URL_CLIENT_SCOPES.format(url=self.baseurl, realm=realm) try: - return self._request_and_deserialize(clientscopes_url, method="GET") + return self._request_and_deserialize(client_scopes_url, method="GET") except Exception as e: - self.fail_request(e, msg=f"Could not fetch list of clientscopes in realm {realm}: {e}") + self.fail_request(e, msg=f"Could not fetch list of client scopes in realm {realm}: {e}") - def get_clientscope_by_clientscopeid(self, cid, realm: str = "master"): - """Fetch a keycloak clientscope from the provided realm using the clientscope's unique ID. + def get_client_scope_by_client_scopeid(self, cid, realm: str = "master"): + """Fetch a keycloak client scope from the provided realm using the client scope's unique ID. - If the clientscope does not exist, None is returned. + If the client scope does not exist, None is returned. gid is a UUID provided by the Keycloak API - :param cid: UUID of the clientscope to be returned - :param realm: Realm in which the clientscope resides; default 'master'. + :param cid: UUID of the client scope to be returned + :param realm: Realm in which the client scope resides; default 'master'. """ - clientscope_url = URL_CLIENTSCOPE.format(url=self.baseurl, realm=realm, id=cid) + client_scope_url = URL_CLIENT_SCOPE.format(url=self.baseurl, realm=realm, id=cid) try: - return self._request_and_deserialize(clientscope_url, method="GET") + return self._request_and_deserialize(client_scope_url, method="GET") except HTTPError as e: if e.code == HTTPStatus.NOT_FOUND: return None else: - self.fail_request(e, msg=f"Could not fetch clientscope {cid} in realm {realm}: {e}") + self.fail_request(e, msg=f"Could not fetch client scope {cid} in realm {realm}: {e}") except Exception as e: - self.module.fail_json(msg=f"Could not clientscope group {cid} in realm {realm}: {e}") + self.module.fail_json(msg=f"Could not client scope group {cid} in realm {realm}: {e}") - def get_clientscope_by_name(self, name, realm: str = "master"): - """Fetch a keycloak clientscope within a realm based on its name. + def get_client_scope_by_name(self, name, realm: str = "master"): + """Fetch a keycloak client scope within a realm based on its name. - The Keycloak API does not allow filtering of the clientscopes resource by name. - As a result, this method first retrieves the entire list of clientscopes - name and ID - + The Keycloak API does not allow filtering of the client scopes resource by name. + As a result, this method first retrieves the entire list of client scopes - name and ID - then performs a second query to fetch the group. - If the clientscope does not exist, None is returned. - :param name: Name of the clientscope to fetch. - :param realm: Realm in which the clientscope resides; default 'master' + If the client scope does not exist, None is returned. + :param name: Name of the client scope to fetch. + :param realm: Realm in which the client scope resides; default 'master' """ try: - all_clientscopes = self.get_clientscopes(realm=realm) + all_client_scopes = self.get_client_scopes(realm=realm) - for clientscope in all_clientscopes: - if clientscope["name"] == name: - return self.get_clientscope_by_clientscopeid(clientscope["id"], realm=realm) + for client_scope in all_client_scopes: + if client_scope["name"] == name: + return self.get_client_scope_by_client_scopeid(client_scope["id"], realm=realm) return None except Exception as e: - self.module.fail_json(msg=f"Could not fetch clientscope {name} in realm {realm}: {e}") + self.module.fail_json(msg=f"Could not fetch client scope {name} in realm {realm}: {e}") - def create_clientscope(self, clientscoperep, realm: str = "master"): - """Create a Keycloak clientscope. + def create_client_scope(self, client_scoperep, realm: str = "master"): + """Create a Keycloak client scope. - :param clientscoperep: a ClientScopeRepresentation of the clientscope to be created. Must contain at minimum the field name. + :param client_scoperep: a ClientScopeRepresentation of the client scope to be created. Must contain at minimum the field name. :return: HTTPResponse object on success """ - clientscopes_url = URL_CLIENTSCOPES.format(url=self.baseurl, realm=realm) + client_scopes_url = URL_CLIENT_SCOPES.format(url=self.baseurl, realm=realm) try: - return self._request(clientscopes_url, method="POST", data=json.dumps(clientscoperep)) + return self._request(client_scopes_url, method="POST", data=json.dumps(client_scoperep)) except Exception as e: - self.fail_request(e, msg=f"Could not create clientscope {clientscoperep['name']} in realm {realm}: {e}") + self.fail_request(e, msg=f"Could not create client scope {client_scoperep['name']} in realm {realm}: {e}") - def update_clientscope(self, clientscoperep, realm: str = "master"): - """Update an existing clientscope. + def update_client_scope(self, client_scoperep, realm: str = "master"): + """Update an existing client scope. :param grouprep: A GroupRepresentation of the updated group. :return HTTPResponse object on success """ - clientscope_url = URL_CLIENTSCOPE.format(url=self.baseurl, realm=realm, id=clientscoperep["id"]) + client_scope_url = URL_CLIENT_SCOPE.format(url=self.baseurl, realm=realm, id=client_scoperep["id"]) try: - return self._request(clientscope_url, method="PUT", data=json.dumps(clientscoperep)) + return self._request(client_scope_url, method="PUT", data=json.dumps(client_scoperep)) except Exception as e: - self.fail_request(e, msg=f"Could not update clientscope {clientscoperep['name']} in realm {realm}: {e}") + self.fail_request(e, msg=f"Could not update client scope {client_scoperep['name']} in realm {realm}: {e}") - def delete_clientscope(self, name=None, cid=None, realm: str = "master"): - """Delete a clientscope. One of name or cid must be provided. + def delete_client_scope(self, name=None, cid=None, realm: str = "master"): + """Delete a client scope. One of name or cid must be provided. - Providing the clientscope ID is preferred as it avoids a second lookup to - convert a clientscope name to an ID. + Providing the client scope ID is preferred as it avoids a second lookup to + convert a client scope name to an ID. - :param name: The name of the clientscope. A lookup will be performed to retrieve the clientscope ID. - :param cid: The ID of the clientscope (preferred to name). + :param name: The name of the client scope. A lookup will be performed to retrieve the client scope ID. + :param cid: The ID of the client scope (preferred to name). :param realm: The realm in which this group resides, default "master". """ @@ -1393,9 +1393,9 @@ class KeycloakAPI: # in the case that both are provided, prefer the ID, since it is one # less lookup. if cid is None and name is not None: - for clientscope in self.get_clientscopes(realm=realm): - if clientscope["name"] == name: - cid = clientscope["id"] + for client_scope in self.get_client_scopes(realm=realm): + if client_scope["name"] == name: + cid = client_scope["id"] break # if the group doesn't exist - no problem, nothing to delete. @@ -1403,41 +1403,41 @@ class KeycloakAPI: return None # should have a good cid by here. - clientscope_url = URL_CLIENTSCOPE.format(realm=realm, id=cid, url=self.baseurl) + client_scope_url = URL_CLIENT_SCOPE.format(realm=realm, id=cid, url=self.baseurl) try: - return self._request(clientscope_url, method="DELETE") + return self._request(client_scope_url, method="DELETE") except Exception as e: - self.fail_request(e, msg=f"Unable to delete clientscope {cid}: {e}") + self.fail_request(e, msg=f"Unable to delete client scope {cid}: {e}") - def get_clientscope_protocolmappers(self, cid, realm: str = "master"): - """Fetch the name and ID of all clientscopes on the Keycloak server. + def get_client_scope_protocolmappers(self, cid, realm: str = "master"): + """Fetch the name and ID of all client scopes on the Keycloak server. To fetch the full data of the group, make a subsequent call to - get_clientscope_by_clientscopeid, passing in the ID of the group you wish to return. + get_client_scope_by_client_scopeid, passing in the ID of the group you wish to return. - :param cid: id of clientscope (not name). - :param realm: Realm in which the clientscope resides; default 'master'. + :param cid: id of client scope (not name). + :param realm: Realm in which the client_scope resides; default 'master'. :return The protocolmappers of this realm (default "master") """ - protocolmappers_url = URL_CLIENTSCOPE_PROTOCOLMAPPERS.format(id=cid, url=self.baseurl, realm=realm) + protocolmappers_url = URL_CLIENT_SCOPE_PROTOCOLMAPPERS.format(id=cid, url=self.baseurl, realm=realm) try: return self._request_and_deserialize(protocolmappers_url, method="GET") except Exception as e: self.fail_request(e, msg=f"Could not fetch list of protocolmappers in realm {realm}: {e}") - def get_clientscope_protocolmapper_by_protocolmapperid(self, pid, cid, realm: str = "master"): - """Fetch a keycloak clientscope from the provided realm using the clientscope's unique ID. + def get_client_scope_protocolmapper_by_protocolmapperid(self, pid, cid, realm: str = "master"): + """Fetch a keycloak client scope from the provided realm using the client scope's unique ID. - If the clientscope does not exist, None is returned. + If the client scope does not exist, None is returned. gid is a UUID provided by the Keycloak API :param cid: UUID of the protocolmapper to be returned - :param cid: UUID of the clientscope to be returned - :param realm: Realm in which the clientscope resides; default 'master'. + :param cid: UUID of the client scope to be returned + :param realm: Realm in which the client scope resides; default 'master'. """ - protocolmapper_url = URL_CLIENTSCOPE_PROTOCOLMAPPER.format(url=self.baseurl, realm=realm, id=cid, mapper_id=pid) + protocolmapper_url = URL_CLIENT_SCOPE_PROTOCOLMAPPER.format(url=self.baseurl, realm=realm, id=cid, mapper_id=pid) try: return self._request_and_deserialize(protocolmapper_url, method="GET") @@ -1449,24 +1449,24 @@ class KeycloakAPI: except Exception as e: self.module.fail_json(msg=f"Could not fetch protocolmapper {cid} in realm {realm}: {e}") - def get_clientscope_protocolmapper_by_name(self, cid, name, realm: str = "master"): - """Fetch a keycloak clientscope within a realm based on its name. + def get_client_scope_protocolmapper_by_name(self, cid, name, realm: str = "master"): + """Fetch a keycloak client scope within a realm based on its name. - The Keycloak API does not allow filtering of the clientscopes resource by name. - As a result, this method first retrieves the entire list of clientscopes - name and ID - + The Keycloak API does not allow filtering of the client scopes resource by name. + As a result, this method first retrieves the entire list of client scopes - name and ID - then performs a second query to fetch the group. - If the clientscope does not exist, None is returned. - :param cid: Id of the clientscope (not name). + If the client scope does not exist, None is returned. + :param cid: Id of the client scope (not name). :param name: Name of the protocolmapper to fetch. - :param realm: Realm in which the clientscope resides; default 'master' + :param realm: Realm in which the client scope resides; default 'master' """ try: - all_protocolmappers = self.get_clientscope_protocolmappers(cid, realm=realm) + all_protocolmappers = self.get_client_scope_protocolmappers(cid, realm=realm) for protocolmapper in all_protocolmappers: if protocolmapper["name"] == name: - return self.get_clientscope_protocolmapper_by_protocolmapperid( + return self.get_client_scope_protocolmapper_by_protocolmapperid( protocolmapper["id"], cid, realm=realm ) @@ -1475,27 +1475,27 @@ class KeycloakAPI: except Exception as e: self.module.fail_json(msg=f"Could not fetch protocolmapper {name} in realm {realm}: {e}") - def create_clientscope_protocolmapper(self, cid, mapper_rep, realm: str = "master"): - """Create a Keycloak clientscope protocolmapper. + def create_client_scope_protocolmapper(self, cid, mapper_rep, realm: str = "master"): + """Create a Keycloak client scope protocolmapper. - :param cid: Id of the clientscope. + :param cid: Id of the client scope. :param mapper_rep: a ProtocolMapperRepresentation of the protocolmapper to be created. Must contain at minimum the field name. :return: HTTPResponse object on success """ - protocolmappers_url = URL_CLIENTSCOPE_PROTOCOLMAPPERS.format(url=self.baseurl, id=cid, realm=realm) + protocolmappers_url = URL_CLIENT_SCOPE_PROTOCOLMAPPERS.format(url=self.baseurl, id=cid, realm=realm) try: return self._request(protocolmappers_url, method="POST", data=json.dumps(mapper_rep)) except Exception as e: self.fail_request(e, msg=f"Could not create protocolmapper {mapper_rep['name']} in realm {realm}: {e}") - def update_clientscope_protocolmappers(self, cid, mapper_rep, realm: str = "master"): - """Update an existing clientscope. + def update_client_scope_protocolmappers(self, cid, mapper_rep, realm: str = "master"): + """Update an existing client scope. - :param cid: Id of the clientscope. + :param cid: Id of the client scope. :param mapper_rep: A ProtocolMapperRepresentation of the updated protocolmapper. :return HTTPResponse object on success """ - protocolmapper_url = URL_CLIENTSCOPE_PROTOCOLMAPPER.format( + protocolmapper_url = URL_CLIENT_SCOPE_PROTOCOLMAPPER.format( url=self.baseurl, realm=realm, id=cid, mapper_id=mapper_rep["id"] ) @@ -1504,137 +1504,137 @@ class KeycloakAPI: except Exception as e: self.fail_request( - e, msg=f"Could not update protocolmappers for clientscope {mapper_rep} in realm {realm}: {e}" + e, msg=f"Could not update protocolmappers for client scope {mapper_rep} in realm {realm}: {e}" ) - def get_default_clientscopes(self, realm, client_id=None): - """Fetch the name and ID of all clientscopes on the Keycloak server. + def get_default_client_scopes(self, realm, client_id=None): + """Fetch the name and ID of all client scopes on the Keycloak server. To fetch the full data of the client scope, make a subsequent call to - get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return. + get_client_scope_by_client_scopeid, passing in the ID of the client scope you wish to return. - :param realm: Realm in which the clientscope resides. - :param client_id: The client in which the clientscope resides. - :return The default clientscopes of this realm or client + :param realm: Realm in which the client scope resides. + :param client_id: The client in which the client scope resides. + :return The default client scopes of this realm or client """ - url = URL_DEFAULT_CLIENTSCOPES if client_id is None else URL_CLIENT_DEFAULT_CLIENTSCOPES - return self._get_clientscopes_of_type(realm, url, "default", client_id) + url = URL_DEFAULT_CLIENT_SCOPES if client_id is None else URL_CLIENT_DEFAULT_CLIENT_SCOPES + return self._get_client_scopes_of_type(realm, url, "default", client_id) - def get_optional_clientscopes(self, realm, client_id=None): - """Fetch the name and ID of all clientscopes on the Keycloak server. + def get_optional_client_scopes(self, realm, client_id=None): + """Fetch the name and ID of all client scopes on the Keycloak server. To fetch the full data of the client scope, make a subsequent call to - get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return. + get_client_scope_by_client_scopeid, passing in the ID of the client scope you wish to return. - :param realm: Realm in which the clientscope resides. - :param client_id: The client in which the clientscope resides. - :return The optional clientscopes of this realm or client + :param realm: Realm in which the client scope resides. + :param client_id: The client in which the client scope resides. + :return The optional client scopes of this realm or client """ - url = URL_OPTIONAL_CLIENTSCOPES if client_id is None else URL_CLIENT_OPTIONAL_CLIENTSCOPES - return self._get_clientscopes_of_type(realm, url, "optional", client_id) + url = URL_OPTIONAL_CLIENT_SCOPES if client_id is None else URL_CLIENT_OPTIONAL_CLIENT_SCOPES + return self._get_client_scopes_of_type(realm, url, "optional", client_id) - def _get_clientscopes_of_type(self, realm, url_template, scope_type, client_id=None): - """Fetch the name and ID of all clientscopes on the Keycloak server. + def _get_client_scopes_of_type(self, realm, url_template, scope_type, client_id=None): + """Fetch the name and ID of all client scopes on the Keycloak server. To fetch the full data of the client scope, make a subsequent call to - get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return. + get_client_scope_by_client_scopeid, passing in the ID of the client scope you wish to return. - :param realm: Realm in which the clientscope resides. + :param realm: Realm in which the client scope resides. :param url_template the template for the right type :param scope_type this can be either optional or default - :param client_id: The client in which the clientscope resides. - :return The clientscopes of the specified type of this realm + :param client_id: The client in which the client scope resides. + :return The client scopes of the specified type of this realm """ if client_id is None: - clientscopes_url = url_template.format(url=self.baseurl, realm=realm) + client_scopes_url = url_template.format(url=self.baseurl, realm=realm) try: - return self._request_and_deserialize(clientscopes_url, method="GET") + return self._request_and_deserialize(client_scopes_url, method="GET") except Exception as e: - self.fail_request(e, msg=f"Could not fetch list of {scope_type} clientscopes in realm {realm}: {e}") + self.fail_request(e, msg=f"Could not fetch list of {scope_type} client scopes in realm {realm}: {e}") else: cid = self.get_client_id(client_id=client_id, realm=realm) - clientscopes_url = url_template.format(url=self.baseurl, realm=realm, cid=cid) + client_scopes_url = url_template.format(url=self.baseurl, realm=realm, cid=cid) try: - return self._request_and_deserialize(clientscopes_url, method="GET") + return self._request_and_deserialize(client_scopes_url, method="GET") except Exception as e: self.fail_request( e, - msg=f"Could not fetch list of {scope_type} clientscopes in client {client_id}: {clientscopes_url}", + msg=f"Could not fetch list of {scope_type} client scopes in client {client_id}: {client_scopes_url}", ) - def _decide_url_type_clientscope(self, client_id=None, scope_type="default"): + def _decide_url_type_client_scope(self, client_id=None, scope_type="default"): """Decides which url to use. :param scope_type this can be either optional or default - :param client_id: The client in which the clientscope resides. + :param client_id: The client in which the client scope resides. """ if client_id is None: if scope_type == "default": - return URL_DEFAULT_CLIENTSCOPE + return URL_DEFAULT_CLIENT_SCOPE if scope_type == "optional": - return URL_OPTIONAL_CLIENTSCOPE + return URL_OPTIONAL_CLIENT_SCOPE else: if scope_type == "default": - return URL_CLIENT_DEFAULT_CLIENTSCOPE + return URL_CLIENT_DEFAULT_CLIENT_SCOPE if scope_type == "optional": - return URL_CLIENT_OPTIONAL_CLIENTSCOPE + return URL_CLIENT_OPTIONAL_CLIENT_SCOPE - def add_default_clientscope(self, id, realm: str = "master", client_id=None): + def add_default_client_scope(self, id, realm: str = "master", client_id=None): """Add a client scope as default either on realm or client level. :param id: Client scope Id. - :param realm: Realm in which the clientscope resides. - :param client_id: The client in which the clientscope resides. + :param realm: Realm in which the client scope resides. + :param client_id: The client in which the client scope resides. """ - self._action_type_clientscope(id, client_id, "default", realm, "add") + self._action_type_client_scope(id, client_id, "default", realm, "add") - def add_optional_clientscope(self, id, realm: str = "master", client_id=None): + def add_optional_client_scope(self, id, realm: str = "master", client_id=None): """Add a client scope as optional either on realm or client level. :param id: Client scope Id. - :param realm: Realm in which the clientscope resides. - :param client_id: The client in which the clientscope resides. + :param realm: Realm in which the client scope resides. + :param client_id: The client in which the client scope resides. """ - self._action_type_clientscope(id, client_id, "optional", realm, "add") + self._action_type_client_scope(id, client_id, "optional", realm, "add") - def delete_default_clientscope(self, id, realm: str = "master", client_id=None): + def delete_default_client_scope(self, id, realm: str = "master", client_id=None): """Remove a client scope as default either on realm or client level. :param id: Client scope Id. - :param realm: Realm in which the clientscope resides. - :param client_id: The client in which the clientscope resides. + :param realm: Realm in which the client scope resides. + :param client_id: The client in which the client scope resides. """ - self._action_type_clientscope(id, client_id, "default", realm, "delete") + self._action_type_client_scope(id, client_id, "default", realm, "delete") - def delete_optional_clientscope(self, id, realm: str = "master", client_id=None): + def delete_optional_client_scope(self, id, realm: str = "master", client_id=None): """Remove a client scope as optional either on realm or client level. :param id: Client scope Id. - :param realm: Realm in which the clientscope resides. - :param client_id: The client in which the clientscope resides. + :param realm: Realm in which the client scope resides. + :param client_id: The client in which the client scope resides. """ - self._action_type_clientscope(id, client_id, "optional", realm, "delete") + self._action_type_client_scope(id, client_id, "optional", realm, "delete") - def _action_type_clientscope( + def _action_type_client_scope( self, id=None, client_id=None, scope_type="default", realm: str = "master", action="add" ): - """Delete or add a clientscope of type. - :param name: The name of the clientscope. A lookup will be performed to retrieve the clientscope ID. - :param client_id: The ID of the clientscope (preferred to name). + """Delete or add a client scope of type. + :param name: The name of the client scope. A lookup will be performed to retrieve the client scope ID. + :param client_id: The ID of the client scope (preferred to name). :param scope_type 'default' or 'optional' :param realm: The realm in which this group resides, default "master". """ cid = None if client_id is None else self.get_client_id(client_id=client_id, realm=realm) # should have a good cid by here. - clientscope_type_url = self._decide_url_type_clientscope(client_id, scope_type).format( + client_scope_type_url = self._decide_url_type_client_scope(client_id, scope_type).format( realm=realm, id=id, cid=cid, url=self.baseurl ) try: method = "PUT" if action == "add" else "DELETE" - return self._request(clientscope_type_url, method=method) + return self._request(client_scope_type_url, method=method) except Exception as e: place = "realm" if client_id is None else f"client {client_id}" - self.fail_request(e, msg=f"Unable to {action} {scope_type} clientscope {id} @ {place} : {e}") + self.fail_request(e, msg=f"Unable to {action} {scope_type} client_scope {id} @ {place} : {e}") def create_clientsecret(self, id, realm: str = "master"): """Generate a new client secret by id @@ -3259,77 +3259,77 @@ class KeycloakAPI: except Exception: return False - def get_all_clientscope_scope_mappings(self, clientscope_id, realm: str = "master"): - """Fetch all (realm and client) roles (scope-mappings) associated with the clientscope for a specific clientscope on the Keycloak server. - :param clientscope_id: ID of the clientscope from which to obtain the associated roles. + def get_all_client_scope_scope_mappings(self, client_scope_id, realm: str = "master"): + """Fetch all (realm and client) roles (scope-mappings) associated with the client scope for a specific client scope on the Keycloak server. + :param client_scope_id: ID of the client scope from which to obtain the associated roles. :param realm: Realm from which to obtain the scope. - :return: The clientscope scope-mappings. + :return: The client scope scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS.format(url=self.baseurl, realm=realm, id=clientscope_id) + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS.format(url=self.baseurl, realm=realm, id=client_scope_id) try: return self._request_and_deserialize(client_role_scope_url, method="GET") except Exception as e: - self.fail_request(e, msg=f"Could not fetch roles for client-scope {clientscope_id} in realm {realm}: {e}") + self.fail_request(e, msg=f"Could not fetch roles for client-scope {client_scope_id} in realm {realm}: {e}") - def get_clientscope_scope_mappings_realm(self, clientscope_id, realm: str = "master"): - """Fetch the realm roles (scope-mappings) associated with the clientscope for a specific clientscope on the Keycloak server. - :param clientscope_id: ID of the clientscope from which to obtain the associated roles. + def get_client_scope_scope_mappings_realm(self, client_scope_id, realm: str = "master"): + """Fetch the realm roles (scope-mappings) associated with the client scope for a specific client scope on the Keycloak server. + :param client_scope_id: ID of the client scope from which to obtain the associated roles. :param realm: Realm from which to obtain the scope. - :return: The clientscope realm scope-mappings. + :return: The client scope realm scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS_REALM.format( - url=self.baseurl, realm=realm, id=clientscope_id + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS_REALM.format( + url=self.baseurl, realm=realm, id=client_scope_id ) try: return self._request_and_deserialize(client_role_scope_url, method="GET") except Exception as e: self.fail_request( - e, msg=f"Could not fetch realm roles for client-scope {clientscope_id} in realm {realm}: {e}" + e, msg=f"Could not fetch realm roles for client-scope {client_scope_id} in realm {realm}: {e}" ) - def get_clientscope_scope_mappings_client(self, clientscope_id, client_id, realm: str = "master"): - """Fetch the client roles (scope-mappings) associated with the clientscope for a specific clientscope and client on the Keycloak server. - :param clientscope_id: ID of the clientscope from which to obtain the associated roles. + def get_client_scope_scope_mappings_client(self, client_scope_id, client_id, realm: str = "master"): + """Fetch the client roles (scope-mappings) associated with the client scope for a specific client scope and client on the Keycloak server. + :param client_scope_id: ID of the client scope from which to obtain the associated roles. :param clientid: ID of the client from which to obtain the associated roles. :param realm: Realm from which to obtain the scope. - :return: The clientscope client scope-mappings. + :return: The client scope client scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS_CLIENT.format( - url=self.baseurl, realm=realm, id=clientscope_id, client=client_id + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS_CLIENT.format( + url=self.baseurl, realm=realm, id=client_scope_id, client=client_id ) try: return self._request_and_deserialize(client_role_scope_url, method="GET") except Exception as e: self.fail_request( e, - msg=f"Could not fetch client roles from client {client_id} for client-scope {clientscope_id} in realm {realm}: {e}", + msg=f"Could not fetch client roles from client {client_id} for client-scope {client_scope_id} in realm {realm}: {e}", ) - def get_client_role_scope_from_client(self, clientid, clientscopeid, realm: str = "master"): + def get_client_role_scope_from_client(self, clientid, client_scopeid, realm: str = "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 client_scopeid: 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 + url=self.baseurl, realm=realm, id=clientid, scopeid=client_scopeid ) try: return self._request_and_deserialize(client_role_scope_url, method="GET") except Exception as e: self.fail_request(e, msg=f"Could not fetch roles scope for client {clientid} in realm {realm}: {e}") - def update_client_role_scope_from_client(self, payload, clientid, clientscopeid, realm: str = "master"): + def update_client_role_scope_from_client(self, payload, clientid, client_scopeid, realm: str = "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 client_scopeid: 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 + url=self.baseurl, realm=realm, id=clientid, scopeid=client_scopeid ) try: self._request(client_role_scope_url, method="POST", data=json.dumps(payload)) @@ -3337,18 +3337,18 @@ class KeycloakAPI: except Exception as e: self.fail_request(e, msg=f"Could not update roles scope for client {clientid} in realm {realm}: {e}") - return self.get_client_role_scope_from_client(clientid, clientscopeid, realm) + return self.get_client_role_scope_from_client(clientid, client_scopeid, realm) - def delete_client_role_scope_from_client(self, payload, clientid, clientscopeid, realm: str = "master"): + def delete_client_role_scope_from_client(self, payload, clientid, client_scopeid, realm: str = "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 client_scopeid: 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 + url=self.baseurl, realm=realm, id=clientid, scopeid=client_scopeid ) try: self._request(client_role_scope_url, method="DELETE", data=json.dumps(payload)) @@ -3356,20 +3356,20 @@ class KeycloakAPI: except Exception as e: self.fail_request(e, msg=f"Could not delete roles scope for client {clientid} in realm {realm}: {e}") - return self.get_client_role_scope_from_client(clientid, clientscopeid, realm) + return self.get_client_role_scope_from_client(clientid, client_scopeid, realm) - def update_clientscope_scope_mappings_client( - self, payload: list[dict], clientscope_id: str, client_id: str, realm: str = "master" + def update_client_scope_scope_mappings_client( + self, payload: list[dict], client_scope_id: str, client_id: str, realm: str = "master" ): - """Update and fetch the client roles (scope-mappings) associated with the clientscope on the Keycloak server. + """Update and fetch the client roles (scope-mappings) associated with the client scope on the Keycloak server. :param payload: List of client roles to be added to the scope. - :param clientscope_id: ID of the clientscope to update scope-mappings. + :param client_scope_id: ID of the client scope to update scope-mappings. :param clientid: ID of the client from which to obtain the associated roles. :param realm: Realm from which to obtain the client. - :return: The clientscope client scope-mappings. + :return: The client scope client scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS_CLIENT.format( - url=self.baseurl, realm=realm, id=clientscope_id, client=client_id + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS_CLIENT.format( + url=self.baseurl, realm=realm, id=client_scope_id, client=client_id ) try: self._request(client_role_scope_url, method="POST", data=json.dumps(payload)) @@ -3377,43 +3377,43 @@ class KeycloakAPI: except Exception as e: self.fail_request( e, - msg=f"Could not update scope mappings for client-scope {client_id}.{clientscope_id} in realm {realm}: {e}", + msg=f"Could not update scope mappings for client-scope {client_id}.{client_scope_id} in realm {realm}: {e}", ) - return self.get_clientscope_scope_mappings_client(clientscope_id, client_id, realm) + return self.get_client_scope_scope_mappings_client(client_scope_id, client_id, realm) - def update_clientscope_scope_mappings_realm(self, payload: list[dict], clientscope_id: str, realm: str = "master"): - """Update and fetch the realm roles (scope-mappings) associated with the clientscope on the Keycloak server. + def update_client_scope_scope_mappings_realm(self, payload: list[dict], client_scope_id: str, realm: str = "master"): + """Update and fetch the realm roles (scope-mappings) associated with the client scope on the Keycloak server. :param payload: List of realm roles to be added to the scope. - :param clientscope_id: ID of the clientscope to update scope-mappings. + :param client_scope_id: ID of the client scope to update scope-mappings. :param realm: Realm from which to obtain the roles. - :return: The clientscope realm scope-mappings. + :return: The client scope realm scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS_REALM.format( - url=self.baseurl, realm=realm, id=clientscope_id + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS_REALM.format( + url=self.baseurl, realm=realm, id=client_scope_id ) try: self._request(client_role_scope_url, method="POST", data=json.dumps(payload)) except Exception as e: self.fail_request( - e, msg=f"Could not update scope mappings for client-scope {clientscope_id} in realm {realm}: {e}" + e, msg=f"Could not update scope mappings for client scope {client_scope_id} in realm {realm}: {e}" ) - return self.get_clientscope_scope_mappings_realm(clientscope_id, realm) + return self.get_client_scope_scope_mappings_realm(client_scope_id, realm) - def delete_clientscope_scope_mappings_client( - self, payload: list[dict], clientscope_id: str, client_id: str, realm: str = "master" + def delete_client_scope_scope_mappings_client( + self, payload: list[dict], client_scope_id: str, client_id: str, realm: str = "master" ): - """Delete the client roles (scope_mappings) contained in the payload from the clientscope on the Keycloak server. + """Delete the client roles (scope_mappings) contained in the payload from the client scope on the Keycloak server. :param payload: List of roles to be deleted. - :param clientscope_id: ID of the clientscope to delete roles from scope-mappings. + :param client_scope_id: ID of the client scope to delete roles from scope-mappings. :param clientid: ID of the client who owns the roles. :param realm: Realm from which to obtain the client. - :return: The clientscope client scope-mappings. + :return: The client scope client scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS_CLIENT.format( - url=self.baseurl, realm=realm, id=clientscope_id, client=client_id + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS_CLIENT.format( + url=self.baseurl, realm=realm, id=client_scope_id, client=client_id ) try: self._request(client_role_scope_url, method="DELETE", data=json.dumps(payload)) @@ -3421,30 +3421,30 @@ class KeycloakAPI: except Exception as e: self.fail_request( e, - msg=f"Could not delete scope mappings for client-scope {client_id}.{clientscope_id} in realm {realm}: {e}", + msg=f"Could not delete scope mappings for client scope {client_id}.{client_scope_id} in realm {realm}: {e}", ) - return self.get_clientscope_scope_mappings_client(clientscope_id, client_id, realm) + return self.get_client_scope_scope_mappings_client(client_scope_id, client_id, realm) - def delete_clientscope_scope_mappings_realm(self, payload: list[dict], clientscope_id: str, realm: str = "master"): - """Delete the realm roles (scope_mappings) contained in the payload from the clientscope on the Keycloak server. + def delete_client_scope_scope_mappings_realm(self, payload: list[dict], client_scope_id: str, realm: str = "master"): + """Delete the realm roles (scope_mappings) contained in the payload from the client scope on the Keycloak server. :param payload: List of roles to be deleted. - :param clientscope_id: ID of the clientscope to delete roles from scope-mappings. + :param client_scope_id: ID of the client scope to delete roles from scope-mappings. :param realm: Realm from which to obtain the roles. - :return: The clientscope realm scope-mappings. + :return: The client scope realm scope-mappings. """ - client_role_scope_url = URL_CLIENTSCOPE_SCOPE_MAPPINGS_REALM.format( - url=self.baseurl, realm=realm, id=clientscope_id + client_role_scope_url = URL_CLIENT_SCOPE_SCOPE_MAPPINGS_REALM.format( + url=self.baseurl, realm=realm, id=client_scope_id ) try: self._request(client_role_scope_url, method="DELETE", data=json.dumps(payload)) except Exception as e: self.fail_request( - e, msg=f"Could not delete scope mappings for client-scope {clientscope_id} in realm {realm}: {e}" + e, msg=f"Could not delete scope mappings for client-scope {client_scope_id} in realm {realm}: {e}" ) - return self.get_clientscope_scope_mappings_realm(clientscope_id, realm) + return self.get_client_scope_scope_mappings_realm(client_scope_id, realm) def get_client_role_scope_from_realm(self, clientid, realm: str = "master"): """Fetch the realm roles from the client's scope on the Keycloak server. diff --git a/plugins/modules/keycloak_client.py b/plugins/modules/keycloak_client.py index 9a15881..0407a13 100644 --- a/plugins/modules/keycloak_client.py +++ b/plugins/modules/keycloak_client.py @@ -1100,11 +1100,11 @@ def add_default_client_scopes(desired_client, before_client, realm, kc): missing_scopes = [item for item in desired_default_scope if item not in before_client["defaultClientScopes"]] if not missing_scopes: return - client_scopes = kc.get_clientscopes(realm) + client_scopes = kc.get_client_scopes(realm) for name in missing_scopes: scope = find_match(client_scopes, "name", name) if scope: - kc.add_default_clientscope(scope["id"], realm, desired_client["clientId"]) + kc.add_default_client_scope(scope["id"], realm, desired_client["clientId"]) def add_optional_client_scopes(desired_client, before_client, realm, kc): @@ -1139,11 +1139,11 @@ def add_optional_client_scopes(desired_client, before_client, realm, kc): missing_scopes = [item for item in desired_optional_scope if item not in before_client["optionalClientScopes"]] if not missing_scopes: return - client_scopes = kc.get_clientscopes(realm) + client_scopes = kc.get_client_scopes(realm) for name in missing_scopes: scope = find_match(client_scopes, "name", name) if scope: - kc.add_optional_clientscope(scope["id"], realm, desired_client["clientId"]) + kc.add_optional_client_scope(scope["id"], realm, desired_client["clientId"]) def remove_default_client_scopes(desired_client, before_client, realm, kc): @@ -1178,11 +1178,11 @@ def remove_default_client_scopes(desired_client, before_client, realm, kc): missing_scopes = [item for item in before_default_scope if item not in desired_client["defaultClientScopes"]] if not missing_scopes: return - client_scopes = kc.get_default_clientscopes(realm, desired_client["clientId"]) + client_scopes = kc.get_default_client_scopes(realm, desired_client["clientId"]) for name in missing_scopes: scope = find_match(client_scopes, "name", name) if scope: - kc.delete_default_clientscope(scope["id"], realm, desired_client["clientId"]) + kc.delete_default_client_scope(scope["id"], realm, desired_client["clientId"]) def remove_optional_client_scopes(desired_client, before_client, realm, kc): @@ -1217,11 +1217,11 @@ def remove_optional_client_scopes(desired_client, before_client, realm, kc): missing_scopes = [item for item in before_optional_scope if item not in desired_client["optionalClientScopes"]] if not missing_scopes: return - client_scopes = kc.get_optional_clientscopes(realm, desired_client["clientId"]) + client_scopes = kc.get_optional_client_scopes(realm, desired_client["clientId"]) for name in missing_scopes: scope = find_match(client_scopes, "name", name) if scope: - kc.delete_optional_clientscope(scope["id"], realm, desired_client["clientId"]) + kc.delete_optional_client_scope(scope["id"], realm, desired_client["clientId"]) def main(): diff --git a/plugins/modules/keycloak_client_scope.py b/plugins/modules/keycloak_client_scope.py index 35723c9..b2dfccd 100644 --- a/plugins/modules/keycloak_client_scope.py +++ b/plugins/modules/keycloak_client_scope.py @@ -230,7 +230,7 @@ def main(): attributes = module.params.get('attributes') protocol_mappers = module.params.get('protocol_mappers') - before_scope = kc.get_clientscope_by_name(name, realm=realm) + before_scope = kc.get_client_scope_by_name(name, realm=realm) if state == 'absent': if before_scope: @@ -239,7 +239,7 @@ def main(): result['diff'] = dict(before=before_scope, after='') if module.check_mode: module.exit_json(**result) - kc.delete_clientscope(cid=before_scope['id'], realm=realm) + kc.delete_client_scope(cid=before_scope['id'], realm=realm) result['msg'] = "Client scope {name} has been deleted".format(name=name) else: result['msg'] = "Client scope {name} does not exist, doing nothing".format(name=name) @@ -261,8 +261,8 @@ def main(): if module.check_mode: module.exit_json(**result) - kc.create_clientscope(scope_rep, realm=realm) - after_scope = kc.get_clientscope_by_name(name, realm=realm) + kc.create_client_scope(scope_rep, realm=realm) + after_scope = kc.get_client_scope_by_name(name, realm=realm) if protocol_mappers: for mapper in protocol_mappers: @@ -272,8 +272,8 @@ def main(): 'protocolMapper': mapper['protocolMapper'], 'config': mapper['config'], } - kc.create_clientscope_protocolmapper(after_scope['id'], mapper_rep, realm=realm) - after_scope = kc.get_clientscope_by_name(name, realm=realm) + kc.create_client_scope_protocolmapper(after_scope['id'], mapper_rep, realm=realm) + after_scope = kc.get_client_scope_by_name(name, realm=realm) result['end_state'] = after_scope result['msg'] = "Client scope {name} has been created".format(name=name) @@ -296,10 +296,10 @@ def main(): result['diff'] = dict(before=before_scope, after=scope_rep) if module.check_mode: module.exit_json(**result) - kc.update_clientscope(scope_rep, realm=realm) + kc.update_client_scope(scope_rep, realm=realm) if protocol_mappers: - existing_mappers = kc.get_clientscope_protocolmappers(before_scope['id'], realm=realm) + existing_mappers = kc.get_client_scope_protocolmappers(before_scope['id'], realm=realm) existing_mapper_names = {m['name'] for m in existing_mappers} for mapper in protocol_mappers: @@ -312,9 +312,9 @@ def main(): 'protocolMapper': mapper['protocolMapper'], 'config': mapper['config'], } - kc.create_clientscope_protocolmapper(before_scope['id'], mapper_rep, realm=realm) + kc.create_client_scope_protocolmapper(before_scope['id'], mapper_rep, realm=realm) - after_scope = kc.get_clientscope_by_name(name, realm=realm) + after_scope = kc.get_client_scope_by_name(name, realm=realm) result['end_state'] = after_scope if result['changed']: diff --git a/plugins/modules/keycloak_clientscope_rolemappings.py b/plugins/modules/keycloak_clientscope_rolemappings.py index be89a07..a89241d 100644 --- a/plugins/modules/keycloak_clientscope_rolemappings.py +++ b/plugins/modules/keycloak_clientscope_rolemappings.py @@ -6,16 +6,16 @@ from __future__ import annotations DOCUMENTATION = r""" -module: keycloak_clientscope_rolemappings +module: keycloak_client_scope_rolemappings -short_description: Allows administration of Keycloak clientscope scope mappings to restrict the usage of certain roles to - specific clientscopes +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 clientscopes using the Keycloak REST API. It requires access + - 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. @@ -49,11 +49,11 @@ options: - The Keycloak realm under which clients resides. default: 'master' - clientscope_id: + client_scope_id: required: true type: str description: - - Roles provided in O(role_names) will be added to this clientscope. + - Roles provided in O(role_names) will be added to this client scope. client_id: type: str @@ -81,40 +81,40 @@ author: """ EXAMPLES = r""" -- name: Add roles to clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: +- 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 - clientscope_id: frontend-clientscope + client_scope_id: frontend-client-scope role_names: - backend-role-admin - backend-role-user -- name: Remove roles from clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: +- 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 - clientscope_id: frontend-clientscope + client_scope_id: frontend-client-scope role_names: - backend-role-admin state: absent -- name: Add realm roles to clientscope - middleware_automation.keycloak.keycloak_clientscope_rolemappings: +- 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 - clientscope_id: frontend-clientscope + client_scope_id: frontend-client-scope role_names: - realm-role-admin - realm-role-user @@ -122,7 +122,7 @@ EXAMPLES = r""" RETURN = r""" end_state: - description: Representation of clientscope scope mappings after module execution. + description: Representation of client scope scope mappings after module execution. returned: on success type: list elements: dict @@ -164,7 +164,7 @@ def main(): meta_args = dict( client_id=dict(type="str"), - clientscope_id=dict(type="str", required=True), + 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"]), @@ -186,7 +186,7 @@ def main(): realm = module.params["realm"] client_id = module.params["client_id"] - clientscope_id = module.params["clientscope_id"] + client_scope_id = module.params["client_scope_id"] role_names = module.params["role_names"] state = module.params["state"] @@ -194,9 +194,9 @@ def main(): if not realm_object: module.fail_json(msg=f"Failed to retrieve realm '{realm}'") - clientscope_object = kc.get_clientscope_by_name(clientscope_id, realm) - if not clientscope_object: - module.fail_json(msg=f"Failed to retrieve client-scope '{clientscope_id}'") + 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 @@ -206,11 +206,11 @@ def main(): if client_object["fullScopeAllowed"] and state == "present": module.fail_json(msg=f"FullScopeAllowed is active for Client '{realm}.{client_id}'") - before_roles = kc.get_clientscope_scope_mappings_client(clientscope_object["id"], client_object["id"], realm) + 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_clientscope_scope_mappings_realm(clientscope_object["id"], realm) + 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 @@ -248,33 +248,33 @@ def main(): if not result["changed"]: # no changes result["end_state"] = before_roles - result["msg"] = f"No changes required for clientscope {clientscope_id}." + 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_clientscope_scope_mappings_client( - changed_roles, clientscope_object["id"], client_object["id"], realm + 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_clientscope_scope_mappings_realm( - changed_roles, clientscope_object["id"], realm + result["end_state"] = kc.update_client_scope_scope_mappings_realm( + changed_roles, client_scope_object["id"], realm ) - result["msg"] = f"Clientscope scope mappings for {clientscope_id} have been updated" + 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_clientscope_scope_mappings_client( - changed_roles, clientscope_object["id"], client_object["id"], realm + 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_clientscope_scope_mappings_realm( - changed_roles, clientscope_object["id"], realm + result["end_state"] = kc.delete_client_scope_scope_mappings_realm( + changed_roles, client_scope_object["id"], realm ) - result["msg"] = f"Clientscope scope mappings for {clientscope_id} have been deleted" + result["msg"] = f"Clientscope scope mappings for {client_scope_id} have been deleted" module.exit_json(**result) diff --git a/plugins/modules/keycloak_clientscope_type.py b/plugins/modules/keycloak_clientscope_type.py index 6c467a3..00cbd05 100644 --- a/plugins/modules/keycloak_clientscope_type.py +++ b/plugins/modules/keycloak_clientscope_type.py @@ -6,15 +6,15 @@ from __future__ import annotations DOCUMENTATION = r""" -module: keycloak_clientscope_type +module: keycloak_client_scope_type -short_description: Set the type of aclientscope in realm or client using Keycloak API +short_description: Set the type of a client scope in a realm or client using the Keycloak API # Originally added in community.general 6.6.0 version_added: "3.0.0" description: - - This module allows you to set the type (optional, default) of clientscopes using the Keycloak REST API. It requires access + - This module allows you to set the type (optional, default) of 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, 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. @@ -36,18 +36,18 @@ options: client_id: description: - - The O(client_id) of the client. If not set the clientscope types are set as a default for the realm. + - The O(client_id) of the client. If not set the client scope types are set as a default for the realm. aliases: - clientId type: str - default_clientscopes: + default_client_scopes: description: - Client scopes that should be of type default. type: list elements: str - optional_clientscopes: + optional_client_scopes: description: - Client scopes that should be of type optional. type: list @@ -64,26 +64,26 @@ author: EXAMPLES = r""" - name: Set default client scopes on realm level - middleware_automation.keycloak.keycloak_clientscope_type: + middleware_automation.keycloak.keycloak_client_scope_type: auth_client_id: admin-cli auth_keycloak_url: https://auth.example.com auth_realm: master auth_username: USERNAME auth_password: PASSWORD realm: "MyCustomRealm" - default_clientscopes: ['profile', 'roles'] + default_client_scopes: ['profile', 'roles'] delegate_to: localhost - name: Set default and optional client scopes on client level with token auth - middleware_automation.keycloak.keycloak_clientscope_type: + middleware_automation.keycloak.keycloak_client_scope_type: auth_client_id: admin-cli auth_keycloak_url: https://auth.example.com token: TOKEN realm: "MyCustomRealm" client_id: "MyCustomClient" - default_clientscopes: ['profile', 'roles'] - optional_clientscopes: ['phone'] + default_client_scopes: ['profile', 'roles'] + optional_client_scopes: ['phone'] delegate_to: localhost """ @@ -99,11 +99,11 @@ proposed: type: dict sample: { - "default_clientscopes": [ + "default_client_scopes": [ "profile", "role" ], - "optional_clientscopes": [] + "optional_client_scopes": [] } existing: description: @@ -112,11 +112,11 @@ existing: type: dict sample: { - "default_clientscopes": [ + "default_client_scopes": [ "profile", "role" ], - "optional_clientscopes": [ + "optional_client_scopes": [ "phone" ] } @@ -128,11 +128,11 @@ end_state: type: dict sample: { - "default_clientscopes": [ + "default_client_scopes": [ "profile", "role" ], - "optional_clientscopes": [] + "optional_client_scopes": [] } """ @@ -146,7 +146,7 @@ from ansible_collections.middleware_automation.keycloak.plugins.module_utils.ide ) -def keycloak_clientscope_type_module(): +def keycloak_client_scope_type_module(): """ Returns an AnsibleModule definition. @@ -157,8 +157,8 @@ def keycloak_clientscope_type_module(): meta_args = dict( realm=dict(default="master"), client_id=dict(type="str", aliases=["clientId"]), - default_clientscopes=dict(type="list", elements="str"), - optional_clientscopes=dict(type="list", elements="str"), + default_client_scopes=dict(type="list", elements="str"), + optional_client_scopes=dict(type="list", elements="str"), ) argument_spec.update(meta_args) @@ -169,7 +169,7 @@ def keycloak_clientscope_type_module(): required_one_of=( [ ["token", "auth_realm", "auth_username", "auth_password", "auth_client_id", "auth_client_secret"], - ["default_clientscopes", "optional_clientscopes"], + ["default_client_scopes", "optional_client_scopes"], ] ), required_together=([["auth_username", "auth_password"]]), @@ -180,21 +180,21 @@ def keycloak_clientscope_type_module(): return module -def clientscopes_to_add(existing, proposed): +def client_scopes_to_add(existing, proposed): to_add = [] - existing_clientscope_ids = extract_field(existing, "id") - for clientscope in proposed: - if clientscope["id"] not in existing_clientscope_ids: - to_add.append(clientscope) + existing_client_scope_ids = extract_field(existing, "id") + for client_scope in proposed: + if client_scope["id"] not in existing_client_scope_ids: + to_add.append(client_scope) return to_add -def clientscopes_to_delete(existing, proposed): +def client_scopes_to_delete(existing, proposed): to_delete = [] - proposed_clientscope_ids = extract_field(proposed, "id") - for clientscope in existing: - if clientscope["id"] not in proposed_clientscope_ids: - to_delete.append(clientscope) + proposed_client_scope_ids = extract_field(proposed, "id") + for client_scope in existing: + if client_scope["id"] not in proposed_client_scope_ids: + to_delete.append(client_scope) return to_delete @@ -204,21 +204,21 @@ def extract_field(dictionary, field="name"): def normalize_scopes(scopes): scopes_copy = scopes.copy() - if isinstance(scopes_copy.get("default_clientscopes"), list): - scopes_copy["default_clientscopes"] = sorted(scopes_copy["default_clientscopes"]) - if isinstance(scopes_copy.get("optional_clientscopes"), list): - scopes_copy["optional_clientscopes"] = sorted(scopes_copy["optional_clientscopes"]) + if isinstance(scopes_copy.get("default_client_scopes"), list): + scopes_copy["default_client_scopes"] = sorted(scopes_copy["default_client_scopes"]) + if isinstance(scopes_copy.get("optional_client_scopes"), list): + scopes_copy["optional_client_scopes"] = sorted(scopes_copy["optional_client_scopes"]) return scopes_copy def main(): """ - Module keycloak_clientscope_type + Module keycloak_client_scope_type :return: """ - module = keycloak_clientscope_type_module() + module = keycloak_client_scope_type_module() # Obtain access token, initialize API try: @@ -230,81 +230,81 @@ def main(): realm = module.params.get("realm") client_id = module.params.get("client_id") - default_clientscopes = module.params.get("default_clientscopes") - optional_clientscopes = module.params.get("optional_clientscopes") + default_client_scopes = module.params.get("default_client_scopes") + optional_client_scopes = module.params.get("optional_client_scopes") result = dict(changed=False, msg="", proposed={}, existing={}, end_state={}) - all_clientscopes = kc.get_clientscopes(realm) - default_clientscopes_real = [] - optional_clientscopes_real = [] + all_client_scopes = kc.get_client_scopes(realm) + default_client_scopes_real = [] + optional_client_scopes_real = [] - for client_scope in all_clientscopes: - if default_clientscopes is not None and client_scope["name"] in default_clientscopes: - default_clientscopes_real.append(client_scope) - if optional_clientscopes is not None and client_scope["name"] in optional_clientscopes: - optional_clientscopes_real.append(client_scope) + for client_scope in all_client_scopes: + if default_client_scopes is not None and client_scope["name"] in default_client_scopes: + default_client_scopes_real.append(client_scope) + if optional_client_scopes is not None and client_scope["name"] in optional_client_scopes: + optional_client_scopes_real.append(client_scope) - if default_clientscopes is not None and len(default_clientscopes_real) != len(default_clientscopes): - module.fail_json(msg="At least one of the default_clientscopes does not exist!") + if default_client_scopes is not None and len(default_client_scopes_real) != len(default_client_scopes): + module.fail_json(msg="At least one of the default_client_scopes does not exist!") - if optional_clientscopes is not None and len(optional_clientscopes_real) != len(optional_clientscopes): - module.fail_json(msg="At least one of the optional_clientscopes does not exist!") + if optional_client_scopes is not None and len(optional_client_scopes_real) != len(optional_client_scopes): + module.fail_json(msg="At least one of the optional_client_scopes does not exist!") result["proposed"].update( { - "default_clientscopes": "no-change" if default_clientscopes is None else default_clientscopes, - "optional_clientscopes": "no-change" if optional_clientscopes is None else optional_clientscopes, + "default_client_scopes": "no-change" if default_client_scopes is None else default_client_scopes, + "optional_client_scopes": "no-change" if optional_client_scopes is None else optional_client_scopes, } ) - default_clientscopes_existing = kc.get_default_clientscopes(realm, client_id) - optional_clientscopes_existing = kc.get_optional_clientscopes(realm, client_id) + default_client_scopes_existing = kc.get_default_client_scopes(realm, client_id) + optional_client_scopes_existing = kc.get_optional_client_scopes(realm, client_id) result["existing"].update( { - "default_clientscopes": extract_field(default_clientscopes_existing), - "optional_clientscopes": extract_field(optional_clientscopes_existing), + "default_client_scopes": extract_field(default_client_scopes_existing), + "optional_client_scopes": extract_field(optional_client_scopes_existing), } ) if module._diff: result["diff"] = dict(before=normalize_scopes(result["existing"]), after=normalize_scopes(result["proposed"])) - default_clientscopes_add = clientscopes_to_add(default_clientscopes_existing, default_clientscopes_real) - optional_clientscopes_add = clientscopes_to_add(optional_clientscopes_existing, optional_clientscopes_real) + default_client_scopes_add = client_scopes_to_add(default_client_scopees_existing, defaultclient_scopees_real) + optional_client_scopes_add = client_scopes_to_add(optional_client_scopes_existing, optional_client_scopes_real) - default_clientscopes_delete = clientscopes_to_delete(default_clientscopes_existing, default_clientscopes_real) - optional_clientscopes_delete = clientscopes_to_delete(optional_clientscopes_existing, optional_clientscopes_real) + default_client_scopes_delete = client_scopes_to_delete(default_client_scopes_existing, default_client_scopes_real) + optional_client_scopes_delete = client_scopes_to_delete(optional_client_scopes_existing, optional_client_scopes_real) result["changed"] = any( len(x) > 0 for x in [ - default_clientscopes_add, - optional_clientscopes_add, - default_clientscopes_delete, - optional_clientscopes_delete, + default_client_scopes_add, + optional_client_scopes_add, + default_client_scopes_delete, + optional_client_scopes_delete, ] ) if module.check_mode: module.exit_json(**result) - # first delete so clientscopes can change type - for clientscope in default_clientscopes_delete: - kc.delete_default_clientscope(clientscope["id"], realm, client_id) - for clientscope in optional_clientscopes_delete: - kc.delete_optional_clientscope(clientscope["id"], realm, client_id) + # first delete so client_scopes can change type + for client_scope in default_client_scopes_delete: + kc.delete_default_client_scope(client_scope["id"], realm, client_id) + for client_scope in optional_client_scopes_delete: + kc.delete_optional_client_scope(client_scope["id"], realm, client_id) - for clientscope in default_clientscopes_add: - kc.add_default_clientscope(clientscope["id"], realm, client_id) - for clientscope in optional_clientscopes_add: - kc.add_optional_clientscope(clientscope["id"], realm, client_id) + for client_scope in default_client_scopes_add: + kc.add_default_client_scope(client_scope["id"], realm, client_id) + for client_scope in optional_client_scopes_add: + kc.add_optional_client_scope(client_scope["id"], realm, client_id) result["end_state"].update( { - "default_clientscopes": extract_field(kc.get_default_clientscopes(realm, client_id)), - "optional_clientscopes": extract_field(kc.get_optional_clientscopes(realm, client_id)), + "default_client_scopes": extract_field(kc.get_default_client_scopes(realm, client_id)), + "optional_client_scopes": extract_field(kc.get_optional_client_scopes(realm, client_id)), } )