-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
bpo-27820: Fix AUTH LOGIN logic in smtplib.SMTP #24118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -785,7 +785,7 @@ def found_terminator(self): | |||
except ResponseException as e: | |||
self.smtp_state = self.COMMAND | |||
self.push('%s %s' % (e.smtp_code, e.smtp_error)) | |||
return | |||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mis-indented return caused the test for smtpd state to "fall through" to the next test, resulting ultimately in "Internal Confusion" error.
@@ -662,7 +666,7 @@ def auth_plain(self, challenge=None): | |||
def auth_login(self, challenge=None): | |||
""" Authobject to use with LOGIN authentication. Requires self.user and | |||
self.password to be set.""" | |||
if challenge is None: | |||
if challenge is None or self._auth_challenge_count < 2: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The draft standard for AUTH LOGIN specifies that clients SHOULD ignore the actual contents of the challenge, and respond only based on how many challenges have been received.
This PR is stale because it has been open for 30 days with no activity. |
Well, it's a clean, non-conflicting PR (so far) ... so there's no need to keep updating it? 😅 |
Bump |
And in the process also fix a longstanding bug in the SimSMTPChannel.found_terminator() method that causes inability to test SMTP AUTH with initial_response_ok=False.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Response to some questions.
Broken/buggy server might 'trap' us in AUTH. We raise an exception and let the user handle things.
5c8f4d8
to
481ca55
Compare
# If server keeps sending challenges, something is wrong. | ||
if self._auth_challenge_count > _MAXCHALLENGE: | ||
raise SMTPException( | ||
"Server AUTH mechanism infinite loop. Last response: " | ||
+ repr((code, resp)) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This guards against broken/buggy server that traps us in the AUTH state.
At this point, state is indeterminate, and we should let user handle things. That's why it simply raises. (The only "guaranteed safe" thing to do is close()
, actually.)
"AUTH trap" is when server keeps sending AUTH Challenge (334 ...)
def _auth_buggy(self, arg=None): | ||
# This AUTH mechanism will 'trap' client in a neverending 334 | ||
# base64 encoded 'BuGgYbUgGy' | ||
self.push('334 QnVHZ1liVWdHeQ==') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally made-up AUTH mechanism whose purpose is to 'trap' the client in an infinite loop of 334
(AUTH Challenge)
smtp = smtplib.SMTP( | ||
HOST, self.port, local_hostname='localhost', | ||
timeout=support.LOOPBACK_TIMEOUT | ||
) | ||
try: | ||
smtp.user, smtp.password = sim_auth | ||
smtp.ehlo("test_auth_buggy") | ||
expect = r"^Server AUTH mechanism infinite loop.*" | ||
with self.assertRaisesRegex(smtplib.SMTPException, expect) as cm: | ||
smtp.auth("BUGGY", auth_buggy, initial_response_ok=False) | ||
finally: | ||
smtp.close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't use smtplib.SMTP as context manager here ... its __exit__
causes a different exception to be raised in addition. So the test uses a decidedly "lower level" mechanism to close the connection.
VSCode did not indicate any problems, that's why I missed this during previous push.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you, @pepoluan .
Thanks @pepoluan for the PR, and @orsenthil for merging it 🌮🎉.. I'm working now to backport this PR to: 3.8, 3.9. |
* Fix auth_login logic (bpo-27820) * Also fix a longstanding bug in the SimSMTPChannel.found_terminator() method that causes inability to test SMTP AUTH with initial_response_ok=False. (cherry picked from commit 7591d94) Co-authored-by: Pandu E POLUAN <[email protected]>
GH-24832 is a backport of this pull request to the 3.9 branch. |
Sorry, @pepoluan and @orsenthil, I could not cleanly backport this to |
GH-24833 is a backport of this pull request to the 3.8 branch. |
* Fix auth_login logic (bpo-27820) * Also fix a longstanding bug in the SimSMTPChannel.found_terminator() method that causes inability to test SMTP AUTH with initial_response_ok=False. (cherry picked from commit 7591d94) Co-authored-by: Pandu E POLUAN <[email protected]>
) * bpo-27820: Fix AUTH LOGIN logic in smtplib.SMTP (GH-24118) * Fix auth_login logic (bpo-27820) * Also fix a longstanding bug in the SimSMTPChannel.found_terminator() method that causes inability to test SMTP AUTH with initial_response_ok=False. (cherry picked from commit 7591d94) * Set timeout to 15 directly. Co-authored-by: Pandu E POLUAN <[email protected]>
bpo-27820: Fix AUTH LOGIN logic in smtplib.SMTP (pythonGH-24118)
Previously,
smtplib.SMTP.auth_login
responded with username if challenge is not given, and always responded with password if challenge is given. This causes auth failure wheninitial_response_ok=False
.The standard for AUTH LOGIN specifies that clients should simply respond with base64-encoded username on first challenge, and with base64-encoded password on second challenge, disregarding the actual contents of the challenges themselves.
Suitable test cases have been added to
test_smtplib.py
+ a fix for a long-standing bug intest_smtplib.py
where settinginitial_response_ok=False
will always result in "Internal Confusion" error.https://bugs.python.org/issue27820