Introduce client cert alias for HostAuth.

Some email servers require client certificates to be presented to
establish an SSL connection. While this certificate will be maintained
by the system key store, we need to store the "alias" of the certificate
stored in that system store.

Wiring up to use the actual alias will be done in future CL's. It is
currently unused.

Change-Id: I8d1290151342daea9ceb0df8a4088405b44faa81
This commit is contained in:
Ben Komalo 2011-06-07 11:39:16 -07:00
parent 4431a74be5
commit 313586c8eb
13 changed files with 252 additions and 102 deletions

View File

@ -2313,6 +2313,8 @@ public abstract class EmailContent {
static final String PASSWORD = "password";
// A domain or path, if required (used in IMAP and EAS)
static final String DOMAIN = "domain";
// An alias to a local client certificate for SSL
static final String CLIENT_CERT_ALIAS = "certAlias";
// DEPRECATED - Will not be set or stored
static final String ACCOUNT_KEY = "accountKey";
}

View File

@ -41,6 +41,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
public static final String SCHEME_POP3 = "pop3";
public static final String SCHEME_EAS = "eas";
public static final String SCHEME_SMTP = "smtp";
public static final String SCHEME_TRUST_ALL_CERTS = "trustallcerts";
public static final int PORT_UNKNOWN = -1;
@ -59,6 +60,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
public String mLogin;
public String mPassword;
public String mDomain;
public String mClientCertAlias = null;
public static final int CONTENT_ID_COLUMN = 0;
public static final int CONTENT_PROTOCOL_COLUMN = 1;
@ -68,11 +70,12 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
public static final int CONTENT_LOGIN_COLUMN = 5;
public static final int CONTENT_PASSWORD_COLUMN = 6;
public static final int CONTENT_DOMAIN_COLUMN = 7;
public static final int CONTENT_CLIENT_CERT_ALIAS_COLUMN = 8;
public static final String[] CONTENT_PROJECTION = new String[] {
RECORD_ID, HostAuthColumns.PROTOCOL, HostAuthColumns.ADDRESS, HostAuthColumns.PORT,
HostAuthColumns.FLAGS, HostAuthColumns.LOGIN,
HostAuthColumns.PASSWORD, HostAuthColumns.DOMAIN
HostAuthColumns.PASSWORD, HostAuthColumns.DOMAIN, HostAuthColumns.CLIENT_CERT_ALIAS
};
/**
@ -101,6 +104,14 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
* Returns the scheme for the specified flags.
*/
public static String getSchemeString(String protocol, int flags) {
return getSchemeString(protocol, flags, null);
}
/**
* Builds a URI scheme name given the parameters for a {@code HostAuth}.
* If a {@code clientAlias} is provided, this indicates that a secure connection must be used.
*/
public static String getSchemeString(String protocol, int flags, String clientAlias) {
String security = "";
switch (flags & USER_CONFIG_MASK) {
case FLAG_SSL:
@ -116,6 +127,21 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
security = "+tls+trustallcerts";
break;
}
if (!TextUtils.isEmpty(clientAlias)) {
if (TextUtils.isEmpty(security)) {
throw new IllegalArgumentException(
"Can't specify a certificate alias for a non-secure connection");
}
// TODO: investigate what the certificate aliases look like from the framework
// and ensure they're safe scheme names.
String safeScheme = clientAlias;
if (!security.endsWith("+")) {
security += "+";
}
security += safeScheme;
}
return protocol + security;
}
@ -134,7 +160,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
}
if (schemeParts.length >= 3) {
String part2 = schemeParts[2];
if ("trustallcerts".equals(part2)) {
if (SCHEME_TRUST_ALL_CERTS.equals(part2)) {
flags |= HostAuth.FLAG_TRUST_ALL;
}
}
@ -153,6 +179,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
mLogin = cursor.getString(CONTENT_LOGIN_COLUMN);
mPassword = cursor.getString(CONTENT_PASSWORD_COLUMN);
mDomain = cursor.getString(CONTENT_DOMAIN_COLUMN);
mClientCertAlias = cursor.getString(CONTENT_CLIENT_CERT_ALIAS_COLUMN);
}
@Override
@ -165,6 +192,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
values.put(HostAuthColumns.LOGIN, mLogin);
values.put(HostAuthColumns.PASSWORD, mPassword);
values.put(HostAuthColumns.DOMAIN, mDomain);
values.put(HostAuthColumns.CLIENT_CERT_ALIAS, mClientCertAlias);
values.put(HostAuthColumns.ACCOUNT_KEY, 0); // Need something to satisfy the DB
return values;
}
@ -202,6 +230,33 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
}
}
/**
* Legacy URI parser. Used in one of three different scenarios:
* 1. Backup / Restore of account
* 2. Parsing template from provider.xml
* 3. Forcefully creating URI for test
* Example string:
* "eas+ssl+trustallcerts://user:password@server/domain:123"
*
* Note that the use of client certificate is specified in the URI, a secure connection type
* must be used.
*/
public static void setHostAuthFromString(HostAuth auth, String uriString)
throws URISyntaxException {
URI uri = new URI(uriString);
String path = uri.getPath();
String domain = null;
if (!TextUtils.isEmpty(path)) {
// Strip off the leading slash that begins the path.
domain = path.substring(1);
}
auth.mDomain = domain;
auth.setLogin(uri.getUserInfo());
String scheme = uri.getScheme();
auth.setConnection(scheme, uri.getHost(), uri.getPort());
}
/**
* Sets the user name and password from URI user info string
*/
@ -251,18 +306,48 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
public void setConnection(String scheme, String host, int port) {
String[] schemeParts = scheme.split("\\+");
String protocol = schemeParts[0];
String clientCertAlias = null;
int flags = getSchemeFlags(scheme);
setConnection(protocol, host, port, flags);
// Example scheme: "eas+ssl+trustallcerts" or "eas+tls+trustallcerts+client-cert-alias"
if (schemeParts.length > 3) {
clientCertAlias = schemeParts[3];
} else if (schemeParts.length > 2) {
if (!SCHEME_TRUST_ALL_CERTS.equals(schemeParts[2])) {
mClientCertAlias = schemeParts[2];
}
}
setConnection(protocol, host, port, flags, clientCertAlias);
}
public void setConnection(String protocol, String address, int port, int flags) {
setConnection(protocol, address, port, flags, null);
}
/**
* Sets the internal connection parameters based on the specified parameter values.
* @param protocol the mail protocol to use (e.g. "eas", "imap").
* @param address the address of the server
* @param port the port for the connection
* @param flags flags indicating the security and type of the connection
* @param clientCertAlias an optional alias to use if a client user certificate is to be
* presented during connection establishment. If this is non-empty, it must be the case
* that flags indicates use of a secure connection
*/
public void setConnection(String protocol, String address,
int port, int flags, String clientCertAlias) {
// Set protocol, security, and additional flags based on uri scheme
mProtocol = protocol;
mFlags &= ~(FLAG_SSL | FLAG_TLS | FLAG_TRUST_ALL);
mFlags |= (flags & USER_CONFIG_MASK);
boolean useSecureConnection = (flags & (FLAG_SSL | FLAG_TLS)) != 0;
if (!useSecureConnection && !TextUtils.isEmpty(clientCertAlias)) {
throw new IllegalArgumentException("Can't use client alias on non-secure connections");
}
mAddress = address;
mPort = port;
if (mPort == PORT_UNKNOWN) {
@ -283,6 +368,8 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
mPort = useSSL ? 465 : 587;
}
}
mClientCertAlias = clientCertAlias;
}
/** Returns {@code true} if this is an EAS connection; otherwise, {@code false}. */
@ -328,6 +415,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
dest.writeString(mLogin);
dest.writeString(mPassword);
dest.writeString(mDomain);
dest.writeString(mClientCertAlias);
}
/**
@ -343,6 +431,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
mLogin = in.readString();
mPassword = in.readString();
mDomain = in.readString();
mClientCertAlias = in.readString();
}
/**
@ -365,6 +454,7 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
&& Utility.areStringsEqual(mAddress, that.mAddress)
&& Utility.areStringsEqual(mLogin, that.mLogin)
&& Utility.areStringsEqual(mPassword, that.mPassword)
&& Utility.areStringsEqual(mDomain, that.mDomain);
&& Utility.areStringsEqual(mDomain, that.mDomain)
&& Utility.areStringsEqual(mClientCertAlias, that.mClientCertAlias);
}
}

View File

@ -63,8 +63,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
@ -1059,25 +1057,6 @@ public class Utility {
}
}
/**
* Legacy URI parser. Used in one of three different scenarios:
* 1. Backup / Restore of account
* 2. Parsing template from provider.xml
* 3. Forcefully creating URI for test
*/
public static void setHostAuthFromString(HostAuth auth, String uriString)
throws URISyntaxException {
URI uri = new URI(uriString);
String path = uri.getPath();
String domain = null;
if (path != null && path.length() > 0) {
domain = path.substring(1);
}
auth.mDomain = domain;
auth.setLogin(uri.getUserInfo());
auth.setConnection(uri.getScheme(), uri.getHost(), uri.getPort());
}
/**
* Test that the given strings are equal in a null-pointer safe fashion.
*/

