#!/usr/bin/python # Copyright: (c) 2017, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} DOCUMENTATION = ''' --- module: cyberark_user short_description: Module for CyberArk User Management using PAS Web Services SDK author: Edward Nunez @ CyberArk BizDev (@enunez-cyberark, @cyberark-bizdev, @erasmix) version_added: 2.4 description: - CyberArk User Management using PAS Web Services SDK. It currently supports the following actions Get User Details, Add User, Update User, Delete User. options: username: required: True description: - The name of the user who will be queried (for details), added, updated or deleted. state: default: present choices: [present, absent] description: - Specifies the state needed for the user present for create user, absent for delete user. cyberark_session: required: True description: - Dictionary set by a CyberArk authentication containing the different values to perform actions on a logged-on CyberArk session, please see M(cyberark_authentication) module for an example of cyberark_session. initial_password: description: - The password that the new user will use to log on the first time. This password must meet the password policy requirements. this parameter is required when state is present -- Add User. new_password: description: - The user updated password. Make sure that this password meets the password policy requirements. email: description: - The user email address. first_name: description: - The user first name. last_name: description: - The user last name. change_password_on_the_next_logon: type: bool default: 'no' description: - Whether or not the user must change their password in their next logon. Valid values = true/false. expiry_date: description: - The date and time when the user account will expire and become disabled. user_type_name: default: EPVUser description: - The type of user. disabled: type: bool default: 'no' description: - Whether or not the user will be disabled. Valid values = true/false. location: description: - The Vault Location for the user. group_name: description: - The name of the group the user will be added to. ''' EXAMPLES = ''' - name: Logon to CyberArk Vault using PAS Web Services SDK cyberark_authentication: api_base_url: "https://components.cyberark.local" use_shared_logon_authentication: true - name: Create user & immediately add it to a group cyberark_user: username: "username" initial_password: "password" user_type_name: "EPVUser" change_password_on_the_next_logon: false group_name: "GroupOfUsers" state: present cyberark_session: "{{ cyberark_session }}" - name: Make sure user is present and reset user credential if present cyberark_user: username: "Username" new_password: "password" disabled: false state: present cyberark_session: "{{ cyberark_session }}" - name: Logoff from CyberArk Vault cyberark_authentication: state: absent cyberark_session: "{{ cyberark_session }}" ''' RETURN = ''' changed: description: Whether there was a change done. type: bool returned: always cyberark_user: description: Dictionary containing result properties. returned: always type: dict sample: result: description: user properties when state is present type: dict returned: success status_code: description: Result HTTP Status code returned: success type: int sample: 200 ''' import json import traceback from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_text from ansible.module_utils.six.moves import http_client as httplib from ansible.module_utils.six.moves.urllib.error import HTTPError from ansible.module_utils.urls import open_url def user_details(module): # Get username from module parameters, and api base url # along with validate_certs from the cyberark_session established username = module.params["username"] cyberark_session = module.params["cyberark_session"] api_base_url = cyberark_session["api_base_url"] validate_certs = cyberark_session["validate_certs"] # Prepare result, end_point, and headers result = {} end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{0}".format( username) headers = {'Content-Type': 'application/json'} headers["Authorization"] = cyberark_session["token"] try: response = open_url( api_base_url + end_point, method="GET", headers=headers, validate_certs=validate_certs) result = {"result": json.loads(response.read())} return (False, result, response.getcode()) except (HTTPError, httplib.HTTPException) as http_exception: if http_exception.code == 404: return (False, None, http_exception.code) else: module.fail_json( msg=("Error while performing user_details." "Please validate parameters provided." "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, to_text(http_exception))), headers=headers, status_code=http_exception.code) except Exception as unknown_exception: module.fail_json( msg=("Unknown error while performing user_details." "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), headers=headers, exception=traceback.format_exc(), status_code=-1) def user_add_or_update(module, HTTPMethod): # Get username from module parameters, and api base url # along with validate_certs from the cyberark_session established username = module.params["username"] cyberark_session = module.params["cyberark_session"] api_base_url = cyberark_session["api_base_url"] validate_certs = cyberark_session["validate_certs"] # Prepare result, paylod, and headers result = {} payload = {} headers = {'Content-Type': 'application/json', "Authorization": cyberark_session["token"]} # end_point and payload sets different depending on POST/PUT # for POST -- create -- payload contains username # for PUT -- update -- username is part of the endpoint if HTTPMethod == "POST": end_point = "/PasswordVault/WebServices/PIMServices.svc/Users" payload["UserName"] = username elif HTTPMethod == "PUT": end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{0}" end_point = end_point.format(username) # --- Optionally populate payload based on parameters passed --- if "initial_password" in module.params: payload["InitialPassword"] = module.params["initial_password"] if "new_password" in module.params: payload["NewPassword"] = module.params["new_password"] if "email" in module.params: payload["Email"] = module.params["email"] if "first_name" in module.params: payload["FirstName"] = module.params["first_name"] if "last_name" in module.params: payload["LastName"] = module.params["last_name"] if "change_password_on_the_next_logon" in module.params: if module.params["change_password_on_the_next_logon"]: payload["ChangePasswordOnTheNextLogon"] = "true" else: payload["ChangePasswordOnTheNextLogon"] = "false" if "expiry_date" in module.params: payload["ExpiryDate"] = module.params["expiry_date"] if "user_type_name" in module.params: payload["UserTypeName"] = module.params["user_type_name"] if "disabled" in module.params: if module.params["disabled"]: payload["Disabled"] = "true" else: payload["Disabled"] = "false" if "location" in module.params: payload["Location"] = module.params["location"] # -------------------------------------------------------------- try: # execute REST action response = open_url( api_base_url + end_point, method=HTTPMethod, headers=headers, data=json.dumps(payload), validate_certs=validate_certs) result = {"result": json.loads(response.read())} return (True, result, response.getcode()) except (HTTPError, httplib.HTTPException) as http_exception: module.fail_json( msg=("Error while performing user_add_or_update." "Please validate parameters provided." "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, to_text(http_exception))), payload=payload, headers=headers, status_code=http_exception.code) except Exception as unknown_exception: module.fail_json( msg=("Unknown error while performing user_add_or_update." "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), payload=payload, headers=headers, exception=traceback.format_exc(), status_code=-1) def user_delete(module): # Get username from module parameters, and api base url # along with validate_certs from the cyberark_session established username = module.params["username"] cyberark_session = module.params["cyberark_session"] api_base_url = cyberark_session["api_base_url"] validate_certs = cyberark_session["validate_certs"] # Prepare result, end_point, and headers result = {} end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{0}".format( username) headers = {'Content-Type': 'application/json'} headers["Authorization"] = cyberark_session["token"] try: # execute REST action response = open_url( api_base_url + end_point, method="DELETE", headers=headers, validate_certs=validate_certs) result = {"result": {}} return (True, result, response.getcode()) except (HTTPError, httplib.HTTPException) as http_exception: exception_text = to_text(http_exception) if http_exception.code == 404 and "ITATS003E" in exception_text: # User does not exist result = {"result": {}} return (False, result, http_exception.code) else: module.fail_json( msg=("Error while performing user_delete." "Please validate parameters provided." "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, exception_text)), headers=headers, status_code=http_exception.code) except Exception as unknown_exception: module.fail_json( msg=("Unknown error while performing user_delete." "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), headers=headers, exception=traceback.format_exc(), status_code=-1) def user_add_to_group(module): # Get username, and groupname from module parameters, and api base url # along with validate_certs from the cyberark_session established username = module.params["username"] group_name = module.params["group_name"] cyberark_session = module.params["cyberark_session"] api_base_url = cyberark_session["api_base_url"] validate_certs = cyberark_session["validate_certs"] # Prepare result, end_point, headers and payload result = {} end_point = "/PasswordVault/WebServices/PIMServices.svc//Groups/{0}/Users".format( group_name) headers = {'Content-Type': 'application/json'} headers["Authorization"] = cyberark_session["token"] payload = {"UserName": username} try: # execute REST action response = open_url( api_base_url + end_point, method="POST", headers=headers, data=json.dumps(payload), validate_certs=validate_certs) result = {"result": {}} return (True, result, response.getcode()) except (HTTPError, httplib.HTTPException) as http_exception: exception_text = to_text(http_exception) if http_exception.code == 409 and "ITATS262E" in exception_text: # User is already member of Group return (False, None, http_exception.code) else: module.fail_json( msg=("Error while performing user_add_to_group." "Please validate parameters provided." "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, exception_text)), payload=payload, headers=headers, exception=traceback.format_exc(), status_code=http_exception.code) except Exception as unknown_exception: module.fail_json( msg=("Unknown error while performing user_add_to_group." "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), payload=payload, headers=headers, status_code=-1) def main(): fields = { "username": {"required": True, "type": "str"}, "state": {"type": "str", "choices": ["present", "absent"], "default": "present"}, "cyberark_session": {"required": True, "type": "dict"}, "initial_password": {"type": "str", "no_log": True}, "new_password": {"type": "str", "no_log": True}, "email": {"type": "str"}, "first_name": {"type": "str"}, "last_name": {"type": "str"}, "change_password_on_the_next_logon": {"type": "bool"}, "expiry_date": {"type": "str"}, "user_type_name": {"type": "str"}, "disabled": {"type": "bool"}, "location": {"type": "str"}, "group_name": {"type": "str"}, } module = AnsibleModule(argument_spec=fields) state = module.params["state"] changed = False result = {} if (state == "present"): (changed, result, status_code) = user_details(module) if (status_code == 200): # user already exists if ("new_password" in module.params): # if new_password specified, proceed to update user credential (changed, result, status_code) = user_add_or_update(module, "PUT") if ("group_name" in module.params and module.params["group_name"] is not None): # if user exists, add to group if needed (changed, ignored_result, ignored_status_code) = user_add_to_group(module) elif (status_code == 404): # user does not exist, proceed to create it (changed, result, status_code) = user_add_or_update(module, "POST") if (status_code == 201 and "group_name" in module.params and module.params["group_name"] is not None): # if user was created, add to group if needed (changed, ignored_result, ignored_status_code) = user_add_to_group(module) elif (state == "absent"): (changed, result, status_code) = user_delete(module) module.exit_json( changed=changed, cyberark_user=result, status_code=status_code) if __name__ == '__main__': main()