From fcdd7493ae6241badf43caf5e120690c5b9bdd33 Mon Sep 17 00:00:00 2001 From: Sloane Hertel <19572925+s-hertel@users.noreply.github.com> Date: Wed, 8 Feb 2023 14:46:07 -0500 Subject: [PATCH] improve password_hash warning for unsupported algorithms (#79872) * password_hash - give a warning for unsupported algorithms (that raise a TypeError) * add suggested changes, a test and changelog --- ...on-enforced-password_hash-type-choices.yml | 4 ++++ lib/ansible/plugins/filter/core.py | 19 ++++++++++++++- .../targets/filter_core/tasks/main.yml | 24 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/deprecate-non-enforced-password_hash-type-choices.yml diff --git a/changelogs/fragments/deprecate-non-enforced-password_hash-type-choices.yml b/changelogs/fragments/deprecate-non-enforced-password_hash-type-choices.yml new file mode 100644 index 00000000000..a5d82a3309c --- /dev/null +++ b/changelogs/fragments/deprecate-non-enforced-password_hash-type-choices.yml @@ -0,0 +1,4 @@ +deprecated_features: + - password_hash - deprecate using passlib.hash.hashtype if hashtype isn't in the list of documented choices. +bugfixes: + - password_hash - handle errors using unknown passlib hashtypes more gracefully (https://github.com/ansible/ansible/issues/45392). diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index 5906408fa70..671f9f50426 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -34,7 +34,7 @@ from ansible.parsing.ajson import AnsibleJSONEncoder from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.template import recursive_check_defined from ansible.utils.display import Display -from ansible.utils.encrypt import passlib_or_crypt +from ansible.utils.encrypt import passlib_or_crypt, PASSLIB_AVAILABLE from ansible.utils.hashing import md5s, checksum_s from ansible.utils.unicode import unicode_wrap from ansible.utils.vars import merge_hash @@ -281,10 +281,27 @@ def get_encrypted_password(password, hashtype='sha512', salt=None, salt_size=Non } hashtype = passlib_mapping.get(hashtype, hashtype) + + unknown_passlib_hashtype = False + if PASSLIB_AVAILABLE and hashtype not in passlib_mapping and hashtype not in passlib_mapping.values(): + unknown_passlib_hashtype = True + display.deprecated( + f"Checking for unsupported password_hash passlib hashtype '{hashtype}'. " + "This will be an error in the future as all supported hashtypes must be documented.", + version='2.19' + ) + try: return passlib_or_crypt(password, hashtype, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident) except AnsibleError as e: reraise(AnsibleFilterError, AnsibleFilterError(to_native(e), orig_exc=e), sys.exc_info()[2]) + except Exception as e: + if unknown_passlib_hashtype: + # This can occur if passlib.hash has the hashtype attribute, but it has a different signature than the valid choices. + # In 2.19 this will replace the deprecation warning above and the extra exception handling can be deleted. + choices = ', '.join(passlib_mapping) + raise AnsibleFilterError(f"{hashtype} is not in the list of supported passlib algorithms: {choices}") from e + raise def to_uuid(string, namespace=UUID_NAMESPACE_ANSIBLE): diff --git a/test/integration/targets/filter_core/tasks/main.yml b/test/integration/targets/filter_core/tasks/main.yml index 2d084191678..ebf9962dece 100644 --- a/test/integration/targets/filter_core/tasks/main.yml +++ b/test/integration/targets/filter_core/tasks/main.yml @@ -454,6 +454,30 @@ - password_hash_2 is failed - "'not support' in password_hash_2.msg" +- name: install passlib if needed + pip: + name: passlib + state: present + register: installed_passlib + +- name: test using passlib with an unsupported hash type + set_fact: + foo: '{{"hey"|password_hash("msdcc")}}' + ignore_errors: yes + register: unsupported_hash_type + +- name: remove passlib if it was installed + pip: + name: passlib + state: absent + when: installed_passlib.changed + +- assert: + that: + - unsupported_hash_type.msg == msg + vars: + msg: "msdcc is not in the list of supported passlib algorithms: md5, blowfish, sha256, sha512" + - name: Verify to_uuid throws on weird namespace set_fact: foo: '{{"hey"|to_uuid(namespace=22)}}'