View File

@ -425,11 +425,11 @@ public class AccountSetupBasics extends AccountSetupActivity
Account account = SetupData.getAccount();
HostAuth recvAuth = account.getOrCreateHostAuthRecv(this);
Utility.setHostAuthFromString(recvAuth, mProvider.incomingUri);
HostAuth.setHostAuthFromString(recvAuth, mProvider.incomingUri);
recvAuth.setLogin(mProvider.incomingUsername, password);
HostAuth sendAuth = account.getOrCreateHostAuthSend(this);
Utility.setHostAuthFromString(sendAuth, mProvider.outgoingUri);
HostAuth.setHostAuthFromString(sendAuth, mProvider.outgoingUri);
sendAuth.setLogin(mProvider.outgoingUsername, password);
// Populate the setup data, assuming that the duplicate account check will succeed
@ -576,10 +576,10 @@ public class AccountSetupBasics extends AccountSetupActivity
Account account = SetupData.getAccount();
try {
HostAuth recvAuth = account.getOrCreateHostAuthRecv(this);
Utility.setHostAuthFromString(recvAuth, incoming);
HostAuth.setHostAuthFromString(recvAuth, incoming);
HostAuth sendAuth = account.getOrCreateHostAuthSend(this);
Utility.setHostAuthFromString(sendAuth, outgoing);
HostAuth.setHostAuthFromString(sendAuth, outgoing);
populateSetupData(user, email, false);
} catch (URISyntaxException e) {

View File

@ -61,7 +61,16 @@ public class MailTransport implements Transport {
private String mHost;
private int mPort;
private String[] mUserInfoParts;
/**
* One of the {@code Transport.CONNECTION_SECURITY_*} values.
*/
private int mConnectionSecurity;
/**
* Whether or not to trust all server certificates (i.e. skip host verification) in SSL
* handshakes
*/
private boolean mTrustCertificates;
private Socket mSocket;
@ -131,7 +140,7 @@ public class MailTransport implements Transport {
@Override
public boolean canTrySslSecurity() {
return mConnectionSecurity == CONNECTION_SECURITY_SSL;
return mConnectionSecurity == Transport.CONNECTION_SECURITY_SSL;
}
@Override

View File

@ -141,8 +141,9 @@ public class EmailProvider extends ContentProvider {
// Version 21: Add lastSeenMessageKey column to Mailbox table
// Version 22: Upgrade path for IMAP/POP accounts to integrate with AccountManager
// Version 23: Add column to mailbox table for time of last access
// Version 24: Add column to hostauth table for client cert alias
public static final int DATABASE_VERSION = 23;
public static final int DATABASE_VERSION = 24;
// Any changes to the database format *must* include update-in-place code.
// Original version: 2
@ -607,7 +608,8 @@ public class EmailProvider extends ContentProvider {
+ HostAuthColumns.LOGIN + " text, "
+ HostAuthColumns.PASSWORD + " text, "
+ HostAuthColumns.DOMAIN + " text, "
+ HostAuthColumns.ACCOUNT_KEY + " integer"
+ HostAuthColumns.ACCOUNT_KEY + " integer,"
+ HostAuthColumns.CLIENT_CERT_ALIAS + " text"
+ ");";
db.execSQL("create table " + HostAuth.TABLE_NAME + s);
}
@ -1084,6 +1086,10 @@ public class EmailProvider extends ContentProvider {
upgradeFromVersion22ToVersion23(db);
oldVersion = 23;
}
if (oldVersion == 23) {
upgradeFromVersion23ToVersion24(db);
oldVersion = 24;
}
}
@Override
@ -2087,4 +2093,15 @@ public class EmailProvider extends ContentProvider {
Log.w(TAG, "Exception upgrading EmailProvider.db from 22 to 23 " + e);
}
}
/** Adds in a column for information about a client certificate to use. */
private static void upgradeFromVersion23ToVersion24(SQLiteDatabase db) {
try {
db.execSQL("alter table " + HostAuth.TABLE_NAME
+ " add column " + HostAuth.CLIENT_CERT_ALIAS + " text;");
} catch (SQLException e) {
// Shouldn't be needed unless we're debugging and interrupt the process
Log.w(TAG, "Exception upgrading EmailProvider.db from 23 to 24 " + e);
}
}
}

View File

@ -18,7 +18,7 @@ package com.android.email.activity.setup;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.utility.Utility;
import com.android.emailcommon.provider.HostAuth;
import android.content.ContentUris;
import android.content.Context;
@ -164,8 +164,8 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
mAccount.setSenderName(name);
// For EAS, at least, email address is required
mAccount.mEmailAddress = "user@server.com";
Utility.setHostAuthFromString(mAccount.getOrCreateHostAuthRecv(mContext), storeUri);
Utility.setHostAuthFromString(mAccount.getOrCreateHostAuthSend(mContext), senderUri);
HostAuth.setHostAuthFromString(mAccount.getOrCreateHostAuthRecv(mContext), storeUri);
HostAuth.setHostAuthFromString(mAccount.getOrCreateHostAuthSend(mContext), senderUri);
mAccount.save(mContext);
mAccountId = mAccount.mId;

View File

@ -20,7 +20,6 @@ import com.android.email.R;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.utility.Utility;
import android.content.ContentUris;
import android.content.Context;
@ -119,7 +118,7 @@ public class AccountSetupAccountTypeTests
throws URISyntaxException {
Account account = new Account();
HostAuth auth = account.getOrCreateHostAuthRecv(mContext);
Utility.setHostAuthFromString(auth, scheme + "://user:pass@server.com:123");
HostAuth.setHostAuthFromString(auth, scheme + "://user:pass@server.com:123");
account.save(mContext);
mAccounts.add(account);
SetupData.init(SetupData.FLOW_MODE_NORMAL, account);

View File

@ -21,7 +21,6 @@ import com.android.email.provider.ProviderTestUtils;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.utility.Utility;
import android.content.Context;
import android.content.Intent;
@ -242,7 +241,7 @@ public class AccountSetupExchangeTests extends
EmailContent.Account account = new EmailContent.Account();
Context context = getInstrumentation().getTargetContext();
HostAuth auth = account.getOrCreateHostAuthRecv(context);
Utility.setHostAuthFromString(auth, storeUriString);
HostAuth.setHostAuthFromString(auth, storeUriString);
Intent i = new Intent(Intent.ACTION_MAIN);
SetupData.init(SetupData.FLOW_MODE_NORMAL, account);
SetupData.setAllowAutodiscover(false);

View File

@ -19,7 +19,6 @@ package com.android.email.activity.setup;
import com.android.email.R;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.utility.Utility;
import android.content.Context;
import android.content.Intent;
@ -195,7 +194,7 @@ public class AccountSetupIncomingTests extends
EmailContent.Account account = new EmailContent.Account();
Context context = getInstrumentation().getTargetContext();
HostAuth auth = account.getOrCreateHostAuthRecv(context);
Utility.setHostAuthFromString(auth, storeUriString);
HostAuth.setHostAuthFromString(auth, storeUriString);
SetupData.init(SetupData.FLOW_MODE_NORMAL, account);
return new Intent(Intent.ACTION_MAIN);
}

View File

@ -20,7 +20,6 @@ import com.android.email.R;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.utility.Utility;
import android.content.Context;
import android.content.Intent;
@ -181,7 +180,7 @@ public class AccountSetupOptionsTests
account.setSenderName(name);
Context context = getInstrumentation().getTargetContext();
HostAuth auth = account.getOrCreateHostAuthRecv(context);
Utility.setHostAuthFromString(auth, storeUri);
HostAuth.setHostAuthFromString(auth, storeUri);
SetupData.init(SetupData.FLOW_MODE_NORMAL, account);
return new Intent(Intent.ACTION_MAIN);
}

