diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java index 6c3cfa109..80fa274ee 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/SmtpTransport.java @@ -290,7 +290,7 @@ public class SmtpTransport extends Transport { } } - Map extensions = sendHello(localHost); + Map extensions = sendHello(localHost); m8bitEncodingAllowed = extensions.containsKey("8BITMIME"); @@ -306,7 +306,7 @@ public class SmtpTransport extends Transport { mClientCertificateAlias); mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), - 1024)); + 1024)); mOut = new BufferedOutputStream(mSocket.getOutputStream(), 1024); /* * Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically, @@ -344,8 +344,8 @@ public class SmtpTransport extends Transport { if (!TextUtils.isEmpty(mUsername) && (!TextUtils.isEmpty(mPassword) || - AuthType.EXTERNAL == mAuthType || - AuthType.XOAUTH2 == mAuthType)) { + AuthType.EXTERNAL == mAuthType || + AuthType.XOAUTH2 == mAuthType)) { switch (mAuthType) { @@ -354,36 +354,37 @@ public class SmtpTransport extends Transport { * but it still may exist in a user's settings from a previous * version, or it may have been imported. */ - case LOGIN: - case PLAIN: - // try saslAuthPlain first, because it supports UTF-8 explicitly - if (authPlainSupported) { - saslAuthPlain(mUsername, mPassword); - } else if (authLoginSupported) { - saslAuthLogin(mUsername, mPassword); - } else { - throw new MessagingException("Authentication methods SASL PLAIN and LOGIN are unavailable."); - } - break; + case LOGIN: + case PLAIN: + // try saslAuthPlain first, because it supports UTF-8 explicitly + if (authPlainSupported) { + saslAuthPlain(mUsername, mPassword); + } else if (authLoginSupported) { + saslAuthLogin(mUsername, mPassword); + } else { + throw new MessagingException( + "Authentication methods SASL PLAIN and LOGIN are unavailable."); + } + break; - case CRAM_MD5: - if (authCramMD5Supported) { - saslAuthCramMD5(mUsername, mPassword); - } else { - throw new MessagingException("Authentication method CRAM-MD5 is unavailable."); - } - break; - case XOAUTH2: - if (authXoauth2Supported && oauthTokenProvider != null) { - saslXoauth2(mUsername); - } else { - throw new MessagingException("Authentication method XOAUTH2 is unavailable."); - } - break; - case EXTERNAL: - if (authExternalSupported) { - saslAuthExternal(mUsername); - } else { + case CRAM_MD5: + if (authCramMD5Supported) { + saslAuthCramMD5(mUsername, mPassword); + } else { + throw new MessagingException("Authentication method CRAM-MD5 is unavailable."); + } + break; + case XOAUTH2: + if (authXoauth2Supported && oauthTokenProvider != null) { + saslXoauth2(mUsername); + } else { + throw new MessagingException("Authentication method XOAUTH2 is unavailable."); + } + break; + case EXTERNAL: + if (authExternalSupported) { + saslAuthExternal(mUsername); + } else { /* * Some SMTP servers are known to provide no error * indication when a client certificate fails to @@ -394,53 +395,60 @@ public class SmtpTransport extends Transport { * EXTERNAL when using client certificates. That way, the * user can be notified of a problem during account setup. */ - throw new CertificateValidationException(MissingCapability); - } - break; + throw new CertificateValidationException(MissingCapability); + } + break; /* * AUTOMATIC is an obsolete option which is unavailable to users, * but it still may exist in a user's settings from a previous * version, or it may have been imported. */ - case AUTOMATIC: - if (secureConnection) { - // try saslAuthPlain first, because it supports UTF-8 explicitly - if (authPlainSupported) { - saslAuthPlain(mUsername, mPassword); - } else if (authLoginSupported) { - saslAuthLogin(mUsername, mPassword); - } else if (authCramMD5Supported) { - saslAuthCramMD5(mUsername, mPassword); - } else { - throw new MessagingException("No supported authentication methods available."); - } - } else { - if (authCramMD5Supported) { - saslAuthCramMD5(mUsername, mPassword); + case AUTOMATIC: + if (secureConnection) { + // try saslAuthPlain first, because it supports UTF-8 explicitly + if (authPlainSupported) { + saslAuthPlain(mUsername, mPassword); + } else if (authLoginSupported) { + saslAuthLogin(mUsername, mPassword); + } else if (authCramMD5Supported) { + saslAuthCramMD5(mUsername, mPassword); + } else { + throw new MessagingException("No supported authentication methods available."); + } } else { + if (authCramMD5Supported) { + saslAuthCramMD5(mUsername, mPassword); + } else { /* * We refuse to insecurely transmit the password * using the obsolete AUTOMATIC setting because of * the potential for a MITM attack. Affected users * must choose a different setting. */ - throw new MessagingException( - "Update your outgoing server authentication setting. AUTOMATIC auth. is unavailable."); + throw new MessagingException( + "Update your outgoing server authentication setting. AUTOMATIC auth. is unavailable."); + } } - } - break; + break; - default: - throw new MessagingException("Unhandled authentication method found in the server settings (bug)."); + default: + throw new MessagingException( + "Unhandled authentication method found in the server settings (bug)."); } } + } catch (MessagingException e) { + close(); + throw e; } catch (SSLException e) { + close(); throw new CertificateValidationException(e.getMessage(), e); } catch (GeneralSecurityException gse) { + close(); throw new MessagingException( "Unable to open connection to SMTP server due to security error.", gse); } catch (IOException ioe) { + close(); throw new MessagingException("Unable to open connection to SMTP server.", ioe); } } diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java index 97492e52e..bfc8cec31 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/SmtpTransportTest.java @@ -133,6 +133,8 @@ public class SmtpTransportTest { server.expect("EHLO localhost"); server.output("250-localhost Hello client.localhost"); server.output("250 AUTH"); + server.expect("QUIT"); + server.output("221 BYE"); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.PLAIN, ConnectionSecurity.NONE); try { @@ -172,6 +174,8 @@ public class SmtpTransportTest { server.expect("EHLO localhost"); server.output("250-localhost Hello client.localhost"); server.output("250 AUTH PLAIN LOGIN"); + server.expect("QUIT"); + server.output("221 BYE"); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.CRAM_MD5, ConnectionSecurity.NONE); try { @@ -181,7 +185,7 @@ public class SmtpTransportTest { assertEquals("Authentication method CRAM-MD5 is unavailable.", e.getMessage()); } - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); } @@ -214,6 +218,8 @@ public class SmtpTransportTest { server.expect(""); server.output("535-5.7.1 Username and Password not accepted. Learn more at"); server.output("535 5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68"); + server.expect("QUIT"); + server.output("221 BYE"); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.XOAUTH2, ConnectionSecurity.NONE); try { @@ -228,7 +234,7 @@ public class SmtpTransportTest { InOrder inOrder = inOrder(oAuth2TokenProvider); inOrder.verify(oAuth2TokenProvider).getToken(eq(USERNAME), anyInt()); inOrder.verify(oAuth2TokenProvider).invalidateToken(USERNAME); - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); } @@ -327,6 +333,9 @@ public class SmtpTransportTest { server.expect(""); server.output("535-5.7.1 Username and Password not accepted. Learn more at"); server.output("535 5.7.1 http://support.google.com/mail/bin/answer.py?answer=14257 hx9sm5317360pbc.68"); + server.expect("QUIT"); + server.output("221 BYE"); + SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.XOAUTH2, ConnectionSecurity.NONE); try { @@ -338,7 +347,7 @@ public class SmtpTransportTest { e.getMessage()); } - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); } @@ -349,6 +358,8 @@ public class SmtpTransportTest { server.expect("EHLO localhost"); server.output("250-localhost Hello client.localhost"); server.output("250 AUTH XOAUTH2"); + server.expect("QUIT"); + server.output("221 BYE"); when(oAuth2TokenProvider.getToken(anyString(), anyInt())).thenThrow(new AuthenticationFailedException("Failed to fetch token")); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.XOAUTH2, ConnectionSecurity.NONE); @@ -359,7 +370,7 @@ public class SmtpTransportTest { assertEquals("Failed to fetch token", e.getMessage()); } - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); } @@ -371,6 +382,8 @@ public class SmtpTransportTest { server.expect("EHLO localhost"); server.output("250-localhost Hello client.localhost"); server.output("250 AUTH PLAIN LOGIN"); + server.expect("QUIT"); + server.output("221 BYE"); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.XOAUTH2, ConnectionSecurity.NONE); try { @@ -380,7 +393,7 @@ public class SmtpTransportTest { assertEquals("Authentication method XOAUTH2 is unavailable.", e.getMessage()); } - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); } @@ -408,6 +421,8 @@ public class SmtpTransportTest { server.expect("EHLO localhost"); server.output("250-localhost Hello client.localhost"); server.output("250 AUTH"); + server.expect("QUIT"); + server.output("221 BYE"); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.EXTERNAL, ConnectionSecurity.NONE); try { @@ -417,7 +432,7 @@ public class SmtpTransportTest { assertEquals(CertificateValidationException.Reason.MissingCapability, e.getReason()); } - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); } @@ -449,6 +464,8 @@ public class SmtpTransportTest { server.expect("EHLO localhost"); server.output("250-localhost Hello client.localhost"); server.output("250 AUTH PLAIN LOGIN"); + server.expect("QUIT"); + server.output("221 BYE"); SmtpTransport transport = startServerAndCreateSmtpTransport(server, AuthType.AUTOMATIC, ConnectionSecurity.NONE); @@ -460,7 +477,7 @@ public class SmtpTransportTest { e.getMessage()); } - server.verifyConnectionStillOpen(); + server.verifyConnectionClosed(); server.verifyInteractionCompleted(); }