From d729614d72890293a5d88b94faf7d42b034ad57c Mon Sep 17 00:00:00 2001 From: Nilashish Chakraborty Date: Wed, 12 Dec 2018 22:22:15 +0530 Subject: [PATCH] Add support for hashed password (#49464) * Add support for hashed password Signed-off-by: NilashishC * Fix Shippable errors Signed-off-by: NilashishC * Make pwd options mutually exclusive Signed-off-by: NilashishC --- lib/ansible/modules/network/ios/ios_user.py | 40 ++++++++++++++++++- .../targets/ios_user/tests/cli/basic.yaml | 16 ++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/ansible/modules/network/ios/ios_user.py b/lib/ansible/modules/network/ios/ios_user.py index 8af43169d16..ec5756430f8 100644 --- a/lib/ansible/modules/network/ios/ios_user.py +++ b/lib/ansible/modules/network/ios/ios_user.py @@ -73,6 +73,21 @@ options: default: secret choices: ['secret', 'password'] version_added: "2.8" + hashed_password: + description: + - This option allows configuring hashed passwords on Cisco IOS devices. + suboptions: + type: + description: + - Specifies the type of hash (e.g., 5 for MD5, 8 for PBKDF2, etc.) + - For this to work, the device needs to support the desired hash type + type: int + required: True + value: + description: + - The actual hashed password to be configured on the device + required: True + version_added: "2.8" privilege: description: - The C(privilege) argument configures the privilege level of the @@ -170,6 +185,13 @@ EXAMPLES = """ configured_password: "{{ new_password }}" password_type: password +- name: Add a user with MD5 hashed password + ios_user: + name: ansibletest5 + hashed_password: + type: 5 + value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/ + - name: Delete users with aggregate ios_user: aggregate: @@ -191,6 +213,7 @@ commands: from copy import deepcopy import re +import ast import base64 import hashlib @@ -245,6 +268,10 @@ def map_obj_to_commands(updates, module): def add(command, want, x): command.append('username %s %s' % (want['name'], x)) + def add_hashed_password(command, want, x): + command.append('username %s secret %s %s' % (want['name'], ast.literal_eval(x)['type'], + ast.literal_eval(x)['value'])) + def add_ssh(command, want, x=None): command.append('ip ssh pubkey-chain') if x: @@ -280,6 +307,9 @@ def map_obj_to_commands(updates, module): ' Please choose one or the other.') add(commands, want, '%s %s' % (password_type, want['configured_password'])) + if needs_update(want, have, 'hashed_password'): + add_hashed_password(commands, want, want['hashed_password']) + if needs_update(want, have, 'nopassword'): if want['nopassword']: add(commands, want, 'nopassword') @@ -335,6 +365,7 @@ def map_config_to_obj(module): 'state': 'present', 'nopassword': 'nopassword' in cfg, 'configured_password': None, + 'hashed_password': None, 'password_type': parse_password_type(cfg), 'sshkey': parse_sshkey(sshcfg), 'privilege': parse_privilege(cfg), @@ -389,6 +420,7 @@ def map_params_to_obj(module): for item in aggregate: get_value = partial(get_param_value, item=item, module=module) item['configured_password'] = get_value('configured_password') + item['hashed_password'] = get_value('hashed_password') item['nopassword'] = get_value('nopassword') item['privilege'] = get_value('privilege') item['view'] = get_value('view') @@ -415,10 +447,16 @@ def update_objects(want, have): def main(): """ main entry point for module execution """ + hashed_password_spec = dict( + type=dict(type='int', required=True), + value=dict(no_log=True, required=True) + ) + element_spec = dict( name=dict(), configured_password=dict(no_log=True), + hashed_password=dict(no_log=True, elements='dict', options=hashed_password_spec), nopassword=dict(type='bool'), update_password=dict(default='always', choices=['on_create', 'always']), password_type=dict(default='secret', choices=['secret', 'password']), @@ -444,7 +482,7 @@ def main(): argument_spec.update(element_spec) argument_spec.update(ios_argument_spec) - mutually_exclusive = [('name', 'aggregate')] + mutually_exclusive = [('name', 'aggregate'), ('nopassword', 'hashed_password', 'configured_password')] module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, diff --git a/test/integration/targets/ios_user/tests/cli/basic.yaml b/test/integration/targets/ios_user/tests/cli/basic.yaml index ecd778c0a90..a2876aad586 100644 --- a/test/integration/targets/ios_user/tests/cli/basic.yaml +++ b/test/integration/targets/ios_user/tests/cli/basic.yaml @@ -7,6 +7,7 @@ - name: ansibletest3 - name: ansibletest4 - name: ansibletest5 + - name: ansibletest6 state: absent provider: "{{ cli }}" @@ -94,6 +95,20 @@ - 'result.changed == true' - "'username ansibleuser5 secret' in result.commands[0]" +- name: Create user with hashed_password + ios_user: + name: ansibleuser6 + hashed_password: + type: 5 + value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/ + state: present + register: result + +- assert: + that: + - 'result.changed == true' + - "'username ansibleuser6 secret' in result.commands[0]" + - name: tearDown ios_user: aggregate: @@ -102,6 +117,7 @@ - name: ansibletest3 - name: ansibletest4 - name: ansibletest5 + - name: ansibletest6 state: absent provider: "{{ cli }}" register: result