mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Give warning if user inputs not encrypted password to user module (#43615)
* Check the password format Check the password format and notify user if they input unencrypted password. * Fix sanity error * Add integration test * Missed a task name * Hard code the testing password Since some testing platfrom has no passlib installed * Add changelog fragment * Rework some English sentences * Fix a grammar mistake
This commit is contained in:
parent
cceddfab9b
commit
b20d903cc4
3 changed files with 79 additions and 0 deletions
3
changelogs/fragments/password_sanity_check.yml
Normal file
3
changelogs/fragments/password_sanity_check.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- user module - add a sanity check for the user's password and a more helpful warning message (https://github.com/ansible/ansible/pull/43615)
|
|
@ -342,6 +342,7 @@ uid:
|
||||||
import errno
|
import errno
|
||||||
import grp
|
import grp
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import platform
|
import platform
|
||||||
import pwd
|
import pwd
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -358,6 +359,9 @@ except ImportError:
|
||||||
HAVE_SPWD = False
|
HAVE_SPWD = False
|
||||||
|
|
||||||
|
|
||||||
|
_HASH_RE = re.compile(r'[^a-zA-Z0-9./=]')
|
||||||
|
|
||||||
|
|
||||||
class User(object):
|
class User(object):
|
||||||
"""
|
"""
|
||||||
This is a generic User manipulation class that is subclassed
|
This is a generic User manipulation class that is subclassed
|
||||||
|
@ -429,6 +433,37 @@ class User(object):
|
||||||
else:
|
else:
|
||||||
self.ssh_file = os.path.join('.ssh', 'id_%s' % self.ssh_type)
|
self.ssh_file = os.path.join('.ssh', 'id_%s' % self.ssh_type)
|
||||||
|
|
||||||
|
def check_password_encrypted(self):
|
||||||
|
# darwin need cleartext password, so no check
|
||||||
|
if self.module.params['password'] and self.platform != 'Darwin':
|
||||||
|
maybe_invalid = False
|
||||||
|
# : for delimiter, * for disable user, ! for lock user
|
||||||
|
# these characters are invalid in the password
|
||||||
|
if any(char in self.module.params['password'] for char in ':*!'):
|
||||||
|
maybe_invalid = True
|
||||||
|
if '$' not in self.module.params['password']:
|
||||||
|
maybe_invalid = True
|
||||||
|
else:
|
||||||
|
fields = self.module.params['password'].split("$")
|
||||||
|
if len(fields) >= 3:
|
||||||
|
# contains character outside the crypto constraint
|
||||||
|
if bool(_HASH_RE.search(fields[-1])):
|
||||||
|
maybe_invalid = True
|
||||||
|
# md5
|
||||||
|
if fields[1] == '1' and len(fields[-1]) != 22:
|
||||||
|
maybe_invalid = True
|
||||||
|
# sha256
|
||||||
|
if fields[1] == '5' and len(fields[-1]) != 43:
|
||||||
|
maybe_invalid = True
|
||||||
|
# sha512
|
||||||
|
if fields[1] == '6' and len(fields[-1]) != 86:
|
||||||
|
maybe_invalid = True
|
||||||
|
else:
|
||||||
|
maybe_invalid = True
|
||||||
|
if maybe_invalid:
|
||||||
|
self.module.warn("The input password appears not to have been hashed. "
|
||||||
|
"The 'password' argument must be encrypted for this module to work properly.")
|
||||||
|
|
||||||
def execute_command(self, cmd, use_unsafe_shell=False, data=None, obey_checkmode=True):
|
def execute_command(self, cmd, use_unsafe_shell=False, data=None, obey_checkmode=True):
|
||||||
if self.module.check_mode and obey_checkmode:
|
if self.module.check_mode and obey_checkmode:
|
||||||
self.module.debug('In check mode, would have run: "%s"' % cmd)
|
self.module.debug('In check mode, would have run: "%s"' % cmd)
|
||||||
|
@ -2392,6 +2427,7 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
user = User(module)
|
user = User(module)
|
||||||
|
user.check_password_encrypted()
|
||||||
|
|
||||||
module.debug('User instantiated - platform %s' % user.platform)
|
module.debug('User instantiated - platform %s' % user.platform)
|
||||||
if user.distribution:
|
if user.distribution:
|
||||||
|
|
|
@ -64,6 +64,46 @@
|
||||||
- user_test0_1 is not changed
|
- user_test0_1 is not changed
|
||||||
- '"ansibulluser" in user_names.stdout_lines'
|
- '"ansibulluser" in user_names.stdout_lines'
|
||||||
|
|
||||||
|
# test user add with password
|
||||||
|
- name: add an encrypted password for user
|
||||||
|
user:
|
||||||
|
name: ansibulluser
|
||||||
|
password: "$6$rounds=656000$TT4O7jz2M57npccl$33LF6FcUMSW11qrESXL1HX0BS.bsiT6aenFLLiVpsQh6hDtI9pJh5iY7x8J7ePkN4fP8hmElidHXaeD51pbGS."
|
||||||
|
state: present
|
||||||
|
update_password: always
|
||||||
|
register: test_user_encrypt0
|
||||||
|
|
||||||
|
- name: there should not be warnings
|
||||||
|
assert:
|
||||||
|
that: "'warnings' not in test_user_encrypt0"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: add an plaintext password for user
|
||||||
|
user:
|
||||||
|
name: ansibulluser
|
||||||
|
password: "plaintextpassword"
|
||||||
|
state: present
|
||||||
|
update_password: always
|
||||||
|
register: test_user_encrypt1
|
||||||
|
|
||||||
|
- name: there should be a warning complains that the password is plaintext
|
||||||
|
assert:
|
||||||
|
that: "'warnings' in test_user_encrypt1"
|
||||||
|
|
||||||
|
- name: add an invalid hashed password
|
||||||
|
user:
|
||||||
|
name: ansibulluser
|
||||||
|
password: "$6$rounds=656000$tgK3gYTyRLUmhyv2$lAFrYUQwn7E6VsjPOwQwoSx30lmpiU9r/E0Al7tzKrR9mkodcMEZGe9OXD0H/clOn6qdsUnaL4zefy5fG+++++"
|
||||||
|
state: present
|
||||||
|
update_password: always
|
||||||
|
register: test_user_encrypt2
|
||||||
|
|
||||||
|
- name: there should be a warning complains about the character set of password
|
||||||
|
assert:
|
||||||
|
that: "'warnings' in test_user_encrypt2"
|
||||||
|
when: ansible_system != 'Darwin'
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/ansible/ansible/issues/42484
|
# https://github.com/ansible/ansible/issues/42484
|
||||||
# Skipping macOS for now since there is a bug when changing home directory
|
# Skipping macOS for now since there is a bug when changing home directory
|
||||||
- block:
|
- block:
|
||||||
|
|
Loading…
Reference in a new issue