Rework EAS account creation & ssl operation
* Fixes 2048663, 2025029, and 2100131 * Add "Trust Certificates" checkbox in EAS account creation * Use custom ClientConnectionManager for HttpClient with registry for plain, ssl, and tssl (trusted ssl) connection * Use a ConnectionPool for HttpClient connections * Remove "Domain" checkbox in EAS account creation * Remove tests related to the "Domain" field * TODO Write a test for valid usernames (requires a bit of research) <name>, <email address>, <domain>/<name, and <domain>\<name> are all valid, but there might be others Change-Id: I4a0338df5960bfd3d679a88aaf22d1c49f49992b
This commit is contained in:
parent
7f3f3f392d
commit
cef2344e70
@ -69,24 +69,16 @@
|
||||
android:imeOptions="actionDone"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
<TextView
|
||||
android:text="@string/account_setup_exchange_domain_label"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
<EditText
|
||||
android:id="@+id/account_domain"
|
||||
android:hint="@string/account_setup_exchange_domain_hint"
|
||||
inputType="text"
|
||||
android:imeOptions="actionDone"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
<CheckBox
|
||||
android:id="@+id/account_ssl"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:text="@string/account_setup_exchange_ssl_label" />
|
||||
<CheckBox
|
||||
android:id="@+id/account_trust_certificates"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:text="@string/account_setup_exchange_trust_certificates_label" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
|
@ -364,6 +364,8 @@
|
||||
<string name="account_setup_exchange_domain_hint">Enter domain here</string>
|
||||
<!-- On "Exchange" setup screen, the use-SSL checkbox label -->
|
||||
<string name="account_setup_exchange_ssl_label">Use secure connection (SSL)</string>
|
||||
<!-- On "Exchange" setup screen, the trust ssl certificates checkbox label -->
|
||||
<string name="account_setup_exchange_trust_certificates_label">Accept all SSL certificates</string>
|
||||
|
||||
<!-- In Account setup options screen, Activity title -->
|
||||
<string name="account_setup_options_title">Account options</string>
|
||||
|
@ -19,18 +19,20 @@ package com.android.email.activity.setup;
|
||||
import com.android.email.R;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@ -45,7 +47,8 @@ import java.net.URISyntaxException;
|
||||
* User (login)
|
||||
* Password
|
||||
*/
|
||||
public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
public class AccountSetupExchange extends Activity implements OnClickListener,
|
||||
OnCheckedChangeListener {
|
||||
private static final String EXTRA_ACCOUNT = "account";
|
||||
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
|
||||
private static final String EXTRA_EAS_FLOW = "easFlow";
|
||||
@ -53,14 +56,14 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
private EditText mUsernameView;
|
||||
private EditText mPasswordView;
|
||||
private EditText mServerView;
|
||||
private EditText mDomainView;
|
||||
private CheckBox mSslSecurityView;
|
||||
private CheckBox mTrustCertificatesView;
|
||||
|
||||
private Button mNextButton;
|
||||
private EmailContent.Account mAccount;
|
||||
private Account mAccount;
|
||||
private boolean mMakeDefault;
|
||||
|
||||
public static void actionIncomingSettings(Activity fromActivity, EmailContent.Account account,
|
||||
public static void actionIncomingSettings(Activity fromActivity, Account account,
|
||||
boolean makeDefault, boolean easFlowMode) {
|
||||
Intent i = new Intent(fromActivity, AccountSetupExchange.class);
|
||||
i.putExtra(EXTRA_ACCOUNT, account);
|
||||
@ -69,7 +72,7 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
fromActivity.startActivity(i);
|
||||
}
|
||||
|
||||
public static void actionEditIncomingSettings(Activity fromActivity, EmailContent.Account account)
|
||||
public static void actionEditIncomingSettings(Activity fromActivity, Account account)
|
||||
{
|
||||
Intent i = new Intent(fromActivity, AccountSetupExchange.class);
|
||||
i.setAction(Intent.ACTION_EDIT);
|
||||
@ -81,7 +84,7 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
* For now, we'll simply replicate outgoing, for the purpose of satisfying the
|
||||
* account settings flow.
|
||||
*/
|
||||
public static void actionEditOutgoingSettings(Activity fromActivity, EmailContent.Account account)
|
||||
public static void actionEditOutgoingSettings(Activity fromActivity, Account account)
|
||||
{
|
||||
Intent i = new Intent(fromActivity, AccountSetupExchange.class);
|
||||
i.setAction(Intent.ACTION_EDIT);
|
||||
@ -97,8 +100,9 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
mUsernameView = (EditText) findViewById(R.id.account_username);
|
||||
mPasswordView = (EditText) findViewById(R.id.account_password);
|
||||
mServerView = (EditText) findViewById(R.id.account_server);
|
||||
mDomainView = (EditText) findViewById(R.id.account_domain);
|
||||
mSslSecurityView = (CheckBox) findViewById(R.id.account_ssl);
|
||||
mSslSecurityView.setOnCheckedChangeListener(this);
|
||||
mTrustCertificatesView = (CheckBox) findViewById(R.id.account_trust_certificates);
|
||||
|
||||
mNextButton = (Button)findViewById(R.id.next);
|
||||
mNextButton.setOnClickListener(this);
|
||||
@ -121,7 +125,6 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
mUsernameView.addTextChangedListener(validationTextWatcher);
|
||||
mPasswordView.addTextChangedListener(validationTextWatcher);
|
||||
mServerView.addTextChangedListener(validationTextWatcher);
|
||||
mDomainView.addTextChangedListener(validationTextWatcher);
|
||||
|
||||
mAccount = (EmailContent.Account) getIntent().getParcelableExtra(EXTRA_ACCOUNT);
|
||||
mMakeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
|
||||
@ -164,12 +167,10 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
mServerView.setText(uri.getHost());
|
||||
}
|
||||
|
||||
String domain = uri.getPath();
|
||||
if (!TextUtils.isEmpty(domain)) {
|
||||
mDomainView.setText(domain.substring(1));
|
||||
}
|
||||
|
||||
mSslSecurityView.setChecked(uri.getScheme().contains("ssl"));
|
||||
boolean ssl = uri.getScheme().contains("ssl");
|
||||
mSslSecurityView.setChecked(ssl);
|
||||
mTrustCertificatesView.setChecked(uri.getScheme().contains("tssl"));
|
||||
mTrustCertificatesView.setVisibility(ssl ? View.VISIBLE : View.GONE);
|
||||
|
||||
} catch (URISyntaxException use) {
|
||||
/*
|
||||
@ -233,15 +234,12 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
*/
|
||||
private URI getUri() throws URISyntaxException {
|
||||
boolean sslRequired = mSslSecurityView.isChecked();
|
||||
String scheme = sslRequired ? "eas+ssl+" : "eas";
|
||||
boolean trustCertificates = mTrustCertificatesView.isChecked();
|
||||
String scheme = (sslRequired) ? (trustCertificates ? "eas+tssl+" : "eas+ssl+") : "eas";
|
||||
String userInfo = mUsernameView.getText().toString().trim() + ":" +
|
||||
mPasswordView.getText().toString().trim();
|
||||
String host = mServerView.getText().toString().trim();
|
||||
String domain = mDomainView.getText().toString().trim();
|
||||
String path = null;
|
||||
if (domain.length() > 0) {
|
||||
path = "/" + domain;
|
||||
}
|
||||
|
||||
URI uri = new URI(
|
||||
scheme,
|
||||
@ -281,4 +279,10 @@ public class AccountSetupExchange extends Activity implements OnClickListener {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (buttonView.getId() == R.id.account_ssl) {
|
||||
mTrustCertificatesView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ import java.util.HashMap;
|
||||
public class ExchangeStore extends Store {
|
||||
public static final String LOG_TAG = "ExchangeStore";
|
||||
|
||||
private Context mContext;
|
||||
private URI mUri;
|
||||
private final ExchangeTransport mTransport;
|
||||
|
||||
@ -66,7 +65,6 @@ public class ExchangeStore extends Store {
|
||||
*/
|
||||
private ExchangeStore(String _uri, Context context, PersistentDataCallbacks callbacks)
|
||||
throws MessagingException {
|
||||
mContext = context;
|
||||
try {
|
||||
mUri = new URI(_uri);
|
||||
} catch (URISyntaxException e) {
|
||||
@ -157,14 +155,14 @@ public class ExchangeStore extends Store {
|
||||
|
||||
private static HashMap<String, ExchangeTransport> sUriToInstanceMap =
|
||||
new HashMap<String, ExchangeTransport>();
|
||||
private static final HashMap<String, Integer> sFolderMap = new HashMap<String, Integer>();
|
||||
|
||||
/**
|
||||
* Public factory. The transport should be a singleton (per Uri)
|
||||
*/
|
||||
public synchronized static ExchangeTransport getInstance(URI uri, Context context)
|
||||
throws MessagingException {
|
||||
if (!uri.getScheme().equals("eas") && !uri.getScheme().equals("eas+ssl+")) {
|
||||
if (!uri.getScheme().equals("eas") && !uri.getScheme().equals("eas+ssl+") &&
|
||||
!uri.getScheme().equals("eas+tssl+")) {
|
||||
throw new MessagingException("Invalid scheme");
|
||||
}
|
||||
|
||||
@ -221,9 +219,11 @@ public class ExchangeStore extends Store {
|
||||
public void checkSettings(URI uri) throws MessagingException {
|
||||
setUri(uri);
|
||||
boolean ssl = uri.getScheme().contains("ssl+");
|
||||
boolean tssl = uri.getScheme().contains("tssl+");
|
||||
try {
|
||||
int port = ssl ? 443 : 80;
|
||||
int result = new EmailServiceProxy(mContext, SyncManager.class)
|
||||
.validate("eas", mHost, mUsername, mPassword, ssl ? 443 : 80, ssl);
|
||||
.validate("eas", mHost, mUsername, mPassword, port, ssl, tssl);
|
||||
if (result != MessagingException.NO_ERROR) {
|
||||
if (result == MessagingException.AUTHENTICATION_FAILED) {
|
||||
throw new AuthenticationFailedException("Authentication failed.");
|
||||
|
@ -16,18 +16,17 @@
|
||||
|
||||
package com.android.email.mail.store;
|
||||
|
||||
import org.apache.harmony.xnet.provider.jsse.SSLParameters;
|
||||
|
||||
import android.net.http.DomainNameChecker;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.harmony.xnet.provider.jsse.SSLParameters;
|
||||
|
||||
public final class TrustManagerFactory {
|
||||
private static X509TrustManager sUnsecureTrustManager
|
||||
= new SimpleX509TrustManager();
|
||||
private static X509TrustManager sUnsecureTrustManager = new SimpleX509TrustManager();
|
||||
|
||||
private static class SimpleX509TrustManager implements X509TrustManager {
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
@ -63,8 +62,7 @@ public final class TrustManagerFactory {
|
||||
mTrustManager.checkServerTrusted(chain, authType);
|
||||
|
||||
if (!DomainNameChecker.match(chain[0], mHost)) {
|
||||
throw new CertificateException("Certificate domain name does not match "
|
||||
+ mHost);
|
||||
throw new CertificateException("Certificate domain name does not match " + mHost);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,8 +75,7 @@ public final class TrustManagerFactory {
|
||||
}
|
||||
|
||||
public static X509TrustManager get(String host, boolean secure) {
|
||||
return secure ? new SecureX509TrustManager(
|
||||
SSLParameters.getDefaultTrustManager(), host)
|
||||
return secure ? new SecureX509TrustManager(SSLParameters.getDefaultTrustManager(), host)
|
||||
: sUnsecureTrustManager;
|
||||
}
|
||||
}
|
||||
|
@ -1916,6 +1916,7 @@ public abstract class EmailContent {
|
||||
public static final int FLAG_SSL = 1;
|
||||
public static final int FLAG_TLS = 2;
|
||||
public static final int FLAG_AUTHENTICATE = 4;
|
||||
public static final int FLAG_TRUST_ALL_CERTIFICATES = 8;
|
||||
|
||||
public String mProtocol;
|
||||
public String mAddress;
|
||||
@ -2013,7 +2014,9 @@ public abstract class EmailContent {
|
||||
*/
|
||||
public String getStoreUri() {
|
||||
String security = "";
|
||||
if ((mFlags & FLAG_SSL) != 0) {
|
||||
if ((mFlags & FLAG_TRUST_ALL_CERTIFICATES) != 0) {
|
||||
security = "+tssl+";
|
||||
} else if ((mFlags & FLAG_SSL) != 0) {
|
||||
security = "+ssl+";
|
||||
} else if ((mFlags & FLAG_TLS) != 0) {
|
||||
security = "+tls+";
|
||||
@ -2068,10 +2071,15 @@ public abstract class EmailContent {
|
||||
mProtocol = (schemeParts.length >= 1) ? schemeParts[0] : null;
|
||||
boolean ssl = false;
|
||||
boolean tls = false;
|
||||
boolean tssl = false;
|
||||
if (schemeParts.length >= 2) {
|
||||
if ("ssl".equals(schemeParts[1])) {
|
||||
String part1 = schemeParts[1];
|
||||
if ("tssl".equals(part1)) {
|
||||
ssl = true;
|
||||
} else if ("tls".equals(schemeParts[1])) {
|
||||
tssl = true;
|
||||
} else if ("ssl".equals(part1)) {
|
||||
ssl = true;
|
||||
} else if ("tls".equals(part1)) {
|
||||
tls = true;
|
||||
}
|
||||
}
|
||||
@ -2083,6 +2091,9 @@ public abstract class EmailContent {
|
||||
if (tls) {
|
||||
mFlags |= FLAG_TLS;
|
||||
}
|
||||
if (tssl) {
|
||||
mFlags |= FLAG_TRUST_ALL_CERTIFICATES;
|
||||
}
|
||||
|
||||
mAddress = uri.getHost();
|
||||
mPort = uri.getPort();
|
||||
@ -2092,11 +2103,11 @@ public abstract class EmailContent {
|
||||
if ("pop3".equals(mProtocol)) {
|
||||
mPort = ssl ? 995 : 110;
|
||||
} else if ("imap".equals(mProtocol)) {
|
||||
mPort = ssl ? 993 : 143;
|
||||
mPort = ssl || tssl ? 993 : 143;
|
||||
} else if ("eas".equals(mProtocol)) {
|
||||
mPort = ssl ? 443 : 80;
|
||||
mPort = ssl || tssl ? 443 : 80;
|
||||
} else if ("smtp".equals(mProtocol)) {
|
||||
mPort = ssl ? 465 : 25;
|
||||
mPort = ssl || tssl ? 465 : 25;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,12 +184,14 @@ public class EmailServiceProxy implements IEmailService {
|
||||
}
|
||||
|
||||
public int validate(final String protocol, final String host, final String userName,
|
||||
final String password, final int port, final boolean ssl) throws RemoteException {
|
||||
final String password, final int port, final boolean ssl,
|
||||
final boolean trustCertificates) throws RemoteException {
|
||||
setTask(new Runnable () {
|
||||
public void run() {
|
||||
try {
|
||||
if (mCallback != null) mService.setCallback(mCallback);
|
||||
mReturn = mService.validate(protocol, host, userName, password, port, ssl);
|
||||
mReturn = mService.validate(protocol, host, userName, password, port, ssl,
|
||||
trustCertificates);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ public abstract class AbstractSyncService implements Runnable {
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public abstract void validateAccount(String host, String userName, String password, int port,
|
||||
boolean ssl, Context context) throws MessagingException;
|
||||
boolean ssl, boolean trustCertificates, Context context) throws MessagingException;
|
||||
|
||||
public AbstractSyncService(Context _context, Mailbox _mailbox) {
|
||||
mContext = _context;
|
||||
@ -129,12 +129,13 @@ public abstract class AbstractSyncService implements Runnable {
|
||||
* @throws MessagingException
|
||||
*/
|
||||
static public void validate(Class<? extends AbstractSyncService> klass, String host,
|
||||
String userName, String password, int port, boolean ssl, Context context)
|
||||
String userName, String password, int port, boolean ssl, boolean trustCertificates,
|
||||
Context context)
|
||||
throws MessagingException {
|
||||
AbstractSyncService svc;
|
||||
try {
|
||||
svc = klass.newInstance();
|
||||
svc.validateAccount(host, userName, password, port, ssl, context);
|
||||
svc.validateAccount(host, userName, password, port, ssl, trustCertificates, context);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MessagingException("internal error", e);
|
||||
} catch (InstantiationException e) {
|
||||
|
@ -46,6 +46,7 @@ import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpOptions;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
@ -65,11 +66,11 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class EasSyncService extends AbstractSyncService {
|
||||
|
||||
private static final String EMAIL_WINDOW_SIZE = "5";
|
||||
public static final String PIM_WINDOW_SIZE = "20";
|
||||
private static final String WHERE_ACCOUNT_KEY_AND_SERVER_ID =
|
||||
@ -133,6 +134,7 @@ public class EasSyncService extends AbstractSyncService {
|
||||
public String mUserName;
|
||||
public String mPassword;
|
||||
private boolean mSsl = true;
|
||||
private boolean mTrustSsl = false;
|
||||
public ContentResolver mContentResolver;
|
||||
private String[] mBindArguments = new String[2];
|
||||
private ArrayList<String> mPingChangeList;
|
||||
@ -149,6 +151,7 @@ public class EasSyncService extends AbstractSyncService {
|
||||
mContentResolver = _context.getContentResolver();
|
||||
HostAuth ha = HostAuth.restoreHostAuthWithId(_context, mAccount.mHostAuthKeyRecv);
|
||||
mSsl = (ha.mFlags & HostAuth.FLAG_SSL) != 0;
|
||||
mTrustSsl = (ha.mFlags & HostAuth.FLAG_TRUST_ALL_CERTIFICATES) != 0;
|
||||
}
|
||||
|
||||
private EasSyncService(String prefix) {
|
||||
@ -191,7 +194,7 @@ public class EasSyncService extends AbstractSyncService {
|
||||
|
||||
@Override
|
||||
public void validateAccount(String hostAddress, String userName, String password, int port,
|
||||
boolean ssl, Context context) throws MessagingException {
|
||||
boolean ssl, boolean trustCertificates, Context context) throws MessagingException {
|
||||
try {
|
||||
userLog("Testing EAS: ", hostAddress, ", ", userName, ", ssl = ", ssl ? "1" : "0");
|
||||
EasSyncService svc = new EasSyncService("%TestAccount%");
|
||||
@ -200,6 +203,7 @@ public class EasSyncService extends AbstractSyncService {
|
||||
svc.mUserName = userName;
|
||||
svc.mPassword = password;
|
||||
svc.mSsl = ssl;
|
||||
svc.mTrustSsl = trustCertificates;
|
||||
svc.mDeviceId = SyncManager.getDeviceId();
|
||||
HttpResponse resp = svc.sendHttpClientOptions();
|
||||
int code = resp.getStatusLine().getStatusCode();
|
||||
@ -218,7 +222,12 @@ public class EasSyncService extends AbstractSyncService {
|
||||
throw new MessagingException(MessagingException.IOERROR);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
userLog("IOException caught, reporting I/O error: ", e.getMessage());
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null && cause instanceof CertificateException) {
|
||||
userLog("CertificateException caught: ", e.getMessage());
|
||||
throw new MessagingException(MessagingException.GENERAL_SECURITY);
|
||||
}
|
||||
userLog("IOException caught: ", e.getMessage());
|
||||
throw new MessagingException(MessagingException.IOERROR);
|
||||
}
|
||||
|
||||
@ -351,7 +360,7 @@ public class EasSyncService extends AbstractSyncService {
|
||||
mCmdString = "&User=" + safeUserName + "&DeviceId=" + mDeviceId + "&DeviceType="
|
||||
+ mDeviceType;
|
||||
}
|
||||
String us = (mSsl ? "https" : "http") + "://" + mHostAddress +
|
||||
String us = (mSsl ? (mTrustSsl ? "httpts" : "https") : "http") + "://" + mHostAddress +
|
||||
"/Microsoft-Server-ActiveSync";
|
||||
if (cmd != null) {
|
||||
us += "?Cmd=" + cmd + mCmdString;
|
||||
@ -369,11 +378,17 @@ public class EasSyncService extends AbstractSyncService {
|
||||
method.setHeader("User-Agent", mDeviceType + '/' + Eas.VERSION);
|
||||
}
|
||||
|
||||
private ClientConnectionManager getClientConnectionManager() {
|
||||
return SyncManager.getClientConnectionManager();
|
||||
}
|
||||
|
||||
private HttpClient getHttpClient(int timeout) {
|
||||
HttpParams params = new BasicHttpParams();
|
||||
HttpConnectionParams.setConnectionTimeout(params, 15*SECONDS);
|
||||
HttpConnectionParams.setSoTimeout(params, timeout);
|
||||
return new DefaultHttpClient(params);
|
||||
HttpConnectionParams.setSocketBufferSize(params, 8192);
|
||||
HttpClient client = new DefaultHttpClient(getClientConnectionManager(), params);
|
||||
return client;
|
||||
}
|
||||
|
||||
protected HttpResponse sendHttpClientPost(String cmd, byte[] bytes) throws IOException {
|
||||
|
@ -21,7 +21,7 @@ import com.android.exchange.EmailContent;
|
||||
|
||||
interface IEmailService {
|
||||
int validate(in String protocol, in String host, in String userName, in String password,
|
||||
int port, boolean ssl) ;
|
||||
int port, boolean ssl, boolean trustCertificates) ;
|
||||
|
||||
void startSync(long mailboxId);
|
||||
void stopSync(long mailboxId);
|
||||
|
@ -18,6 +18,7 @@
|
||||
package com.android.exchange;
|
||||
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.store.TrustManagerFactory;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.Attachment;
|
||||
@ -29,6 +30,19 @@ import com.android.email.provider.EmailContent.Message;
|
||||
import com.android.email.provider.EmailContent.SyncColumns;
|
||||
import com.android.exchange.utility.FileLogger;
|
||||
|
||||
import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.params.ConnManagerPNames;
|
||||
import org.apache.http.conn.params.ConnPerRoute;
|
||||
import org.apache.http.conn.routing.HttpRoute;
|
||||
import org.apache.http.conn.scheme.PlainSocketFactory;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.OnAccountsUpdatedListener;
|
||||
import android.app.AlarmManager;
|
||||
@ -65,10 +79,16 @@ import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
/**
|
||||
* The SyncManager handles all aspects of starting, maintaining, and stopping the various sync
|
||||
* adapters used by Exchange. However, it is capable of handing any kind of email sync, and it
|
||||
@ -176,6 +196,8 @@ public class SyncManager extends Service implements Runnable {
|
||||
private static Thread sServiceThread = null;
|
||||
// Cached unique device id
|
||||
private static String sDeviceId = null;
|
||||
// ConnectionManager that all EAS threads can use
|
||||
private static ClientConnectionManager sClientConnectionManager = null;
|
||||
|
||||
private boolean mStop = false;
|
||||
|
||||
@ -240,10 +262,10 @@ public class SyncManager extends Service implements Runnable {
|
||||
private final IEmailService.Stub mBinder = new IEmailService.Stub() {
|
||||
|
||||
public int validate(String protocol, String host, String userName, String password,
|
||||
int port, boolean ssl) throws RemoteException {
|
||||
int port, boolean ssl, boolean trustCertificates) throws RemoteException {
|
||||
try {
|
||||
AbstractSyncService.validate(EasSyncService.class, host, userName, password, port,
|
||||
ssl, SyncManager.this);
|
||||
ssl, trustCertificates, SyncManager.this);
|
||||
return MessagingException.NO_ERROR;
|
||||
} catch (MessagingException e) {
|
||||
return e.getExceptionType();
|
||||
@ -672,6 +694,52 @@ public class SyncManager extends Service implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
static public ConnPerRoute sConnPerRoute = new ConnPerRoute() {
|
||||
public int getMaxForRoute(HttpRoute route) {
|
||||
return 8;
|
||||
}
|
||||
};
|
||||
|
||||
static public synchronized ClientConnectionManager getClientConnectionManager() {
|
||||
if (sClientConnectionManager == null) {
|
||||
// Create a registry for our three schemes; http and https will use built-in factories
|
||||
SchemeRegistry registry = new SchemeRegistry();
|
||||
registry.register(new Scheme("http",
|
||||
PlainSocketFactory.getSocketFactory(), 80));
|
||||
registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
|
||||
|
||||
// Create a new SSLSocketFactory for our "trusted ssl"
|
||||
// Get the unsecure trust manager from the factory
|
||||
X509TrustManager trustManager = TrustManagerFactory.get(null, false);
|
||||
TrustManager[] trustManagers = new TrustManager[] {trustManager};
|
||||
SSLContext sslcontext;
|
||||
try {
|
||||
sslcontext = SSLContext.getInstance("TLS");
|
||||
sslcontext.init(null, trustManagers, null);
|
||||
SSLContextImpl sslContext = new SSLContextImpl();
|
||||
try {
|
||||
sslContext.engineInit(null, trustManagers, null, null, null);
|
||||
} catch (KeyManagementException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
// Ok, now make our factory
|
||||
SSLSocketFactory sf = new SSLSocketFactory(sslContext.engineGetSocketFactory());
|
||||
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||
// Register the httpts scheme with our factory
|
||||
registry.register(new Scheme("httpts", sf, 443));
|
||||
// And create a ccm with our registry
|
||||
HttpParams params = new BasicHttpParams();
|
||||
params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 25);
|
||||
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, sConnPerRoute);
|
||||
sClientConnectionManager = new ThreadSafeClientConnManager(params, registry);
|
||||
} catch (NoSuchAlgorithmException e2) {
|
||||
} catch (KeyManagementException e1) {
|
||||
}
|
||||
}
|
||||
// Null is a valid return result if we get an exception
|
||||
return sClientConnectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
log("!!! EAS SyncManager destroyed");
|
||||
|
@ -38,7 +38,6 @@ public class AccountSetupExchangeTests extends
|
||||
|
||||
private AccountSetupExchange mActivity;
|
||||
private EditText mServerView;
|
||||
private EditText mDomainView;
|
||||
private Button mNextButton;
|
||||
|
||||
public AccountSetupExchangeTests() {
|
||||
@ -56,7 +55,7 @@ public class AccountSetupExchangeTests extends
|
||||
// This sets up a default URI which can be used by any of the test methods below.
|
||||
// Individual test methods can replace this with a custom URI if they wish
|
||||
// (except those that run on the UI thread - for them, it's too late to change it.)
|
||||
Intent i = getTestIntent("eas://user:password@server.com/domain");
|
||||
Intent i = getTestIntent("eas://user:password@server.com");
|
||||
setActivityIntent(i);
|
||||
}
|
||||
|
||||
@ -64,17 +63,20 @@ public class AccountSetupExchangeTests extends
|
||||
* Test processing with a complete, good URI -> good fields
|
||||
*/
|
||||
public void testGoodUri() {
|
||||
Intent i = getTestIntent("eas://user:password@server.com/domain");
|
||||
Intent i = getTestIntent("eas://user:password@server.com");
|
||||
setActivityIntent(i);
|
||||
getActivityAndFields();
|
||||
assertTrue(mNextButton.isEnabled());
|
||||
}
|
||||
|
||||
// TODO Add tests for valid usernames in eas
|
||||
// They would be <name> or <name>\<domain> or <name>/<domain> or a valid email address
|
||||
|
||||
/**
|
||||
* No user is not OK - not enabled
|
||||
*/
|
||||
public void testBadUriNoUser() {
|
||||
Intent i = getTestIntent("eas://:password@server.com/domain");
|
||||
Intent i = getTestIntent("eas://:password@server.com");
|
||||
setActivityIntent(i);
|
||||
getActivityAndFields();
|
||||
assertFalse(mNextButton.isEnabled());
|
||||
@ -84,7 +86,7 @@ public class AccountSetupExchangeTests extends
|
||||
* No password is not OK - not enabled
|
||||
*/
|
||||
public void testBadUriNoPassword() {
|
||||
Intent i = getTestIntent("eas://user@server.com/domain");
|
||||
Intent i = getTestIntent("eas://user@server.com");
|
||||
setActivityIntent(i);
|
||||
getActivityAndFields();
|
||||
assertFalse(mNextButton.isEnabled());
|
||||
@ -116,49 +118,6 @@ public class AccountSetupExchangeTests extends
|
||||
mServerView.setText("serv$er.com");
|
||||
assertFalse(mNextButton.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* No EAS domain is OK - enabled
|
||||
*/
|
||||
public void testBadUriNoDomain() {
|
||||
Intent i = getTestIntent("eas://user:password@server.com");
|
||||
setActivityIntent(i);
|
||||
getActivityAndFields();
|
||||
assertTrue(mNextButton.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for non-standard but OK domain names
|
||||
*/
|
||||
@UiThreadTest
|
||||
public void testGoodDomainVariants() {
|
||||
getActivityAndFields();
|
||||
assertTrue(mNextButton.isEnabled());
|
||||
|
||||
mDomainView.setText(" domain ");
|
||||
assertTrue(mNextButton.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for non-empty but non-OK domain names
|
||||
*
|
||||
* TODO: These are tests that *should* fail but the code is not checking these cases
|
||||
*/
|
||||
@UiThreadTest
|
||||
public void disabled_testBadDomainVariants() {
|
||||
getActivityAndFields();
|
||||
assertTrue(mNextButton.isEnabled());
|
||||
|
||||
mDomainView.setText(" ");
|
||||
assertTrue(mNextButton.isEnabled());
|
||||
|
||||
mDomainView.setText("do main");
|
||||
assertFalse(mNextButton.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: More tests of exchange-specific fields?
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the activity (which causes it to be started, using our intent) and get the UI fields
|
||||
@ -166,7 +125,6 @@ public class AccountSetupExchangeTests extends
|
||||
private void getActivityAndFields() {
|
||||
mActivity = getActivity();
|
||||
mServerView = (EditText) mActivity.findViewById(R.id.account_server);
|
||||
mDomainView = (EditText) mActivity.findViewById(R.id.account_domain);
|
||||
mNextButton = (Button) mActivity.findViewById(R.id.next);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user