View File

@ -19,7 +19,6 @@ package com.android.email.activity.setup;
import com.android.email.R;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.utility.Utility;
import android.content.Context;
import android.content.Intent;
@ -191,7 +190,7 @@ public class AccountSetupOutgoingTests extends
EmailContent.Account account = new EmailContent.Account();
Context context = getInstrumentation().getTargetContext();
HostAuth auth = account.getOrCreateHostAuthSend(context);
Utility.setHostAuthFromString(auth, senderUriString);
HostAuth.setHostAuthFromString(auth, senderUriString);
SetupData.init(SetupData.FLOW_MODE_NORMAL, account);
return new Intent(Intent.ACTION_MAIN);
}

View File

@ -17,7 +17,6 @@
package com.android.emailcommon.provider;
import com.android.email.provider.ProviderTestUtils;
import com.android.emailcommon.utility.Utility;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@ -41,15 +40,15 @@ public class HostAuthTests extends AndroidTestCase {
HostAuth.FLAG_SSL | HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL;
// Set various URIs and check the resulting flags
Utility.setHostAuthFromString(ha, "protocol://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol://user:password@server:123");
assertEquals(0, ha.mFlags & MASK);
Utility.setHostAuthFromString(ha, "protocol+ssl+://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol+ssl+://user:password@server:123");
assertEquals(HostAuth.FLAG_SSL, ha.mFlags & MASK);
Utility.setHostAuthFromString(ha, "protocol+ssl+trustallcerts://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol+ssl+trustallcerts://user:password@server:123");
assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, ha.mFlags & MASK);
Utility.setHostAuthFromString(ha, "protocol+tls+://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol+tls+://user:password@server:123");
assertEquals(HostAuth.FLAG_TLS, ha.mFlags & MASK);
Utility.setHostAuthFromString(ha, "protocol+tls+trustallcerts://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol+tls+trustallcerts://user:password@server:123");
assertEquals(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL, ha.mFlags & MASK);
// Now check the retrival method (building URI from flags)
@ -80,59 +79,59 @@ public class HostAuthTests extends AndroidTestCase {
// Set various URIs and check the resulting flags
// Hardwired port
Utility.setHostAuthFromString(ha, "imap://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "imap://user:password@server:123");
assertEquals(123, ha.mPort);
// Auto-assigned ports
Utility.setHostAuthFromString(ha, "imap://user:password@server");
HostAuth.setHostAuthFromString(ha, "imap://user:password@server");
assertEquals(143, ha.mPort);
Utility.setHostAuthFromString(ha, "imap+ssl://user:password@server");
HostAuth.setHostAuthFromString(ha, "imap+ssl://user:password@server");
assertEquals(993, ha.mPort);
Utility.setHostAuthFromString(ha, "imap+ssl+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "imap+ssl+trustallcerts://user:password@server");
assertEquals(993, ha.mPort);
Utility.setHostAuthFromString(ha, "imap+tls://user:password@server");
HostAuth.setHostAuthFromString(ha, "imap+tls://user:password@server");
assertEquals(143, ha.mPort);
Utility.setHostAuthFromString(ha, "imap+tls+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "imap+tls+trustallcerts://user:password@server");
assertEquals(143, ha.mPort);
// Hardwired port
Utility.setHostAuthFromString(ha, "pop3://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "pop3://user:password@server:123");
assertEquals(123, ha.mPort);
// Auto-assigned ports
Utility.setHostAuthFromString(ha, "pop3://user:password@server");
HostAuth.setHostAuthFromString(ha, "pop3://user:password@server");
assertEquals(110, ha.mPort);
Utility.setHostAuthFromString(ha, "pop3+ssl://user:password@server");
HostAuth.setHostAuthFromString(ha, "pop3+ssl://user:password@server");
assertEquals(995, ha.mPort);
Utility.setHostAuthFromString(ha, "pop3+ssl+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "pop3+ssl+trustallcerts://user:password@server");
assertEquals(995, ha.mPort);
Utility.setHostAuthFromString(ha, "pop3+tls://user:password@server");
HostAuth.setHostAuthFromString(ha, "pop3+tls://user:password@server");
assertEquals(110, ha.mPort);
Utility.setHostAuthFromString(ha, "pop3+tls+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "pop3+tls+trustallcerts://user:password@server");
assertEquals(110, ha.mPort);
// Hardwired port
Utility.setHostAuthFromString(ha, "eas://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "eas://user:password@server:123");
assertEquals(123, ha.mPort);
// Auto-assigned ports
Utility.setHostAuthFromString(ha, "eas://user:password@server");
HostAuth.setHostAuthFromString(ha, "eas://user:password@server");
assertEquals(80, ha.mPort);
Utility.setHostAuthFromString(ha, "eas+ssl://user:password@server");
HostAuth.setHostAuthFromString(ha, "eas+ssl://user:password@server");
assertEquals(443, ha.mPort);
Utility.setHostAuthFromString(ha, "eas+ssl+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "eas+ssl+trustallcerts://user:password@server");
assertEquals(443, ha.mPort);
// Hardwired port
Utility.setHostAuthFromString(ha, "smtp://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "smtp://user:password@server:123");
assertEquals(123, ha.mPort);
// Auto-assigned ports
Utility.setHostAuthFromString(ha, "smtp://user:password@server");
HostAuth.setHostAuthFromString(ha, "smtp://user:password@server");
assertEquals(587, ha.mPort);
Utility.setHostAuthFromString(ha, "smtp+ssl://user:password@server");
HostAuth.setHostAuthFromString(ha, "smtp+ssl://user:password@server");
assertEquals(465, ha.mPort);
Utility.setHostAuthFromString(ha, "smtp+ssl+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "smtp+ssl+trustallcerts://user:password@server");
assertEquals(465, ha.mPort);
Utility.setHostAuthFromString(ha, "smtp+tls://user:password@server");
HostAuth.setHostAuthFromString(ha, "smtp+tls://user:password@server");
assertEquals(587, ha.mPort);
Utility.setHostAuthFromString(ha, "smtp+tls+trustallcerts://user:password@server");
HostAuth.setHostAuthFromString(ha, "smtp+tls+trustallcerts://user:password@server");
assertEquals(587, ha.mPort);
}
@ -142,17 +141,17 @@ public class HostAuthTests extends AndroidTestCase {
public void testGetStoreUri()
throws URISyntaxException {
HostAuth ha = new HostAuth();
Utility.setHostAuthFromString(ha, "protocol://user:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol://user:password@server:123");
String getUri = ha.getStoreUri();
assertEquals("protocol://user:password@server:123", getUri);
// Now put spaces in/around username (they are trimmed)
Utility.setHostAuthFromString(ha, "protocol://%20us%20er%20:password@server:123");
HostAuth.setHostAuthFromString(ha, "protocol://%20us%20er%20:password@server:123");
getUri = ha.getStoreUri();
assertEquals("protocol://us%20er:password@server:123", getUri);
// Now put spaces around password (should not be trimmed)
Utility.setHostAuthFromString(ha, "protocol://user:%20pass%20word%20@server:123");
HostAuth.setHostAuthFromString(ha, "protocol://user:%20pass%20word%20@server:123");
getUri = ha.getStoreUri();
assertEquals("protocol://user:%20pass%20word%20@server:123", getUri);
}
@ -228,10 +227,7 @@ public class HostAuthTests extends AndroidTestCase {
assertEquals(~HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
}
/**
* Test setting the connection using a URI scheme
*/
public void testSetConnectionScheme() {
public void testImapConnectionScheme() {
HostAuth ha = new HostAuth();
// Set URIs for IMAP
@ -260,6 +256,10 @@ public class HostAuthTests extends AndroidTestCase {
ha.setConnection("imap+tls+trustallcerts", "server", -1);
assertEquals(HostAuth.FLAG_TLS|HostAuth.FLAG_TRUST_ALL, ha.mFlags);
assertEquals(143, ha.mPort);
}
public void testPopConnectionScheme() {
HostAuth ha = new HostAuth();
// Set URIs for POP3
// Hardwired port
@ -287,6 +287,10 @@ public class HostAuthTests extends AndroidTestCase {
ha.setConnection("pop3+tls+trustallcerts", "server", -1);
assertEquals(HostAuth.FLAG_TLS|HostAuth.FLAG_TRUST_ALL, ha.mFlags);
assertEquals(110, ha.mPort);
}
public void testEasConnectionScheme() {
HostAuth ha = new HostAuth();
// Set URIs for Exchange
// Hardwired port
@ -306,6 +310,10 @@ public class HostAuthTests extends AndroidTestCase {
ha.setConnection("eas+ssl+trustallcerts", "server", -1);
assertEquals(HostAuth.FLAG_SSL|HostAuth.FLAG_TRUST_ALL, ha.mFlags);
assertEquals(443, ha.mPort);
}
public void testSmtpConnectionScheme() {
HostAuth ha = new HostAuth();
// Set URIs for SMTP
// Hardwired port
@ -362,30 +370,58 @@ public class HostAuthTests extends AndroidTestCase {
assertEquals(0, ha.mFlags);
// Sets SSL flag
ha.setConnection("imap", "server", -1, HostAuth.FLAG_SSL);
ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_SSL);
assertEquals(HostAuth.FLAG_SSL, ha.mFlags);
// Sets SSL+Trusted flags
ha.setConnection("imap", "server", -1, HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL);
ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN,
HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL);
assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, ha.mFlags);
// Sets TLS flag
ha.setConnection("imap", "server", -1, HostAuth.FLAG_TLS);
ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_TLS);
assertEquals(HostAuth.FLAG_TLS, ha.mFlags);
// Sets TLS+Trusted flags
ha.setConnection("imap", "server", -1, HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL);
ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN,
HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL);
assertEquals(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL, ha.mFlags);
// Test other defined flags; should not affect mFlags
ha.setConnection("imap", "server", -1, HostAuth.FLAG_AUTHENTICATE);
ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_AUTHENTICATE);
assertEquals(0, ha.mFlags);
// Test every other bit; should not affect mFlags
ha.setConnection("imap", "server", -1, 0xfffffff4);
ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, 0xfffffff4);
assertEquals(0, ha.mFlags);
}
public void testSetConnectionWithCerts() {
HostAuth ha = new HostAuth();
ha.setConnection("eas", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_SSL, "client-cert");
assertEquals(HostAuth.FLAG_SSL, ha.mFlags);
assertEquals("client-cert", ha.mClientCertAlias);
ha.setConnection("eas", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_TLS, "client-cert");
assertEquals(HostAuth.FLAG_TLS, ha.mFlags);
assertEquals("client-cert", ha.mClientCertAlias);
// Note that we can still trust all server certificates, even if we present a client
// user certificate.
ha.setConnection("eas", "server", HostAuth.PORT_UNKNOWN,
HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, "client-cert");
assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, ha.mFlags);
assertEquals("client-cert", ha.mClientCertAlias);
try {
ha.setConnection(
"eas", "server", HostAuth.PORT_UNKNOWN, 0 /* no flags */, "client-cert");
fail("Shouldn't be able to set a client certificate on an unsecure connection");
} catch (IllegalArgumentException expected) {
}
}
public void testGetSchemeString() {
String scheme;
@ -406,11 +442,29 @@ public class HostAuthTests extends AndroidTestCase {
assertEquals("foo", scheme);
scheme = HostAuth.getSchemeString("foo",
HostAuth.FLAG_SSL | HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL);
assertEquals("foo", scheme);
scheme = HostAuth.getSchemeString("foo", 0xfffffff4);
assertEquals("foo", scheme);
// Use of custom client certs.
scheme = HostAuth.getSchemeString("foo", HostAuth.FLAG_SSL, "custom-client-cert-alias");
assertEquals("foo+ssl+custom-client-cert-alias", scheme);
scheme = HostAuth.getSchemeString("foo", HostAuth.FLAG_TLS, "custom-client-cert-alias");
assertEquals("foo+tls+custom-client-cert-alias", scheme);
scheme = HostAuth.getSchemeString(
"foo", HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, "custom_client_cert_alias");
assertEquals("foo+ssl+trustallcerts+custom_client_cert_alias", scheme);
scheme = HostAuth.getSchemeString(
"foo", HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL, "custom_client_cert_alias");
assertEquals("foo+tls+trustallcerts+custom_client_cert_alias", scheme);
try {
scheme = HostAuth.getSchemeString(
"foo", 0 /* no security flags */, "custom_client_cert_alias");
fail("Should not be able to set a custom client cert on an insecure connection");
} catch (IllegalArgumentException expected) {
}
}
public void testGetSchemeFlags() {
int flags;
@ -453,61 +507,65 @@ public class HostAuthTests extends AndroidTestCase {
assertTrue(ha1.equals(ha2));
assertTrue(ha2.equals(ha1));
Utility.setHostAuthFromString(ha1, "smtp+tls+://user:password@server/domain");
Utility.setHostAuthFromString(ha2, "smtp+tls+://user:password@server/domain");
HostAuth.setHostAuthFromString(ha1, "smtp+tls+://user:password@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user:password@server/domain");
assertTrue(ha1.equals(ha2));
assertTrue(ha2.equals(ha1));
// Different protocol
Utility.setHostAuthFromString(ha2, "imap+tls+://user:password@server/domain");
HostAuth.setHostAuthFromString(ha2, "imap+tls+://user:password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Different domain
Utility.setHostAuthFromString(ha2, "smtp+tls+://user:password@server/domain2");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user:password@server/domain2");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Missing server
Utility.setHostAuthFromString(ha2, "smtp+tls+://user:password/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user:password/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Missing domain
Utility.setHostAuthFromString(ha2, "smtp+tls+://user:password@server");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user:password@server");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Different server
Utility.setHostAuthFromString(ha2, "smtp+tls+://user:password@server2/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user:password@server2/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Different password
Utility.setHostAuthFromString(ha2, "smtp+tls+://user:password2@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user:password2@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Different user name
Utility.setHostAuthFromString(ha2, "smtp+tls+://user2:password@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user2:password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Missing password
Utility.setHostAuthFromString(ha2, "smtp+tls+://user@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://user@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Missing user name
Utility.setHostAuthFromString(ha2, "smtp+tls+://password@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Missing user name & password
Utility.setHostAuthFromString(ha2, "smtp+tls+://server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+://server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Added "trustallcerts"
Utility.setHostAuthFromString(ha2, "smtp+tls+trustallcerts://user:password@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+tls+trustallcerts://user:password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Different authentication
Utility.setHostAuthFromString(ha2, "smtp+ssl+://user:password@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+ssl+://user:password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Missing authentication
Utility.setHostAuthFromString(ha2, "smtp+://user:password@server/domain");
HostAuth.setHostAuthFromString(ha2, "smtp+://user:password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
// Use of custom certificate
HostAuth.setHostAuthFromString(ha2, "smtp+ssl+clientcert://user:password@server/domain");
assertFalse(ha1.equals(ha2));
assertFalse(ha2.equals(ha1));
ha2 = null;