Wednesday, October 14, 2009

Web service client (J2EE App) accessing Web Service over Https or SSL

I've recently encountered a situation where a J2EE application needs to access web service that is available on https (SSL). I've realized that accessing the web service over https and http are not alike, specifically when certificate comes in between.

In a usual scenario when a user access the secured site (https://******) in browser the server supplies the certificate to browser and when user agrees to the certificate as reliable/trusted communication, the certificate gets stored in browser. By agreeing the above step the browser assumes the subsequent communication is trusted with server, and does not request user to agree to certificate for every communication.

By analyzing the above handshake, having a java program to authorize/authenticate the communication each time when service is contacted is painful. Since J2ee application (WS client) is running in J2EE server, a smart decision is to let the trusted relationship is established between J2EE Server and Web Service. This allows any application that runs in J2EE Server can access Web Service over Https.

To achieve above I've done following things.

1. Accessed the service on https from browser and opened the certificate (see lock icon in below image.
I did not mind about the validity of response, my intention was to obtain the certificate.


2. Copied (Copy to File) the certificate into a file (xyz.cer) into a directory
Please see the below images. I've used IE6.x browser. The importing/copying of .cer file may be different in different browsers.











3. Uploading/Exporting the .cer file to the J2EE Server Security.

In my case I'm deploying the J2EE application (WS client) is deployed into Websphere Server 6.0.2 (WAS), I need to know what JKS file the WAS is using for SSL communication.

a. Finding JKS file that server is using.
Login to WAS with administration account.
OR
Start the 'Admin console' from context menu of WAS server instance from IDE (Eclipse/IRAD/WSAD).



Navigate to SSL > SSL configuration repertoires > /DefaultSSLSettings
and note down the value (${USER_INSTALL_ROOT}/etc/DummyServerTrustFile.jks) of 'Trust file name'. In your case 'Trust file name' value may be different.

Note: The image is conveying wrong and needs to be corrected.


Now export the cert file into ${USER_INSTALL_ROOT}/etc/DummyServerTrustFile.jks using KeyMan tool.
Navigate to the location keyman tool (C:\Program Files\IBM\Rational\SDP\6.0\runtimes\base_v6\bin\ikeyman.bat) and double click on it to see the application running. See the below image for reference. If ikeyman.bat does not run then run ikeyman_old.bat.



Click on 'Key Database File' > 'New' from Menu to locate the JKS file is configured to use the server. See below images for reference.








The DummyServerTrustFile.jks is located in the profile (C:\Program Files\IBM\Rational\SDP\6.0\runtimes\base_v6\profiles\default\etc\) that I'm using.

Save/Overwrite the file with changes. Enter the default password WebAS


Add xyz.cer to this (DummerServerTrustFile.jks) truststore.



Give a Label name to recoginze the certificate (xyz.cer) in Truststore (DummyServerTrustFile.jks)



Save the Label and see it in 'Key Database Content' pane. Exit from Keyman tool.



4. Restart the Websphere Application Server for changes to Trusted Store is effective.

5. If you have recieved wsdl file either through UDDI or Registery Explorer, generate client stubs and JAR them.
NOTE: IRAD6.0.2 has provided me different (Apache Axis 1.0, IBM SOAP and IBM WebSphere) Web service runtimes and each of them has one or the other problems .
a. Apache Axis 1.0 - java.lang.NoClassDefFoundError: sun/security/provider/Sun
b. IBM WebSphere - Communication was established with WS* only the initial or first time and could not reestablish for subsequent requests. In some occasions WAS was restarted. The error (Server Response Read is Failed) was observed for every request.


I've preferred Apache Axis 1.1 or later runtime.
 

The internet search on runtime problems provided me the following suggestion
There might be a reference in axis1.0 classes to the sun security class - which ignores any dynamically set classes in non SUN JDK environments.

 
6. Use Stubs in your J2EE application. See the example below
ExternalServiceLocator locator = new ExternalServiceLocator();
ExternalService extService= locator.getExternalService();
OR
ExternalService extService= locator.getExternalService(new URL ("https://example.external.service.com"));

String result = extService.getOperation1();

7. I've not run into any problems while running WS Client.
I've not used any of following security System properties settings in code or in server. If you run into problems try setting the following properties at WAS-JVM level ( Application servers > server1 > Process Definition > Java Virtual Machine > Custom Properties )








OR
at WS-Client code before accessing WS in Step 6


String fileName = "your jks file with absolute path";
String passwd = "your jks file password"; //Default is 'WebAS' for IBM WebSphere
System.setProperty("javax.net.ssl.trustStore", fileName);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
System.setProperty("javax.net.ssl.keyStore", fileName);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);

If proxy server authentication is required for WS Client, then additionally configure the HTTP or HTTPS proxyUser and proxyPassword transport properties using one of the methods specified.
To access the Web Proxy over HTTP
System.setProperty("http.proxyHost", "YOUR_PROXY_SERVER_NAME");
System.setProperty("http.proxyPort", "YOUR_PROXY_SERVER_PORT");
System.setProperty("http.proxyUser","PROXY_USER_NAME");
System.setProperty("http.proxyPassword","PROXY_USER_PWD");

To access the Web Proxy over HTTPS
System.setProperty("https.proxyHost", "YOUR_PROXY_SERVER_NAME");
System.setProperty("https.proxyPort", "YOUR_PROXY_SERVER_PORT");
System.setProperty("https.proxyUser","PROXY_USER_NAME");
System.setProperty("https.proxyPassword","PROXY_USER_PWD");


NOTE: If you are accessing the https service from corporate environment make sure your Application Server can establish the connection with Web Service. In my experience my Webpsphere server was restricted from accessing the external Web Service so I had disconnected the server from corporate network and connected to internet over Wireless, was able to access the Web Service.

You may run into some proxy related issues, please correct them before you conclude that your client is able to access WS*.