#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (c) 2021, Florian Dambrine # 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: pritunl_user author: "Florian Dambrine (@Lowess)" version_added: 2.3.0 short_description: Manage Pritunl Users using the Pritunl API description: - A module to manage Pritunl users using the Pritunl API. extends_documentation_fragment: - community.general.pritunl - community.general.attributes attributes: check_mode: support: none diff_mode: support: none options: organization: type: str required: true aliases: - org description: - The name of the organization the user is part of. state: type: str default: 'present' choices: - present - absent description: - If C(present), the module adds user I(user_name) to the Pritunl I(organization). If C(absent), removes the user I(user_name) from the Pritunl I(organization). user_name: type: str required: true default: null description: - Name of the user to create or delete from Pritunl. user_email: type: str required: false default: null description: - Email address associated with the user I(user_name). user_type: type: str required: false default: client choices: - client - server description: - Type of the user I(user_name). user_groups: type: list elements: str required: false default: null description: - List of groups associated with the user I(user_name). user_disabled: type: bool required: false default: null description: - Enable/Disable the user I(user_name). user_gravatar: type: bool required: false default: null description: - Enable/Disable Gravatar usage for the user I(user_name). user_mac_addresses: type: list elements: str description: - Allowed MAC addresses for the user I(user_name). version_added: 5.0.0 """ EXAMPLES = """ - name: Create the user Foo with email address foo@bar.com in MyOrg community.general.pritunl_user: state: present organization: MyOrg user_name: Foo user_email: foo@bar.com user_mac_addresses: - "00:00:00:00:00:99" - name: Disable the user Foo but keep it in Pritunl community.general.pritunl_user: state: present organization: MyOrg user_name: Foo user_email: foo@bar.com user_disabled: true - name: Make sure the user Foo is not part of MyOrg anymore community.general.pritunl_user: state: absent organization: MyOrg user_name: Foo """ RETURN = """ response: description: JSON representation of Pritunl Users. returned: success type: dict sample: { "audit": false, "auth_type": "google", "bypass_secondary": false, "client_to_client": false, "disabled": false, "dns_mapping": null, "dns_servers": null, "dns_suffix": null, "email": "foo@bar.com", "gravatar": true, "groups": [ "foo", "bar" ], "id": "5d070dafe63q3b2e6s472c3b", "name": "foo@acme.com", "network_links": [], "organization": "58070daee6sf342e6e4s2c36", "organization_name": "Acme", "otp_auth": true, "otp_secret": "35H5EJA3XB2$4CWG", "pin": false, "port_forwarding": [], "servers": [], } """ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.dict_transformations import dict_merge from ansible_collections.community.general.plugins.module_utils.net_tools.pritunl.api import ( PritunlException, delete_pritunl_user, get_pritunl_settings, list_pritunl_organizations, list_pritunl_users, post_pritunl_user, pritunl_argument_spec, ) def add_or_update_pritunl_user(module): result = {} org_name = module.params.get("organization") user_name = module.params.get("user_name") user_params = { "name": user_name, "email": module.params.get("user_email"), "groups": module.params.get("user_groups"), "disabled": module.params.get("user_disabled"), "gravatar": module.params.get("user_gravatar"), "mac_addresses": module.params.get("user_mac_addresses"), "type": module.params.get("user_type"), } org_obj_list = list_pritunl_organizations( **dict_merge( get_pritunl_settings(module), {"filters": {"name": org_name}}, ) ) if len(org_obj_list) == 0: module.fail_json( msg="Can not add user to organization '%s' which does not exist" % org_name ) org_id = org_obj_list[0]["id"] # Grab existing users from this org users = list_pritunl_users( **dict_merge( get_pritunl_settings(module), { "organization_id": org_id, "filters": {"name": user_name}, }, ) ) # Check if the pritunl user already exists if len(users) > 0: # Compare remote user params with local user_params and trigger update if needed user_params_changed = False for key in user_params.keys(): # When a param is not specified grab existing ones to prevent from changing it with the PUT request if user_params[key] is None: user_params[key] = users[0][key] # 'groups' and 'mac_addresses' are list comparison if key == "groups" or key == "mac_addresses": if set(users[0][key]) != set(user_params[key]): user_params_changed = True # otherwise it is either a boolean or a string else: if users[0][key] != user_params[key]: user_params_changed = True # Trigger a PUT on the API to update the current user if settings have changed if user_params_changed: response = post_pritunl_user( **dict_merge( get_pritunl_settings(module), { "organization_id": org_id, "user_id": users[0]["id"], "user_data": user_params, }, ) ) result["changed"] = True result["response"] = response else: result["changed"] = False result["response"] = users else: response = post_pritunl_user( **dict_merge( get_pritunl_settings(module), { "organization_id": org_id, "user_data": user_params, }, ) ) result["changed"] = True result["response"] = response module.exit_json(**result) def remove_pritunl_user(module): result = {} org_name = module.params.get("organization") user_name = module.params.get("user_name") org_obj_list = [] org_obj_list = list_pritunl_organizations( **dict_merge( get_pritunl_settings(module), { "filters": {"name": org_name}, }, ) ) if len(org_obj_list) == 0: module.fail_json( msg="Can not remove user '%s' from a non existing organization '%s'" % (user_name, org_name) ) org_id = org_obj_list[0]["id"] # Grab existing users from this org users = list_pritunl_users( **dict_merge( get_pritunl_settings(module), { "organization_id": org_id, "filters": {"name": user_name}, }, ) ) # Check if the pritunl user exists, if not, do nothing if len(users) == 0: result["changed"] = False result["response"] = {} # Otherwise remove the org from Pritunl else: response = delete_pritunl_user( **dict_merge( get_pritunl_settings(module), { "organization_id": org_id, "user_id": users[0]["id"], }, ) ) result["changed"] = True result["response"] = response module.exit_json(**result) def main(): argument_spec = pritunl_argument_spec() argument_spec.update( dict( organization=dict(required=True, type="str", aliases=["org"]), state=dict( required=False, choices=["present", "absent"], default="present" ), user_name=dict(required=True, type="str"), user_type=dict( required=False, choices=["client", "server"], default="client" ), user_email=dict(required=False, type="str", default=None), user_groups=dict(required=False, type="list", elements="str", default=None), user_disabled=dict(required=False, type="bool", default=None), user_gravatar=dict(required=False, type="bool", default=None), user_mac_addresses=dict(required=False, type="list", elements="str", default=None), ) ) module = AnsibleModule(argument_spec=argument_spec) state = module.params.get("state") try: if state == "present": add_or_update_pritunl_user(module) elif state == "absent": remove_pritunl_user(module) except PritunlException as e: module.fail_json(msg=to_native(e)) if __name__ == "__main__": main()