Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts
Dealing with Java Hell using JarJar life boat
Okay, so I wanted to use Hex.encodeHexString method from org.apache.commons.codec.binary.Hex (commons-codec-1.6.jar)library to generate encoded singnature. I was able to do this in plain Java, but not in Android. I googled for a while and found out this ticket about Android not supporting the latest versions of commons-codec-1.6.jar.The solutions was to use magical "jarjar" ! But How ??? Again, I googled and come across this and this, and I came up with solution to solve mystery of using Hex.encodeHexString method in code running on Android (Dalvik VM). Android uses old version of commons-codec jar which doesn't define org.apache.commons.codec.binary.Hex.encodeHexString method signature. Even if you add new commons-codec-1.6.jar to build path of project, code will try to refer to built-in commons-codec not the new one that you added in build path. But, if you change the package name/namespaces for commons-codec-1.6.jar, then you can easily reference from your code and finally can use Hex.encodeHexString. So, you have to create a custom jar with modified package name structure.
Here is how you can spin a new custom jar, say : commons-codec-1.6-jarjar.jar:
Step-1: Create a build.xml like follows:
Step-2: Run command "ant" from command line. This build script will generate a new jar commons-codec-1.6-jarjar.jar, which you can add in your build path and use this new jar to import from.<project name="generate-jarjar"><property name="jarjarfile" value="commons-codec-1.6-jarjar.jar"/><path id="classpath"><pathelement location="jarjar-1.4.jar"/><pathelement location="asm-2.2.3.jar"/></path><taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="classpath"/><delete file="${jarjarfile}"/><jarjar destfile="${jarjarfile}"><zipfileset src="commons-codec-1.6.jar"/><rule pattern="org.apache.**" result="org.jarjar.apache.@1"/></jarjar></project>
You can download all the files mentioned in above script and build.xml from here.
How did I setup SSL with HTTPClient-4.1.2
I've been struggling to get this working for about 2 days now. I was able to POST a request directly from sockets, but it took me a while to see it working with HTTPClient-4.1.2. There are different variants out there in google for legacy HTTPClient and less than 4.1.x.
The key was to specify TrustManager and KeyManager while initializing SSLContext.
Step-1: First, you have to initialize SSLContext like this:
SSLContext ctx = SSLContext.getInstance("TLS");
Step-2: Getting TrustManager. Java look into its trust managers to check against authorized Certification Authorities(CA). Default trust store in Java is "jks". This is how you can get trust manager:
TrustManager[] getTrustManagers(String trustStoreType, InputStream trustStoreFile, String trustStorePassword) throws Exception {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
trustStore.load(trustStoreFile, trustStorePassword.toCharArray());
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(trustStore);
return tmfactory.getTrustManagers();
}
It should be called as:
TrustManager[] trustManagers = getTrustManagers("jks", new FileInputStream(new File("/Library/Java/Home/lib/security/cacerts")), "changeit");
/Library/Java/Home/lib/security/cacerts is the default path to trust managers in Mac OSX
Step-3: Getting KeyManager: This is where your client certificates are stored. KeyManager in the code can be retrieved as :
KeyManager[] keyManagers = getKeyManagers("pkcs12", new FileInputStream(new File("clientCertificate.p12")), "password");
You have to get KeyManagers using KeyManagerFactory like this:
KeyManager[] getKeyManagers(String keyStoreType, InputStream keyStoreFile, String keyStorePassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory init(keyStore, keyStorePassword.toCharArray());
return kmfactory.getKeyManagers();
}
Step-4: Once you have TrustManager and KeyManager ready, pass them in SSLContext:
ctx.init(keyManagers, trustManagers, new SecureRandom());
Step-5: Now create a SSLSocketFactory object using SSLContext object:
SSLSocketFactory sf = new SSLSocketFactory(ctx, new StrictHostnameVerifier());
Step-6: Assign Scheme to the HttpClient:
DefaultHttpClient httpclient = new DefaultHttpClient();
ClientConnectionManager manager = httpclient.getConnectionManager();
manager.getSchemeRegistry().register(new Scheme("https", 443, sf));
Done !
Now use this httpclient in HttpPost, HttpGet ….
The key was to specify TrustManager and KeyManager while initializing SSLContext.
Step-1: First, you have to initialize SSLContext like this:
SSLContext ctx = SSLContext.getInstance("TLS");
Step-2: Getting TrustManager. Java look into its trust managers to check against authorized Certification Authorities(CA). Default trust store in Java is "jks". This is how you can get trust manager:
TrustManager[] getTrustManagers(String trustStoreType, InputStream trustStoreFile, String trustStorePassword) throws Exception {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
trustStore.load(trustStoreFile, trustStorePassword.toCharArray());
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(trustStore);
return tmfactory.getTrustManagers();
}
It should be called as:
TrustManager[] trustManagers = getTrustManagers("jks", new FileInputStream(new File("/Library/Java/Home/lib/security/cacerts")), "changeit");
/Library/Java/Home/lib/security/cacerts is the default path to trust managers in Mac OSX
Step-3: Getting KeyManager: This is where your client certificates are stored. KeyManager in the code can be retrieved as :
KeyManager[] keyManagers = getKeyManagers("pkcs12", new FileInputStream(new File("clientCertificate.p12")), "password");
You have to get KeyManagers using KeyManagerFactory like this:
KeyManager[] getKeyManagers(String keyStoreType, InputStream keyStoreFile, String keyStorePassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory init(keyStore, keyStorePassword.toCharArray());
return kmfactory.getKeyManagers();
}
Step-4: Once you have TrustManager and KeyManager ready, pass them in SSLContext:
ctx.init(keyManagers, trustManagers, new SecureRandom());
Step-5: Now create a SSLSocketFactory object using SSLContext object:
SSLSocketFactory sf = new SSLSocketFactory(ctx, new StrictHostnameVerifier());
Step-6: Assign Scheme to the HttpClient:
DefaultHttpClient httpclient = new DefaultHttpClient();
ClientConnectionManager manager = httpclient.getConnectionManager();
manager.getSchemeRegistry().register(new Scheme("https", 443, sf));
Done !
Now use this httpclient in HttpPost, HttpGet ….
Subscribe to:
Posts (Atom)
Scheduling Repeating Local Notifications using Alarm Manager
Learn about Scheduling Repeating Local Notifications using Alarm Manager in this post .
-
Couple of days ago, I started using Google's code projects for Git as well. It required me to setup and use .netrc file. Here are steps...
-
I've been struggling to get this working for about 2 days now. I was able to POST a request directly from sockets, but it took me a whi...
-
Normal structure of build.gradle for an Android library looks like this: apply plugin : 'com.android.library' android { comp...