From f5431321a295c4f67946c85ee5acd96c5213f44c Mon Sep 17 00:00:00 2001 From: Sloane Hertel <19572925+s-hertel@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:32:42 -0400 Subject: [PATCH] password_hash - fix bcrypt algorithm when passlib is not installed (#81385) --- .../fragments/password_hash-fix-crypt-salt-bcrypt.yml | 2 ++ lib/ansible/utils/encrypt.py | 11 +++++++++-- test/integration/targets/filter_core/tasks/main.yml | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/password_hash-fix-crypt-salt-bcrypt.yml diff --git a/changelogs/fragments/password_hash-fix-crypt-salt-bcrypt.yml b/changelogs/fragments/password_hash-fix-crypt-salt-bcrypt.yml new file mode 100644 index 00000000000..f0ef380857c --- /dev/null +++ b/changelogs/fragments/password_hash-fix-crypt-salt-bcrypt.yml @@ -0,0 +1,2 @@ +bugfixes: + - password_hash - fix salt format for ``crypt`` (only used if ``passlib`` is not installed) for the ``bcrypt`` algorithm. diff --git a/lib/ansible/utils/encrypt.py b/lib/ansible/utils/encrypt.py index 819a0a9cad0..7c6402fc76a 100644 --- a/lib/ansible/utils/encrypt.py +++ b/lib/ansible/utils/encrypt.py @@ -128,7 +128,10 @@ class CryptHash(BaseHash): return ret def _rounds(self, rounds): - if rounds == self.algo_data.implicit_rounds: + if self.algorithm == 'bcrypt': + # crypt requires 2 digits for rounds + return rounds or self.algo_data.implicit_rounds + elif rounds == self.algo_data.implicit_rounds: # Passlib does not include the rounds if it is the same as implicit_rounds. # Make crypt lib behave the same, by not explicitly specifying the rounds in that case. return None @@ -148,7 +151,10 @@ class CryptHash(BaseHash): saltstring = "$%s" % ident if rounds: - saltstring += "$rounds=%d" % rounds + if self.algorithm == 'bcrypt': + saltstring += "$%d" % rounds + else: + saltstring += "$rounds=%d" % rounds saltstring += "$%s" % salt @@ -177,6 +183,7 @@ class PasslibHash(BaseHash): if not PASSLIB_AVAILABLE: raise AnsibleError("passlib must be installed and usable to hash with '%s'" % algorithm, orig_exc=PASSLIB_E) + display.vv("Using passlib to hash input with '%s'" % algorithm) try: self.crypt_algo = getattr(passlib.hash, algorithm) diff --git a/test/integration/targets/filter_core/tasks/main.yml b/test/integration/targets/filter_core/tasks/main.yml index ebf9962dece..9d287a187df 100644 --- a/test/integration/targets/filter_core/tasks/main.yml +++ b/test/integration/targets/filter_core/tasks/main.yml @@ -478,6 +478,14 @@ vars: msg: "msdcc is not in the list of supported passlib algorithms: md5, blowfish, sha256, sha512" +- name: test password_hash can work with bcrypt without passlib installed + debug: + msg: "{{ 'somestring'|password_hash('bcrypt') }}" + register: crypt_bcrypt + # Some implementations of crypt do not fail outright and return some short value. + failed_when: crypt_bcrypt is failed or (crypt_bcrypt.msg|length|int) != 60 + when: ansible_facts.os_family in ['RedHat', 'Debian'] + - name: Verify to_uuid throws on weird namespace set_fact: foo: '{{"hey"|to_uuid(namespace=22)}}'