Wednesday, April 4, 2012

Connecting to a https URL which has a self signed certificate

In scenarios where a REST resource (or any URL) is only accessible via https and has a self signed certificate, you wont be able to connect using a regular http connection.  You will see the following exception.

javax.net.ssl.SSLHandshakeException: ...

So to get around this, grab the certificate using your browser. You can connect to the URL and based on the browser you should be able to download the certificate locally.  
Use the keytool command to convert the .crt file to a .jks file using the following command.
 $ keytool -import -file ngle_test.crt -alias server -keystore ngle_test-1.jks  
 Enter keystore password:  
 Re-enter new password:  
 Trust this certificate? [no]: yes  
 Certificate was added to keystore  
Once you have the certificate in the .jks format, you can 2 choices.  You can upload the certificate to the default cacerts file that is packaged with the jre or in cases where this is not feasible, load the certificate in the java code.
I'm using apache http client.  The resource is also using basic-auth.
 final DefaultHttpClient httpclient = new DefaultHttpClient();  
 try  
 {  
  final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  
  trustStore.load(RestfulClient.class.getResourceAsStream("/ngle_test1.jks"),<certificate_password>.toCharArray());  
  final SSLSocketFactory socketFactory = new SSLSocketFactory("TLS", null, null, trustStore, null, null,  
   SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //Doesn't check if the hostname on the certificate matches the host in the https URL  
  final Scheme sch = new Scheme("https", 8080, socketFactory);  
  httpclient.getConnectionManager().getSchemeRegistry().register(sch);  
  // Basic Auth Start  
  final HttpHost targetHost = new HttpHost(<HTTPSurlHost>, <HTTPSurlPort>, "https");  
  httpclient.getCredentialsProvider().setCredentials(  
   new AuthScope(<HTTPSurlHost>, <HTTPSurlPort>)),  
   new UsernamePasswordCredentials(<basicAuthUsername>, <basicAuthPassword>));  
  // Create AuthCache instance  
  final AuthCache authCache = new BasicAuthCache();  
  // Generate BASIC scheme object and add it to the localauth cache  
  final BasicScheme basicAuth = new BasicScheme();  
  authCache.put(targetHost, basicAuth);  
  // Add AuthCache to the execution context  
  final BasicHttpContext localcontext = new BasicHttpContext();  
  localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);  
  // Basic Auth End  
  final HttpGet httpget = new HttpGet(ngleURL);  
  final HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);  
  final HttpEntity entity = response.getEntity();  
  final String result = EntityUtils.toString(entity);  
  EntityUtils.consume(entity);  
 }  
 catch (Exception e)  
 {  
  LOG.error(e.getMessage());  
 }  
 finally  
 {  
  // When HttpClient instance is no longer needed,  
  // shut down the connection manager to ensure  
  // immediate deallocation of all system resources  
  httpclient.getConnectionManager().shutdown();  
 }