1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3 4# Copyright: (c) 2017, Ansible Project 5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 7from __future__ import absolute_import, division, print_function 8__metaclass__ = type 9 10ANSIBLE_METADATA = {'metadata_version': '1.1', 11 'status': ['preview'], 12 'supported_by': 'certified'} 13 14DOCUMENTATION = r''' 15--- 16module: cyberark_user 17short_description: Module for CyberArk User Management using PAS Web Services SDK 18author: 19 - Edward Nunez (@enunez-cyberark) CyberArk BizDev 20 - Cyberark Bizdev (@cyberark-bizdev) 21 - erasmix (@erasmix) 22version_added: 2.4 23description: 24 - CyberArk User Management using PAS Web Services SDK. 25 - It currently supports the following actions Get User Details, Add User, Update User, Delete User. 26 27options: 28 username: 29 description: 30 - The name of the user who will be queried (for details), added, updated or deleted. 31 type: str 32 required: True 33 state: 34 description: 35 - Specifies the state needed for the user present for create user, absent for delete user. 36 type: str 37 choices: [ absent, present ] 38 default: present 39 cyberark_session: 40 description: 41 - Dictionary set by a CyberArk authentication containing the different values to perform actions on a logged-on CyberArk session, 42 please see M(cyberark_authentication) module for an example of cyberark_session. 43 type: dict 44 required: True 45 initial_password: 46 description: 47 - The password that the new user will use to log on the first time. 48 - This password must meet the password policy requirements. 49 - This parameter is required when state is present -- Add User. 50 type: str 51 new_password: 52 description: 53 - The user updated password. Make sure that this password meets the password policy requirements. 54 type: str 55 email: 56 description: 57 - The user email address. 58 type: str 59 first_name: 60 description: 61 - The user first name. 62 type: str 63 last_name: 64 description: 65 - The user last name. 66 type: str 67 change_password_on_the_next_logon: 68 description: 69 - Whether or not the user must change their password in their next logon. 70 type: bool 71 default: no 72 expiry_date: 73 description: 74 - The date and time when the user account will expire and become disabled. 75 type: str 76 user_type_name: 77 description: 78 - The type of user. 79 - The parameter defaults to C(EPVUser). 80 type: str 81 disabled: 82 description: 83 - Whether or not the user will be disabled. 84 type: bool 85 default: no 86 location: 87 description: 88 - The Vault Location for the user. 89 type: str 90 group_name: 91 description: 92 - The name of the group the user will be added to. 93 type: str 94''' 95 96EXAMPLES = r''' 97- name: Logon to CyberArk Vault using PAS Web Services SDK 98 cyberark_authentication: 99 api_base_url: https://components.cyberark.local 100 use_shared_logon_authentication: yes 101 102- name: Create user & immediately add it to a group 103 cyberark_user: 104 username: username 105 initial_password: password 106 user_type_name: EPVUser 107 change_password_on_the_next_logon: no 108 group_name: GroupOfUser 109 state: present 110 cyberark_session: '{{ cyberark_session }}' 111 112- name: Make sure user is present and reset user credential if present 113 cyberark_user: 114 username: Username 115 new_password: password 116 disabled: no 117 state: present 118 cyberark_session: '{{ cyberark_session }}' 119 120- name: Logoff from CyberArk Vault 121 cyberark_authentication: 122 state: absent 123 cyberark_session: '{{ cyberark_session }}' 124''' 125 126RETURN = r''' 127changed: 128 description: Whether there was a change done. 129 type: bool 130 returned: always 131cyberark_user: 132 description: Dictionary containing result properties. 133 returned: always 134 type: dict 135 sample: 136 result: 137 description: user properties when state is present 138 type: dict 139 returned: success 140status_code: 141 description: Result HTTP Status code 142 returned: success 143 type: int 144 sample: 200 145''' 146 147import json 148 149from ansible.module_utils.basic import AnsibleModule 150from ansible.module_utils._text import to_text 151from ansible.module_utils.six.moves import http_client as httplib 152from ansible.module_utils.six.moves.urllib.error import HTTPError 153from ansible.module_utils.urls import open_url 154 155 156def user_details(module): 157 158 # Get username from module parameters, and api base url 159 # along with validate_certs from the cyberark_session established 160 username = module.params["username"] 161 cyberark_session = module.params["cyberark_session"] 162 api_base_url = cyberark_session["api_base_url"] 163 validate_certs = cyberark_session["validate_certs"] 164 165 # Prepare result, end_point, and headers 166 result = {} 167 end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{0}".format( 168 username) 169 headers = {'Content-Type': 'application/json'} 170 headers["Authorization"] = cyberark_session["token"] 171 172 try: 173 174 response = open_url( 175 api_base_url + end_point, 176 method="GET", 177 headers=headers, 178 validate_certs=validate_certs) 179 result = {"result": json.loads(response.read())} 180 181 return (False, result, response.getcode()) 182 183 except (HTTPError, httplib.HTTPException) as http_exception: 184 185 if http_exception.code == 404: 186 return (False, None, http_exception.code) 187 else: 188 module.fail_json( 189 msg=("Error while performing user_details." 190 "Please validate parameters provided." 191 "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, to_text(http_exception))), 192 headers=headers, 193 status_code=http_exception.code) 194 195 except Exception as unknown_exception: 196 197 module.fail_json( 198 msg=("Unknown error while performing user_details." 199 "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), 200 headers=headers, 201 status_code=-1) 202 203 204def user_add_or_update(module, HTTPMethod): 205 206 # Get username from module parameters, and api base url 207 # along with validate_certs from the cyberark_session established 208 username = module.params["username"] 209 cyberark_session = module.params["cyberark_session"] 210 api_base_url = cyberark_session["api_base_url"] 211 validate_certs = cyberark_session["validate_certs"] 212 213 # Prepare result, payload, and headers 214 result = {} 215 payload = {} 216 headers = {'Content-Type': 'application/json', 217 "Authorization": cyberark_session["token"]} 218 219 # end_point and payload sets different depending on POST/PUT 220 # for POST -- create -- payload contains username 221 # for PUT -- update -- username is part of the endpoint 222 if HTTPMethod == "POST": 223 end_point = "/PasswordVault/WebServices/PIMServices.svc/Users" 224 payload["UserName"] = username 225 elif HTTPMethod == "PUT": 226 end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{0}" 227 end_point = end_point.format(username) 228 229 # --- Optionally populate payload based on parameters passed --- 230 if "initial_password" in module.params: 231 payload["InitialPassword"] = module.params["initial_password"] 232 233 if "new_password" in module.params: 234 payload["NewPassword"] = module.params["new_password"] 235 236 if "email" in module.params: 237 payload["Email"] = module.params["email"] 238 239 if "first_name" in module.params: 240 payload["FirstName"] = module.params["first_name"] 241 242 if "last_name" in module.params: 243 payload["LastName"] = module.params["last_name"] 244 245 if "change_password_on_the_next_logon" in module.params: 246 if module.params["change_password_on_the_next_logon"]: 247 payload["ChangePasswordOnTheNextLogon"] = "true" 248 else: 249 payload["ChangePasswordOnTheNextLogon"] = "false" 250 251 if "expiry_date" in module.params: 252 payload["ExpiryDate"] = module.params["expiry_date"] 253 254 if "user_type_name" in module.params: 255 payload["UserTypeName"] = module.params["user_type_name"] 256 257 if "disabled" in module.params: 258 if module.params["disabled"]: 259 payload["Disabled"] = "true" 260 else: 261 payload["Disabled"] = "false" 262 263 if "location" in module.params: 264 payload["Location"] = module.params["location"] 265 # -------------------------------------------------------------- 266 267 try: 268 269 # execute REST action 270 response = open_url( 271 api_base_url + end_point, 272 method=HTTPMethod, 273 headers=headers, 274 data=json.dumps(payload), 275 validate_certs=validate_certs) 276 277 result = {"result": json.loads(response.read())} 278 279 return (True, result, response.getcode()) 280 281 except (HTTPError, httplib.HTTPException) as http_exception: 282 283 module.fail_json( 284 msg=("Error while performing user_add_or_update." 285 "Please validate parameters provided." 286 "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, to_text(http_exception))), 287 payload=payload, 288 headers=headers, 289 status_code=http_exception.code) 290 291 except Exception as unknown_exception: 292 293 module.fail_json( 294 msg=("Unknown error while performing user_add_or_update." 295 "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), 296 payload=payload, 297 headers=headers, 298 status_code=-1) 299 300 301def user_delete(module): 302 303 # Get username from module parameters, and api base url 304 # along with validate_certs from the cyberark_session established 305 username = module.params["username"] 306 cyberark_session = module.params["cyberark_session"] 307 api_base_url = cyberark_session["api_base_url"] 308 validate_certs = cyberark_session["validate_certs"] 309 310 # Prepare result, end_point, and headers 311 result = {} 312 end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{0}".format( 313 username) 314 315 headers = {'Content-Type': 'application/json'} 316 headers["Authorization"] = cyberark_session["token"] 317 318 try: 319 320 # execute REST action 321 response = open_url( 322 api_base_url + end_point, 323 method="DELETE", 324 headers=headers, 325 validate_certs=validate_certs) 326 327 result = {"result": {}} 328 329 return (True, result, response.getcode()) 330 331 except (HTTPError, httplib.HTTPException) as http_exception: 332 333 exception_text = to_text(http_exception) 334 if http_exception.code == 404 and "ITATS003E" in exception_text: 335 # User does not exist 336 result = {"result": {}} 337 return (False, result, http_exception.code) 338 else: 339 module.fail_json( 340 msg=("Error while performing user_delete." 341 "Please validate parameters provided." 342 "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, exception_text)), 343 headers=headers, 344 status_code=http_exception.code) 345 346 except Exception as unknown_exception: 347 348 module.fail_json( 349 msg=("Unknown error while performing user_delete." 350 "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), 351 headers=headers, 352 status_code=-1) 353 354 355def user_add_to_group(module): 356 357 # Get username, and groupname from module parameters, and api base url 358 # along with validate_certs from the cyberark_session established 359 username = module.params["username"] 360 group_name = module.params["group_name"] 361 cyberark_session = module.params["cyberark_session"] 362 api_base_url = cyberark_session["api_base_url"] 363 validate_certs = cyberark_session["validate_certs"] 364 365 # Prepare result, end_point, headers and payload 366 result = {} 367 end_point = "/PasswordVault/WebServices/PIMServices.svc//Groups/{0}/Users".format( 368 group_name) 369 370 headers = {'Content-Type': 'application/json'} 371 headers["Authorization"] = cyberark_session["token"] 372 payload = {"UserName": username} 373 374 try: 375 376 # execute REST action 377 response = open_url( 378 api_base_url + end_point, 379 method="POST", 380 headers=headers, 381 data=json.dumps(payload), 382 validate_certs=validate_certs) 383 384 result = {"result": {}} 385 386 return (True, result, response.getcode()) 387 388 except (HTTPError, httplib.HTTPException) as http_exception: 389 390 exception_text = to_text(http_exception) 391 if http_exception.code == 409 and "ITATS262E" in exception_text: 392 # User is already member of Group 393 return (False, None, http_exception.code) 394 else: 395 module.fail_json( 396 msg=("Error while performing user_add_to_group." 397 "Please validate parameters provided." 398 "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, exception_text)), 399 payload=payload, 400 headers=headers, 401 status_code=http_exception.code) 402 403 except Exception as unknown_exception: 404 405 module.fail_json( 406 msg=("Unknown error while performing user_add_to_group." 407 "\n*** end_point=%s%s\n%s" % (api_base_url, end_point, to_text(unknown_exception))), 408 payload=payload, 409 headers=headers, 410 status_code=-1) 411 412 413def main(): 414 415 module = AnsibleModule( 416 argument_spec=dict( 417 username=dict(type='str', required=True), 418 state=dict(type='str', default='present', choices=['absent', 'present']), 419 cyberark_session=dict(type='dict', required=True), 420 initial_password=dict(type='str', no_log=True), 421 new_password=dict(type='str', no_log=True), 422 email=dict(type='str'), 423 first_name=dict(type='str'), 424 last_name=dict(type='str'), 425 change_password_on_the_next_logon=dict(type='bool'), 426 expiry_date=dict(type='str'), 427 user_type_name=dict(type='str'), 428 disabled=dict(type='bool'), 429 location=dict(type='str'), 430 group_name=dict(type='str'), 431 ), 432 ) 433 434 state = module.params['state'] 435 new_password = module.params['new_password'] 436 group_name = module.params['group_name'] 437 438 if (state == "present"): 439 (changed, result, status_code) = user_details(module) 440 441 if (status_code == 200): 442 # User already exists 443 444 # If new_password specified, proceed to update user credential 445 if (new_password is not None): 446 (changed, result, status_code) = user_add_or_update(module, "PUT") 447 448 if (group_name is not None): 449 # If user exists, add to group if needed 450 (changed, ignored_result, ignored_status_code) = user_add_to_group(module) 451 452 elif (status_code == 404): 453 # User does not exist, proceed to create it 454 (changed, result, status_code) = user_add_or_update(module, "POST") 455 456 if (status_code == 201 and group_name is not None): 457 # If user was created, add to group if needed 458 (changed, ignored_result, ignored_status_code) = user_add_to_group(module) 459 460 elif (state == "absent"): 461 (changed, result, status_code) = user_delete(module) 462 463 module.exit_json( 464 changed=changed, 465 cyberark_user=result, 466 status_code=status_code) 467 468 469if __name__ == '__main__': 470 main() 471