Add support for hashed password (#49464)
* Add support for hashed password Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com> * Fix Shippable errors Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com> * Make pwd options mutually exclusive Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>
This commit is contained in:
parent
7bdca72713
commit
d729614d72
2 changed files with 55 additions and 1 deletions
|
@ -73,6 +73,21 @@ options:
|
||||||
default: secret
|
default: secret
|
||||||
choices: ['secret', 'password']
|
choices: ['secret', 'password']
|
||||||
version_added: "2.8"
|
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:
|
privilege:
|
||||||
description:
|
description:
|
||||||
- The C(privilege) argument configures the privilege level of the
|
- The C(privilege) argument configures the privilege level of the
|
||||||
|
@ -170,6 +185,13 @@ EXAMPLES = """
|
||||||
configured_password: "{{ new_password }}"
|
configured_password: "{{ new_password }}"
|
||||||
password_type: 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
|
- name: Delete users with aggregate
|
||||||
ios_user:
|
ios_user:
|
||||||
aggregate:
|
aggregate:
|
||||||
|
@ -191,6 +213,7 @@ commands:
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import ast
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
@ -245,6 +268,10 @@ def map_obj_to_commands(updates, module):
|
||||||
def add(command, want, x):
|
def add(command, want, x):
|
||||||
command.append('username %s %s' % (want['name'], 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):
|
def add_ssh(command, want, x=None):
|
||||||
command.append('ip ssh pubkey-chain')
|
command.append('ip ssh pubkey-chain')
|
||||||
if x:
|
if x:
|
||||||
|
@ -280,6 +307,9 @@ def map_obj_to_commands(updates, module):
|
||||||
' Please choose one or the other.')
|
' Please choose one or the other.')
|
||||||
add(commands, want, '%s %s' % (password_type, want['configured_password']))
|
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 needs_update(want, have, 'nopassword'):
|
||||||
if want['nopassword']:
|
if want['nopassword']:
|
||||||
add(commands, want, 'nopassword')
|
add(commands, want, 'nopassword')
|
||||||
|
@ -335,6 +365,7 @@ def map_config_to_obj(module):
|
||||||
'state': 'present',
|
'state': 'present',
|
||||||
'nopassword': 'nopassword' in cfg,
|
'nopassword': 'nopassword' in cfg,
|
||||||
'configured_password': None,
|
'configured_password': None,
|
||||||
|
'hashed_password': None,
|
||||||
'password_type': parse_password_type(cfg),
|
'password_type': parse_password_type(cfg),
|
||||||
'sshkey': parse_sshkey(sshcfg),
|
'sshkey': parse_sshkey(sshcfg),
|
||||||
'privilege': parse_privilege(cfg),
|
'privilege': parse_privilege(cfg),
|
||||||
|
@ -389,6 +420,7 @@ def map_params_to_obj(module):
|
||||||
for item in aggregate:
|
for item in aggregate:
|
||||||
get_value = partial(get_param_value, item=item, module=module)
|
get_value = partial(get_param_value, item=item, module=module)
|
||||||
item['configured_password'] = get_value('configured_password')
|
item['configured_password'] = get_value('configured_password')
|
||||||
|
item['hashed_password'] = get_value('hashed_password')
|
||||||
item['nopassword'] = get_value('nopassword')
|
item['nopassword'] = get_value('nopassword')
|
||||||
item['privilege'] = get_value('privilege')
|
item['privilege'] = get_value('privilege')
|
||||||
item['view'] = get_value('view')
|
item['view'] = get_value('view')
|
||||||
|
@ -415,10 +447,16 @@ def update_objects(want, have):
|
||||||
def main():
|
def main():
|
||||||
""" main entry point for module execution
|
""" 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(
|
element_spec = dict(
|
||||||
name=dict(),
|
name=dict(),
|
||||||
|
|
||||||
configured_password=dict(no_log=True),
|
configured_password=dict(no_log=True),
|
||||||
|
hashed_password=dict(no_log=True, elements='dict', options=hashed_password_spec),
|
||||||
nopassword=dict(type='bool'),
|
nopassword=dict(type='bool'),
|
||||||
update_password=dict(default='always', choices=['on_create', 'always']),
|
update_password=dict(default='always', choices=['on_create', 'always']),
|
||||||
password_type=dict(default='secret', choices=['secret', 'password']),
|
password_type=dict(default='secret', choices=['secret', 'password']),
|
||||||
|
@ -444,7 +482,7 @@ def main():
|
||||||
argument_spec.update(element_spec)
|
argument_spec.update(element_spec)
|
||||||
argument_spec.update(ios_argument_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,
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
mutually_exclusive=mutually_exclusive,
|
mutually_exclusive=mutually_exclusive,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
- name: ansibletest3
|
- name: ansibletest3
|
||||||
- name: ansibletest4
|
- name: ansibletest4
|
||||||
- name: ansibletest5
|
- name: ansibletest5
|
||||||
|
- name: ansibletest6
|
||||||
state: absent
|
state: absent
|
||||||
provider: "{{ cli }}"
|
provider: "{{ cli }}"
|
||||||
|
|
||||||
|
@ -94,6 +95,20 @@
|
||||||
- 'result.changed == true'
|
- 'result.changed == true'
|
||||||
- "'username ansibleuser5 secret' in result.commands[0]"
|
- "'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
|
- name: tearDown
|
||||||
ios_user:
|
ios_user:
|
||||||
aggregate:
|
aggregate:
|
||||||
|
@ -102,6 +117,7 @@
|
||||||
- name: ansibletest3
|
- name: ansibletest3
|
||||||
- name: ansibletest4
|
- name: ansibletest4
|
||||||
- name: ansibletest5
|
- name: ansibletest5
|
||||||
|
- name: ansibletest6
|
||||||
state: absent
|
state: absent
|
||||||
provider: "{{ cli }}"
|
provider: "{{ cli }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
Loading…
Reference in a new issue