From 2531d548800d916b13ebecf4d5ebc63d50cff949 Mon Sep 17 00:00:00 2001 From: Rick Elrod Date: Wed, 24 Jun 2020 13:50:28 -0500 Subject: [PATCH] Throw AnsibleError instead of OSError, py3.9 crypt (#70246) Change: - On Python 3.9, `crypt.crypt` will throw instead of returning `None` when the algorithm isn't supported. So we catch that and handle it the same way we handled the algorithm not being supported on 3.8: by throwing AnsibleError. Test Plan: - CI for <=3.8. - Local for 3.9b3: ansible -m debug -a "msg=\"{{ 'changeme' | password_hash('bcrypt') }}\"" localhost Before: localhost | FAILED! => { "msg": "Unexpected failure during module execution.", "stdout": "" } After: localhost | FAILED! => { "msg": "crypt.crypt does not support 'bcrypt' algorithm" } Tickets: - Fixes #69930 Signed-off-by: Rick Elrod --- changelogs/fragments/crypt-oserror.yml | 2 ++ lib/ansible/utils/encrypt.py | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 changelogs/fragments/crypt-oserror.yml diff --git a/changelogs/fragments/crypt-oserror.yml b/changelogs/fragments/crypt-oserror.yml new file mode 100644 index 00000000000..3bb6e22472b --- /dev/null +++ b/changelogs/fragments/crypt-oserror.yml @@ -0,0 +1,2 @@ +minor_changes: + - ansible.utils.encrypt now returns `AnsibleError` instead of crypt.crypt's `OSError` on Python 3.9 diff --git a/lib/ansible/utils/encrypt.py b/lib/ansible/utils/encrypt.py index 4a35d8cf0e6..4128901a2a5 100644 --- a/lib/ansible/utils/encrypt.py +++ b/lib/ansible/utils/encrypt.py @@ -106,13 +106,23 @@ class CryptHash(BaseHash): saltstring = "$%s$%s" % (self.algo_data.crypt_id, salt) else: saltstring = "$%s$rounds=%d$%s" % (self.algo_data.crypt_id, rounds, salt) - result = crypt.crypt(secret, saltstring) - # crypt.crypt returns None if it cannot parse saltstring + # crypt.crypt on Python < 3.9 returns None if it cannot parse saltstring + # On Python >= 3.9, it throws OSError. + try: + result = crypt.crypt(secret, saltstring) + orig_exc = None + except OSError as e: + result = None + orig_exc = e + # None as result would be interpreted by the some modules (user module) # as no password at all. if not result: - raise AnsibleError("crypt.crypt does not support '%s' algorithm" % self.algorithm) + raise AnsibleError( + "crypt.crypt does not support '%s' algorithm" % self.algorithm, + orig_exc=orig_exc, + ) return result