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 661fde3407b..59f61008421 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 @@ -178,6 +184,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)}}'