Skip to content

Commit dd44eca

Browse files
committed
Let IMAP authentication immediately fail when no password was given
Some clients (old Outlook) try IMAP authentication on first connection without a password, when it was not saved in the client beforehand. So to support scenarios where the client tries to login with IMAP on first connection to email server and OAuth 2.0 authorisation didn't happen yet, the authorisation will be delayed until the correct password is entered in the client. As this password will be used for token encryption/decryption in config file, other protocols, like SMTP, which also needs a password to work, can now use the same password to decrypt the authorisation token.
1 parent dc8fb08 commit dd44eca

File tree

1 file changed

+23
-13
lines changed

1 file changed

+23
-13
lines changed

emailproxy.py

+23-13
Original file line numberDiff line numberDiff line change
@@ -1687,22 +1687,32 @@ def process_data(self, byte_data, censor_server_log=False):
16871687
super().process_data(byte_data)
16881688

16891689
def authenticate_connection(self, username, password, command='login'):
1690-
success, result = OAuth2Helper.get_oauth2_credentials(username, password)
1691-
if success:
1692-
# send authentication command to server (response checked in ServerConnection)
1693-
# note: we only support single-trip authentication (SASL) without checking server capabilities - improve?
1694-
super().process_data(b'%s AUTHENTICATE XOAUTH2 ' % self.authentication_tag.encode('utf-8'))
1695-
super().process_data(b'%s\r\n' % OAuth2Helper.encode_oauth2_string(result), censor_server_log=True)
1696-
1697-
# because get_oauth2_credentials blocks, the server could have disconnected, and may no-longer exist
1698-
if self.server_connection:
1699-
self.server_connection.authenticated_username = username
1700-
1701-
self.reset_login_state()
1702-
if not success:
1690+
if not password:
1691+
# we can't actually check credentials here, but if password is missing, it's possible that
1692+
# the client want to ask for credentials and so tried without password first, in the hope
1693+
# that the server will handle it, which it won't for XOAUTH2 - intercept that here and mimic old behavior
1694+
self.reset_login_state()
1695+
result = '%s: Login failed - the password for account %s is incorrect' % (APP_NAME, username)
17031696
error_message = '%s NO %s %s\r\n' % (self.authentication_tag, command.upper(), result)
17041697
self.authentication_tag = None
17051698
self.send(error_message.encode('utf-8'))
1699+
else:
1700+
success, result = OAuth2Helper.get_oauth2_credentials(username, password)
1701+
if success:
1702+
# send authentication command to server (response checked in ServerConnection)
1703+
# note: we only support single-trip authentication (SASL) without checking server capabilities - improve?
1704+
super().process_data(b'%s AUTHENTICATE XOAUTH2 ' % self.authentication_tag.encode('utf-8'))
1705+
super().process_data(b'%s\r\n' % OAuth2Helper.encode_oauth2_string(result), censor_server_log=True)
1706+
1707+
# because get_oauth2_credentials blocks, the server could have disconnected, and may no-longer exist
1708+
if self.server_connection:
1709+
self.server_connection.authenticated_username = username
1710+
1711+
self.reset_login_state()
1712+
if not success:
1713+
error_message = '%s NO %s %s\r\n' % (self.authentication_tag, command.upper(), result)
1714+
self.authentication_tag = None
1715+
self.send(error_message.encode('utf-8'))
17061716

17071717

17081718
class POPOAuth2ClientConnection(OAuth2ClientConnection):

0 commit comments

Comments
 (0)