Previous post from crazybob doesn't work for me. The problem is I want to authenticate Exchange Web Service from Android. And the long story has begun.
You will need the following tools:
- bcprov-jdk16-145.jar
- Java SE (for keytool)
- Also, you need certificate file (.cer)
Use the following command to create keystore:
keytool -importcert -v -trustcacerts -file "YourCerFile.cer" -al ias parkgroup_restful -keystore "Output.bks" -provider org.bounc ycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar " -storetype BKS -storepass "YourPass"It should show some result, then ask (choose yes):
Trust this certificate? [no]: yesThen verify if the certificates were imported correctly into the keystore:
keytool -list -keystore "Output.bks" -provi der org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass "YourPass"If success, result will be show like this:
Keystore type: BKS Keystore provider: BC Your keystore contains 1 entry parkgroup_restful, Apr 10, 2012, trustedCertEntry, Certificate fingerprint (MD5): 36:47:88:62:23:1C:F3:52:17:BE:7A:A9:94:56:19:18
Use keystore in your app.
Create custom trust manager
import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import android.util.Log; /** * Manage trust certificate * * @author ductran * */ public class CustomTrustManager implements X509TrustManager { private static final String TAG = CustomTrustManager.class.getSimpleName(); static class LocalStoreX509TrustManager implements X509TrustManager { private X509TrustManager trustManager; LocalStoreX509TrustManager(KeyStore localTrustStore) { try { TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(localTrustStore); trustManager = findX509TrustManager(tmf); if (trustManager == null) { throw new IllegalStateException("Couldn't find X509TrustManager"); } } catch (GeneralSecurityException e) { throw new RuntimeException(e); } } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { trustManager.checkClientTrusted(chain, authType); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { trustManager.checkServerTrusted(chain, authType); } @Override public X509Certificate[] getAcceptedIssuers() { return trustManager.getAcceptedIssuers(); } } static X509TrustManager findX509TrustManager(TrustManagerFactory tmf) { TrustManager tms[] = tmf.getTrustManagers(); for (int i = 0; i < tms.length; i++) { if (tms[i] instanceof X509TrustManager) { return (X509TrustManager) tms[i]; } } return null; } private X509TrustManager defaultTrustManager; private X509TrustManager localTrustManager; private X509Certificate[] acceptedIssuers; public CustomTrustManager(KeyStore localKeyStore) { try { TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init((KeyStore) null); defaultTrustManager = findX509TrustManager(tmf); if (defaultTrustManager == null) { throw new IllegalStateException("Couldn't find X509TrustManager"); } localTrustManager = new LocalStoreX509TrustManager(localKeyStore); List<x509certificate> allIssuers = new ArrayList<x509certificate>(); for (X509Certificate cert : defaultTrustManager.getAcceptedIssuers()) { allIssuers.add(cert); } for (X509Certificate cert : localTrustManager.getAcceptedIssuers()) { allIssuers.add(cert); } acceptedIssuers = allIssuers.toArray(new X509Certificate[allIssuers .size()]); } catch (GeneralSecurityException e) { throw new RuntimeException(e); } } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { Log.d(TAG, "checkServerTrusted() with default trust manager..."); defaultTrustManager.checkClientTrusted(chain, authType); } catch (CertificateException ce) { Log.d(TAG, "checkServerTrusted() with local trust manager..."); localTrustManager.checkClientTrusted(chain, authType); } } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { Log.d(TAG, "checkServerTrusted() with default trust manager..."); defaultTrustManager.checkServerTrusted(chain, authType); } catch (CertificateException ce) { Log.d(TAG, "checkServerTrusted() with local trust manager..."); localTrustManager.checkServerTrusted(chain, authType); } } public X509Certificate[] getAcceptedIssuers() { return acceptedIssuers; } }
Create MySSLSocketFactory
import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.scheme.LayeredSocketFactory; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; /** * loosely based on org.apache.http.conn.ssl.SSLSocketFactory * @author ductran * */ public class MySSLSocketFactory implements LayeredSocketFactory { // private SSLContext sslCtx; private SSLSocketFactory socketFactory; private X509HostnameVerifier hostnameVerifier; public MySSLSocketFactory(SSLContext sslCtx, X509HostnameVerifier hostnameVerifier) { //this.setSslCtx(sslCtx); this.socketFactory = sslCtx.getSocketFactory(); this.hostnameVerifier = hostnameVerifier; } @Override public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort, HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { if (host == null) { throw new IllegalArgumentException("Target host may not be null."); } if (params == null) { throw new IllegalArgumentException("Parameters may not be null."); } SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); if ((localAddress != null) || (localPort > 0)) { if (localPort < 0) localPort = 0; InetSocketAddress isa = new InetSocketAddress(localAddress, localPort); sslsock.bind(isa); } int connTimeout = HttpConnectionParams.getConnectionTimeout(params); int soTimeout = HttpConnectionParams.getSoTimeout(params); InetSocketAddress remoteAddress = new InetSocketAddress(host, port); sslsock.connect(remoteAddress, connTimeout); sslsock.setSoTimeout(soTimeout); try { hostnameVerifier.verify(host, sslsock); } catch (IOException iox) { try { sslsock.close(); } catch (Exception x) { } throw iox; } return sslsock; } @Override public Socket createSocket() throws IOException { return socketFactory.createSocket(); } @Override public boolean isSecure(Socket sock) throws IllegalArgumentException { if (sock == null) { throw new IllegalArgumentException("Socket may not be null."); } if (!(sock instanceof SSLSocket)) { throw new IllegalArgumentException( "Socket not created by this factory."); } if (sock.isClosed()) { throw new IllegalArgumentException("Socket is closed."); } return true; } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { SSLSocket sslSocket = (SSLSocket) socketFactory.createSocket(socket, host, port, autoClose); hostnameVerifier.verify(host, sslSocket); return sslSocket; } }And make request with HttpsClient:
public class HttpsClient { private static final String KEYSTORE_PASSWORD = "1234567"; private static final int MAX_CONN_PER_ROUTE = 30; private static final int MAX_CONNECTIONS = 30; private static final int TIMEOUT = 10 * 1000; private static DefaultHttpClient theClient = null; private HttpResponse response = null; private static DefaultHttpClient getHttpClient() throws GeneralSecurityException{ if (theClient == null) { SSLContext sslContext = createSslContext(); MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext, new BrowserCompatHostnameVerifier()); theClient = createDefaultHttpClient(socketFactory); } return theClient; } public HttpResponse getResponse(){ return response; } /** * Excute the request */ public void excuteRequest(String url, String username, String password, String requestBody){ DefaultHttpClient client = getHttpClient(); HttpPost httpPost = new HttpPost(url); httpPost.setHeader("Content-type", "text/xml; charset=utf-8"); httpPost.setHeader("Keep-Alive", "300"); httpPost.setHeader("Connection", "Keep-Alive"); StringEntity se = new StringEntity(requestBody, "UTF-8"); httpPost.setEntity(se); se.setContentType("text/xml"); se.setContentEncoding("gzip,deflate"); // Authentication client.addRequestInterceptor(preemptiveAuth, 0); // Set the proxy ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner( client.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault()); client.setRoutePlanner(routePlanner); List<string> authPrefs = new ArrayList<string>(); authPrefs.add(AuthPolicy.DIGEST); authPrefs.add(AuthPolicy.BASIC); authPrefs.add(AuthPolicy.NTLM); client.getParams().setParameter(HTTP_AUTH_SCHEME_PRIORITY, authPrefs); // Basic authentication httpPost.addHeader( "Authorization", "Basic " + Base64.encodeToString( (username() + ":" + password()) .getBytes(), Base64.NO_WRAP)); BasicHttpContext localContext = new BasicHttpContext(); BasicScheme basicAuth = new BasicScheme(); localContext.setAttribute("preemptive-auth", basicAuth); response = client.execute(httpPost, localContext); } /** * Authentication with preemptive */ HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context .getAttribute(ClientContext.TARGET_AUTH_STATE); CredentialsProvider credsProvider = (CredentialsProvider) context .getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context .getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authState.getAuthScheme() == null) { AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); if (creds != null) { authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } } } }; private static DefaultHttpClient createDefaultHttpClient( SocketFactory socketFactory) { HttpParams params = new BasicHttpParams(); HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); // HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // Set the parameters for timeout, max connection HttpConnectionParams.setConnectionTimeout(params, TIMEOUT); ConnPerRoute connPerRoute = new ConnPerRouteBean(MAX_CONN_PER_ROUTE); ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute); ConnManagerParams.setMaxTotalConnections(params, MAX_CONNECTIONS); // Register the scheme for Http and Https SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); SocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory(); if (socketFactory != null) { sslSocketFactory = socketFactory; } schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); return new DefaultHttpClient(cm, params); } /** * Create SSL Context from X509TrustManager * * @param clientAuth * @return * @throws GeneralSecurityException */ private static SSLContext createSslContext() throws GeneralSecurityException { KeyStore trustStore = loadTrustStore(); KeyStore keyStore = loadKeyStore(); // CustomTrustManager myTrustManager = new CustomTrustManager(trustStore); EwsX509TrustManager myTrustManager = new EwsX509TrustManager(trustStore, null); TrustManager[] tms = new TrustManager[] { myTrustManager }; KeyManager[] kms = null; KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory .getDefaultAlgorithm()); kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray()); kms = kmf.getKeyManagers(); SSLContext context = SSLContext.getInstance("TLS"); context.init(kms, tms, null); return context; } }