|
54 | 54 |
|
55 | 55 | __all__ = ["SMTPException", "SMTPNotSupportedError", "SMTPServerDisconnected", "SMTPResponseException", |
56 | 56 | "SMTPSenderRefused", "SMTPRecipientsRefused", "SMTPDataError", |
57 | | - "SMTPConnectError", "SMTPHeloError", "SMTPAuthenticationError", |
| 57 | + "SMTPConnectError", "SMTPHeloError", "SMTPAuthenticationError", "SMTPAuthHashUnsupportedError", |
58 | 58 | "quoteaddr", "quotedata", "SMTP"] |
59 | 59 |
|
60 | 60 | SMTP_PORT = 25 |
@@ -141,6 +141,10 @@ class SMTPAuthenticationError(SMTPResponseException): |
141 | 141 | combination provided. |
142 | 142 | """ |
143 | 143 |
|
| 144 | +class SMTPAuthHashUnsupportedError(SMTPException): |
| 145 | + """Raised when the authentication mechanism uses a hash algorithm unsupported by the system.""" |
| 146 | + |
| 147 | + |
144 | 148 | def quoteaddr(addrstring): |
145 | 149 | """Quote a subset of the email addresses defined by RFC 821. |
146 | 150 |
|
@@ -665,8 +669,11 @@ def auth_cram_md5(self, challenge=None): |
665 | 669 | # CRAM-MD5 does not support initial-response. |
666 | 670 | if challenge is None: |
667 | 671 | return None |
668 | | - return self.user + " " + hmac.HMAC( |
669 | | - self.password.encode('ascii'), challenge, 'md5').hexdigest() |
| 672 | + try: |
| 673 | + return self.user + " " + hmac.HMAC( |
| 674 | + self.password.encode('ascii'), challenge, 'md5').hexdigest() |
| 675 | + except ValueError as e: |
| 676 | + raise SMTPAuthHashUnsupportedError(f'CRAM-MD5 failed: {e}') from e |
670 | 677 |
|
671 | 678 | def auth_plain(self, challenge=None): |
672 | 679 | """ Authobject to use with PLAIN authentication. Requires self.user and |
@@ -743,13 +750,12 @@ def login(self, user, password, *, initial_response_ok=True): |
743 | 750 | return (code, resp) |
744 | 751 | except SMTPAuthenticationError as e: |
745 | 752 | last_exception = e |
746 | | - except ValueError as e: |
| 753 | + except SMTPAuthHashUnsupportedError as e: |
747 | 754 | # Some environments (e.g., FIPS) disable certain hashing algorithms like MD5, |
748 | 755 | # which are required by CRAM-MD5. This raises a ValueError when trying to use HMAC. |
749 | 756 | # If this happens, we catch the exception and continue trying the next auth method. |
750 | 757 | last_exception = e |
751 | | - if 'unsupported' in str(e).lower(): |
752 | | - continue |
| 758 | + continue |
753 | 759 |
|
754 | 760 | # We could not login successfully. Return result of last attempt. |
755 | 761 | raise last_exception |
|
0 commit comments