1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-24 02:12:15 -05:00

Implement SMTP AUTH EXTERNAL

Also, simplify by using Utility.base64Encode(String) in lieu of
new String(Base64.encodeBase64(String.getBytes())
This commit is contained in:
Joe Steele 2014-07-26 13:35:19 -04:00
parent c0be0eea12
commit b557ba008c
2 changed files with 39 additions and 9 deletions

View File

@ -1107,6 +1107,8 @@ Please submit bug reports, contribute new features and ask questions at
<string name="fetching_attachment_dialog_title_save">Saving draft</string> <string name="fetching_attachment_dialog_title_save">Saving draft</string>
<string name="fetching_attachment_dialog_message">Fetching attachment…</string> <string name="fetching_attachment_dialog_message">Fetching attachment…</string>
<string name="auth_external_error">Unable to authenticate. The server does not advertise the SASL EXTERNAL capability. This could be due to a problem with the client certificate (expired, unknown certificate authority) or some other configuration problem.</string>
<!-- === OpenPGP specific ================================================================== --> <!-- === OpenPGP specific ================================================================== -->
<string name="openpgp_decrypting_verifying">Decrypting/Verifying…</string> <string name="openpgp_decrypting_verifying">Decrypting/Verifying…</string>
<string name="openpgp_successful_decryption">Successful decryption</string> <string name="openpgp_successful_decryption">Successful decryption</string>

View File

@ -5,9 +5,10 @@ import android.util.Log;
import com.fsck.k9.Account; import com.fsck.k9.Account;
import com.fsck.k9.K9; import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.*; import com.fsck.k9.mail.*;
import com.fsck.k9.mail.Message.RecipientType; import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.mail.filter.Base64;
import com.fsck.k9.mail.filter.EOLConvertingOutputStream; import com.fsck.k9.mail.filter.EOLConvertingOutputStream;
import com.fsck.k9.mail.filter.LineWrapOutputStream; import com.fsck.k9.mail.filter.LineWrapOutputStream;
import com.fsck.k9.mail.filter.PeekableInputStream; import com.fsck.k9.mail.filter.PeekableInputStream;
@ -307,11 +308,13 @@ public class SmtpTransport extends Transport {
boolean authLoginSupported = false; boolean authLoginSupported = false;
boolean authPlainSupported = false; boolean authPlainSupported = false;
boolean authCramMD5Supported = false; boolean authCramMD5Supported = false;
boolean authExternalSupported = false;
if (extensions.containsKey("AUTH")) { if (extensions.containsKey("AUTH")) {
List<String> saslMech = Arrays.asList(extensions.get("AUTH").split(" ")); List<String> saslMech = Arrays.asList(extensions.get("AUTH").split(" "));
authLoginSupported = saslMech.contains("LOGIN"); authLoginSupported = saslMech.contains("LOGIN");
authPlainSupported = saslMech.contains("PLAIN"); authPlainSupported = saslMech.contains("PLAIN");
authCramMD5Supported = saslMech.contains("CRAM-MD5"); authCramMD5Supported = saslMech.contains("CRAM-MD5");
authExternalSupported = saslMech.contains("EXTERNAL");
} }
if (extensions.containsKey("SIZE")) { if (extensions.containsKey("SIZE")) {
try { try {
@ -323,8 +326,10 @@ public class SmtpTransport extends Transport {
} }
} }
if (mUsername != null && mUsername.length() > 0 && if (mUsername != null
mPassword != null && mPassword.length() > 0) { && mUsername.length() > 0
&& (mPassword != null && mPassword.length() > 0 || AuthType.EXTERNAL
.equals(mAuthType))) {
switch (mAuthType) { switch (mAuthType) {
@ -353,6 +358,24 @@ public class SmtpTransport extends Transport {
} }
break; break;
case EXTERNAL:
if (authExternalSupported) {
saslAuthExternal(mUsername);
} else {
/*
* Some SMTP servers are known to provide no error
* indication when a client certificate fails to
* validate, other than to not offer the AUTH EXTERNAL
* capability.
*
* So, we treat it is an error to not offer AUTH
* EXTERNAL when using client certificates. That way, the
* user can be notified of a problem during account setup.
*/
throw new MessagingException(K9.app.getString(R.string.auth_external_error));
}
break;
/* /*
* AUTOMATIC is an obsolete option which is unavailable to users, * AUTOMATIC is an obsolete option which is unavailable to users,
* but it still may exist in a user's settings from a previous * but it still may exist in a user's settings from a previous
@ -688,8 +711,8 @@ public class SmtpTransport extends Transport {
AuthenticationFailedException, IOException { AuthenticationFailedException, IOException {
try { try {
executeSimpleCommand("AUTH LOGIN"); executeSimpleCommand("AUTH LOGIN");
executeSimpleCommand(new String(Base64.encodeBase64(username.getBytes())), true); executeSimpleCommand(Utility.base64Encode(username), true);
executeSimpleCommand(new String(Base64.encodeBase64(password.getBytes())), true); executeSimpleCommand(Utility.base64Encode(password), true);
} catch (MessagingException me) { } catch (MessagingException me) {
if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') { if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') {
throw new AuthenticationFailedException("AUTH LOGIN failed (" + me.getMessage() throw new AuthenticationFailedException("AUTH LOGIN failed (" + me.getMessage()
@ -701,10 +724,9 @@ public class SmtpTransport extends Transport {
private void saslAuthPlain(String username, String password) throws MessagingException, private void saslAuthPlain(String username, String password) throws MessagingException,
AuthenticationFailedException, IOException { AuthenticationFailedException, IOException {
byte[] data = ("\000" + username + "\000" + password).getBytes(); String data = Utility.base64Encode("\000" + username + "\000" + password);
data = new Base64().encode(data);
try { try {
executeSimpleCommand("AUTH PLAIN " + new String(data), true); executeSimpleCommand("AUTH PLAIN " + data, true);
} catch (MessagingException me) { } catch (MessagingException me) {
if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') { if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') {
throw new AuthenticationFailedException("AUTH PLAIN failed (" + me.getMessage() throw new AuthenticationFailedException("AUTH PLAIN failed (" + me.getMessage()
@ -732,6 +754,12 @@ public class SmtpTransport extends Transport {
} }
} }
private void saslAuthExternal(String username) throws MessagingException, IOException {
executeSimpleCommand(
String.format("AUTH EXTERNAL %s",
Utility.base64Encode(username)), false);
}
/** /**
* Exception that is thrown when the server sends a negative reply (reply codes 4xx or 5xx). * Exception that is thrown when the server sends a negative reply (reply codes 4xx or 5xx).
*/ */