Showing posts with label sslmanagement. Show all posts
Showing posts with label sslmanagement. Show all posts

Making HTTPS call from inside the WebSphere Application Server

In the Getting markup from HTTPS connection in Java program entry i talked about how to make a HTTPS call from standalone Java program, but what if you want to make a HTTPS call from a Servlet, or some code that is running inside J2EE container such as WebSphere Application server, In that case you will have to import the SSL certificate inside WAS.

I wanted to figure out the steps to make HTTPS call from inside WAS so i did create a DemoSSL servlet that takes URL that you want to access as input and makes request to that URL, once the request is successful it will write the response back to the output. Then i configured WAS so that i can make call to https://mail.atech.com, my employers email server but you can use some other https url if you want.

First i did create a DemoSSLServlet that looks like this



package com.webspherenotes.ssl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Servlet implementation class DemoSSLServlet
*/
public class DemoSSLServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Entering DemoSSLServlet.doPost()");
String submitUrl = request.getParameter("url");
System.out.println("Value of URL " + submitUrl);
URL url = new URL(submitUrl);

// Open the URL: throws exception if not found
HttpURLConnection conn =
(HttpURLConnection)url.openConnection();
conn.connect();
InputStream inputStream = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while((line = reader.readLine()) != null){
response.getWriter().println(line);
}
System.out.println("Exiting DemoSSLServlet.doPost()");
}

}


In the DemoSSLServlet servlet, i did override the doPost() method and in this method i am making call to the supplied URL and printing response to the output. also had to create index.jsp to take URL as input from user


<%@ page language="java" contentType="text/html; %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="DemoSSLServlet" method="post">
<table>
<tr>
<td>URL</td>
<td><input type="text" name="url" /></td>
<td><input type="Submit" name="submit" /></td>
</tr>
</table>
</form>
</body>
</html>


Then i did install the DemoSSL.war file on my WAS server, i tried testing it with http://www.google.com and made sure that it works and it is able to return markup, But when i tried accessing the https://mail.atech.com URL i got following error



So next step was to configure the WAS trust store so that it would trust SSL certificate from https://mail.atech.com. Login into the WAS Admin console and go to Security -< SSL Certificate and Key Management page like this



Click on Key Stores and Certificates



Click on CellDefaultTrustStore




Click on Signer Certificates



Click on Retrieve from Port button to get a screen like this,



On this page enter the information related to the Host from which you want to import the SSL certificate



Click on Retrieve signer certificate button, at this point WAS will import the SSL certificate from host and display it like this





Now save the changes and when you try to hit the URL again it should work without throwing exception

Getting markup from HTTPS connection in Java program

One of the common requirements in J2EE is making a request to HTTP URL and getting response back. The JDK has support to make HTTP call and get response, you dont have to use any external library if you dont want to but (But most of us use Apache HTTP Client).

This sample code demonstrates how you can make a HTTP call to http://wpconnections1.atech.com/ and get and print response back to the console


package com.webspherenotes.ssl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class HelloSSL {
public static void main(String[] args) {
try {
URL url = new URL("http://wpconnections1.atech.com/");

// Open the URL: throws exception if not found
HttpURLConnection conn =
(HttpURLConnection)url.openConnection();
conn.connect();
InputStream inputStream = conn.getInputStream();
BufferedReader reader =
new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while((line = reader.readLine()) != null){
System.out.println(line);
}
} catch (MalformedURLException e) {
e.printStackTrace(System.out);
} catch (IOException e) {
e.printStackTrace(System.out);
}
}
}



This program works but you might want to access the same URL on HTTPs instead of HTTP, This program will work if you try to access say https://encrypted.google.com. But, In development environment we use self-signed SSL certificate and your JVM would not trust the self-signed SSL certificate. So when you try to connect to http://wpconnections1.atech.com/ it will throw this exception


javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)
at com.webspherenotes.ssl.HelloSSL.main(HelloSSL.java:23)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 18 more


You will have to follow some additional steps to import the self signed SSL certificate in your JVM so that it trust it. There are multiple ways to do that but the one that i like is outlined here http://blogs.sun.com/andreas/entry/no_more_unable_to_find, first i had to download the InstallCert.java on my machine and package it into a .jar file then i executed


java -jar InstallCert.jar wpconnections1.atech.com


This will create a jssecacert file on your machine where you executed the InstallCert.jar. In my case i did execute the .jar in c:\temp so i did create a C:\Temp\jssecacert file in that directory. This file has the imported certificate for wpconnections1.atech.com

Then i went back to my program and i did execute it by adding following JVM argument -Djavax.net.ssl.trustStore="c:\temp\jssecacerts" like this


Now when i run the HelloSSL program i can see response being returned

Procedure to enable SSL between web server and WebSphere Application Server

I wanted to try enabling SSL between my WebServer and WebSphere Application Server so i followed this process to do that

Exchanging public certificate

This section provides details and step-by-step instructions for exchanging public certificates between two key stores or trust (certificate) stores. You must perform the certificate exchange when you want to set up trust between two parties based on certificates. Usually you use this process with self-signed certificates because real certificates issued by well-known Certificate Authorities are already included in the key and trust stores.


  • Start ikeyman and open the file that you just C:\Cert\HTTPServer\conf\keys\WAS6PluginCertificates.kdb, whose public certificate you want to export

  • Now select the personal certificate that you created, in my case it is WASPluginCertificate and click on Extract Certificate button



  • ikeyman tool will display a dialog where you can set location where the public certificat should be exported. Export it to c:\temp\publiccertificate\WAS6PluginCertificates.arm



  • Now open the C:\Cert\WebSphere\AppServer\profiles\Dmgr01\config\cells\dmgrCell01\WAS6WebContainerCertificates.jks file in iKeyman tool

  • Switch to the Signer certificate view by selecting signer certificate in the key database content section



  • Now click on add, and it will show you the Add CA's certificate from file dialog, select the c:\temp\publiccertificate\WAS6PluginCertificates.arm file that you exported and click OK


  • It will ask you to enter a lable for the public certificate enter WAS6PluginCertificatesCertificate.

  • Now you should be able to see the certificate that you just imported in the list


Creating self signed certificate




IBM provides a ikeyman tool that you can use to create self signed certificate and manage keys by following these steps


  1. Go to the WAS_HOME/bin directory and execute ikeyman tool, it will open a GUI based tool like this



  2. Now click on Key Database File - New. It will open a dialog box, in that change Key Database type to CMS and enter file and path name. In my case i am creating WAS6PluginCertificates.kdb file in C:\Cert\HTTPServer\conf\keys\ directory and click OK



  3. It will ask you for the password for the Key database file, enter a password, then check Stash the password to a file checkbox.



  4. It will create a .kdb file and import bunch of keys for you by default and show a message like this


  5. Once the .kdb file is created next step is to create a Self Signed certificate so click on Create - New Self Signed Certificate like this



  6. Enter the details for self signed certificate such as, key label, Organizations,...



  7. Thats it your self signed certificate is created, you can check them by going to the directory where we saved it. You will see 4 different files for that certificate are created out of that .sth is the stash password file