SSL-Based HTTPS SOAP and RESTful Web Service Client Application in Java
In this post, we'll discuss how to create a Java, SSL-based client which facilitates both RESTFul and SOAP web service calls to different servers.
Join the DZone community and get the full member experience.
Join For FreeThis is a Java, SSL-based client which facilitates both RESTFul and SOAP web service calls to different servers. To better understand the topic at hand, you should also have knowledge of the below-mentioned topics:
- What is an SSL certificate?
- What is an SSL handshake?
- What is a Java Key Store (JKS)?
- What is a Java Trust Store (JTS)?
- What is a PKCS certificate/key store?
- What is HTTPS network protocol?
This is going to be a complete SSL-based client application for both RESTFul and SOAP calls. The beauty of this project is that it supports both JKS and PKCS certificates through different configuration facilities provided with this project. You can download the project and just need to refractor this framework/codebase and replace the existing Java classes with your classes to make this framework fulfill your business needs. You can download the project from here.
We are going to develop this small project in Eclipse. Let’s go over, step-by-step, how to create the client application.
1. Create a simple Java project, like below:
Give the project the name SSLClient, like below:
Click 'Finish' to create the project.
Now, right-click on source folder, src, and add a new package, com.bhaiti.kela.common.config, and add a new class, ApplicationConfig, to it.
First, add a new package: New->package
Now to add the class to it, click on the package and from the menu and select New->class.
Copy and paste the below code into this class. This is our config class where we will store all the config information for this application.
package com.bhaiti.kela.common.config;
public final class ApplicationConfig {
private String KEYSTOREPATH = null;
private String TRUSTSTOREPATH = null;
private String KEYSTOREPW = null;
private String TRUSTSTOREPW = null;
private String KEYPASS = null;
private String HTTPS_SERV_URL = null;
private String trustAllCertificate = "false";// DEFAULT VALUE
private String keystoreType = "JKS";// DEFAULT VALUE
private String regex = null;
private String keymanageralgorithm = null;
private int mqreadinterval = 1;
private int httpsfialureinterval = 5;
private int prodissueinterval = 1;
private static ApplicationConfig myinstance = null;
public static ApplicationConfig getInstance() {
System.out.println("in ApplicationConfig getInstance");
if (myinstance == null) {
myinstance = new ApplicationConfig();
}
return myinstance;
}
private ApplicationConfig() {
}
public String getKEYSTOREPATH() {
return KEYSTOREPATH;
}
public void setKEYSTOREPATH(String kEYSTOREPATH) {
KEYSTOREPATH = kEYSTOREPATH;
}
public String getTRUSTSTOREPATH() {
return TRUSTSTOREPATH;
}
public void setTRUSTSTOREPATH(String tRUSTSTOREPATH) {
TRUSTSTOREPATH = tRUSTSTOREPATH;
}
public String getKEYSTOREPW() {
return KEYSTOREPW;
}
public void setKEYSTOREPW(String kEYSTOREPW) {
KEYSTOREPW = kEYSTOREPW;
}
public String getTRUSTSTOREPW() {
return TRUSTSTOREPW;
}
public void setTRUSTSTOREPW(String tRUSTSTOREPW) {
TRUSTSTOREPW = tRUSTSTOREPW;
}
public String getKEYPASS() {
return KEYPASS;
}
public void setKEYPASS(String kEYPASS) {
KEYPASS = kEYPASS;
}
public String getHTTPS_SERV_URL() {
return HTTPS_SERV_URL;
}
public void setHTTPS_SERV_URL(String hTTPS_SERV_URL) {
HTTPS_SERV_URL = hTTPS_SERV_URL;
}
public String getTrustAllCertificate() {
return trustAllCertificate;
}
public void setTrustAllCertificate(String trustAllCertificate) {
this.trustAllCertificate = trustAllCertificate;
}
public String getKeystoreType() {
return keystoreType;
}
public void setKeystoreType(String keystoreType) {
this.keystoreType = keystoreType;
}
public String getKeymanageralgorithm() {
return keymanageralgorithm;
}
public void setKeymanageralgorithm(String keymanageralgorithm) {
this.keymanageralgorithm = keymanageralgorithm;
}
public int getMqreadinterval() {
return mqreadinterval;
}
public void setMqreadinterval(int mqreadinterval) {
this.mqreadinterval = mqreadinterval;
}
public int getHttpsfialureinterval() {
return httpsfialureinterval;
}
public void setHttpsfialureinterval(int httpsfialureinterval) {
this.httpsfialureinterval = httpsfialureinterval;
}
public int getProdissueinterval() {
return prodissueinterval;
}
public void setProdissueinterval(int prodissueinterval) {
this.prodissueinterval = prodissueinterval;
}
public void setREGEX(String regex) {
this.regex = regex;
}
public String getREGEX() {
return this.regex;
}
public static ApplicationConfig getMyinstance() {
return myinstance;
}
public static void setMyinstance(ApplicationConfig myinstance) {
ApplicationConfig.myinstance = myinstance;
}
}
Now we are going to add a new class call SSLContextConfig this class will initialize the truststore, keystore and certificate detail to connect to the remove server through a SSL based HTTPS connection. Here based on trust store, key store and certificate detail the below class will create an object of type SSLContext and returns it to caller for establish an SSL based HTTPS connection. Beauty of this class is that I have design it in such a way that your can use both jks and pkcs certificate and that also can be configurable through system.properties file.
Add package com.bhaiti.kela.ssl.config and add below class
package com.bhaiti.kela.ssl.config;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import org.apache.log4j.Logger;
import com.bhaiti.kela.common.config.ApplicationConfig;
import javax.net.ssl.KeyManager;
public class SSLContextConfig {
private static final Logger LOGGER = Logger.getLogger(SSLContextConfig.class);
private ApplicationConfig config_ = ApplicationConfig.getInstance();
private TrustManager[] trustAllCerts = null;
private String keymanageralgorithm = null;
public SSLContext setupSslContext(){
SSLContext sslContext = null;
boolean trustall = false;
try {
String keyStorePath = config_.getKEYSTOREPATH();
String trustStorePath = config_.getTRUSTSTOREPATH();
String keyStorePw = config_.getKEYSTOREPW();
String trustStorePw = config_.getTRUSTSTOREPW();
String keyPass = config_.getKEYPASS();
String trustAllCertificate = config_.getTrustAllCertificate();
String keystoreType = config_.getKeystoreType();
keymanageralgorithm = config_.getKeymanageralgorithm();
trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }
}
};
if(trustAllCertificate.equalsIgnoreCase("True")){
trustall = true;
}
if (keystoreType.equalsIgnoreCase("JKS"))
sslContext = initializeSSLContext(keyStorePath, keyStorePw, trustStorePath, trustStorePw, keyPass,trustall);
else
sslContext = initializeSSLContextP12Cert(keyStorePath, keyStorePw, trustStorePath, trustStorePw, keyPass,trustall);
} catch (Exception exp) {
LOGGER.error("ConfigException exception occurred while reading the config file : " +exp.getMessage());
exp.printStackTrace();
}
return sslContext;
}
/**
*
* @param keyStorePath
* @param pwKeyStore
* @param trustStorePath
* @param pwTrustStore
* @param keyPass
* @return
* @throws Exception
*/
private SSLContext initializeSSLContext(final String keyStorePath, final String pwKeyStore, final String trustStorePath, final String pwTrustStore, final String keyPass, final boolean trustall) {
LOGGER.info(" In initializeSSLContext");
char[] keyStorePw = pwKeyStore.toCharArray();
char[] trustStorePw = pwTrustStore.toCharArray();
char[] keyPw = keyPass.toCharArray();
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
KeyStore ks = null;
try {
ks = KeyStore.getInstance("JKS");
} catch (KeyStoreException exp) {
LOGGER.error("KeyStoreException exception occurred while reading the config file : " +exp.getMessage());
}
FileInputStream fis = null;
try {
try {
fis = new FileInputStream(keyStorePath);
} catch (FileNotFoundException exp) {
LOGGER.error("FileNotFoundException exception occurred " +exp.getMessage());
}
try {
ks.load(fis, keyStorePw);
} catch (NoSuchAlgorithmException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} catch (CertificateException exp) {
LOGGER.error("CertificateException exception occurred " +exp.getMessage());
} catch (IOException exp) {
LOGGER.error("CertificateException exception occurred " +exp.getMessage());
}
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException exp) {
LOGGER.error("IOException exception occurred " +exp.getMessage());
}
}
LOGGER.info("[initializeSSLContext] KMF keystorepw loaded.");
KeyManagerFactory kmf = null;
try {
kmf = KeyManagerFactory.getInstance(keymanageralgorithm);
} catch (NoSuchAlgorithmException exp) {
LOGGER.error("IOException exception occurred " +exp.getMessage());
}
try {
kmf.init(ks, keyPw);
} catch (UnrecoverableKeyException exp) {
LOGGER.error("UnrecoverableKeyException exception occurred " +exp.getMessage());
} catch (KeyStoreException exp) {
LOGGER.error("KeyStoreException exception occurred " +exp.getMessage());
} catch (NoSuchAlgorithmException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
}
LOGGER.info("[initializeSSLContext] KMF init done.");
KeyStore ts = null;
try {
ts = KeyStore.getInstance("JKS");
} catch (KeyStoreException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
}
FileInputStream tfis = null;
SSLContext sslContext = null;
try {
tfis = new FileInputStream(trustStorePath);
ts.load(tfis, trustStorePw);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(keymanageralgorithm);
tmf.init(ts);
LOGGER.info("[initializeSSLContext] Truststore initialized");
sslContext = SSLContext.getInstance("TLS");
if(trustall)
sslContext.init(kmf.getKeyManagers(), trustAllCerts,secureRandom);
else
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers() ,secureRandom);
} catch (NoSuchAlgorithmException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} catch (CertificateException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} catch (IOException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} catch (KeyStoreException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} catch (KeyManagementException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} finally {
if (tfis != null)
try {
tfis.close();
} catch (IOException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
}
}
if((sslContext == null)){
LOGGER.error("[initializeSSLContext] sslContext is null");
System.exit(-1);
}
return sslContext;
}
/**
*
* @param keyStorePath
* @param pwKeyStore
* @param trustStorePath
* @param pwTrustStore
* @param keyPass
* @return
* @throws Exception
*/
private SSLContext initializeSSLContextP12Cert(final String keyStorePath, final String pwKeyStore, final String trustStorePath, final String pwTrustStore, final String keyPass,final boolean trustall) {
LOGGER.info("In initializeSSLContextP12Cert");
SSLContext sslContext = null;
String keystore = keyStorePath;
String keystorepass = pwKeyStore;
String truststore = trustStorePath;
String truststorepass = pwTrustStore;
try{
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream(keystore), keystorepass.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keymanageralgorithm);
kmf.init(clientStore, keystorepass.toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream(truststore), truststorepass.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(keymanageralgorithm);
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
sslContext = SSLContext.getInstance("TLS");
if(trustall)
sslContext.init(kms, trustAllCerts, new SecureRandom());
else
sslContext.init(kms, tms, new SecureRandom());
} catch (NoSuchAlgorithmException exp) {
LOGGER.error("NoSuchAlgorithmException exception occurred " +exp.getMessage());
} catch (CertificateException exp) {
LOGGER.error("CertificateException exception occurred " +exp.getMessage());
} catch (IOException exp) {
LOGGER.error("IOException occurred while reading the key file " +exp.getMessage());
} catch (KeyStoreException exp) {
LOGGER.error("KeyStoreException exception occurred " +exp.getMessage());
} catch (KeyManagementException exp) {
LOGGER.error("KeyManagementException exception occurred " +exp.getMessage());
}catch (UnrecoverableKeyException exp) {
LOGGER.error("UnrecoverableKeyException exception occurred " +exp.getMessage());
}
if((sslContext == null)){
LOGGER.error("[initializeSSLContext] sslContext is null");
LOGGER.error("[initializeSSLContext] verify ssl config");
LOGGER.error("MyREST application exit with status code -1");
//System.exit(-1);
}
LOGGER.info("[initializeSSLContextP12Cert] Truststore and KeyStore initialized");
return sslContext;
}
}
Now we need to add the two config files below to the root directory of this project. The first one is holding all the config information for this project (please read the certificate configuration part carefully) and the second file is a log property file. Please keep in mind that the below files are just sample files only, so do not blindly copy them to your project. Create the below two files in your project as per your config information.
LOG_PROPERTY_FILE_PATH=C:\\Projects\\SSLClient\\log.properties
KEYSTOREPATH=C:\\Projects\\SSLClient\\key\\etc\\mykestore.jks
TRUSTSTOREPATH=kelabhalkoikoribi
KEYSTOREPW=kelapitonpabi
TRUSTSTOREPW=kelabhalkoikoribi
KEYPASS=kelapitonpabi
keystoreType=jks
;assign above key as 'keystoreType=p12' if you are using a PKCS certificate/store
trustAllCertificate=yes
; assign 'no' if you don't want your application to force whether a site should be trusted or not, if you are getting a error like not a trusted site you can
;put the value as 'no' to avoid such issue. But not recomented.
keymanageralgorithm=SunX509 // For IBM it should be IbmX509
log4j.rootLogger=INFO, file, stdout
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\Projects\\SSLClient\\log\\sslClient.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Now add a new package, com.bhaiti.kela.ssl.client, and add the below class to it. This is our actual client application class from which we will make all the SSL-based HTTPS calls.
package com.bhaiti.kela.ssl.client;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import org.apache.log4j.Logger;
import com.bhaiti.kela.common.config.ApplicationConfig;
import com.bhaiti.kela.ssl.config.SSLContextConfig;
public class SSLClient {
static SSLClient _sslClient = null;
int _responseCode = -1;
static private ApplicationConfig config_ = ApplicationConfig.getInstance();
private static final Logger LOGGER = Logger.getLogger(SSLClient.class);
URL url_ = null;
HttpsURLConnection connection_ = null;
static SSLContext sslContext = null;
private SSLClient() {
SSLContextConfig sslconfig = new SSLContextConfig();
sslContext = sslconfig.setupSslContext();
}
public static SSLClient getSSLClient() {
if (_sslClient == null) {
_sslClient = new SSLClient();
}
return _sslClient;
}
private boolean setSSLConnection(URL url, String method, String msgtype) {
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
.getSocketFactory());
try {
connection_ = (HttpsURLConnection) url.openConnection();
connection_.setSSLSocketFactory(sslContext.getSocketFactory());
if(method == "POST")
connection_.setRequestMethod(method);
connection_.setDoOutput(true );
connection_.setRequestProperty("Content-Type", msgtype /*"text/xml" */ );
connection_.connect();
return true;
} catch (Exception e) {
LOGGER.error("Exception occurred while establishing connection to SSL server. Error :"
+ e.getMessage());
connection_.disconnect();
connection_ = null;
return false;
}
}
public void releaseConnection() {
connection_.disconnect();
connection_ = null;
}
/**
*
* @param url
* @param method
* @param message
* @param msgtype json or xml
* @return
*/
public String sendRequest(URL url, String method, String message, String msgtype) {
String response = null;
if (setSSLConnection(url,method,msgtype)) {
try{
//Sending the request to Remote server
OutputStreamWriter writer = new OutputStreamWriter(connection_.getOutputStream());
writer.write(message);
writer.flush();
writer.close();
_responseCode = connection_.getResponseCode();
LOGGER.info("Response Code :" + _responseCode);
// reading the response
InputStreamReader reader = new InputStreamReader(connection_.getInputStream());
StringBuilder buf = new StringBuilder();
char[] cbuf = new char[ 2048 ];
int num;
while ( -1 != (num = reader.read( cbuf )))
{
buf.append(cbuf, 0, num );
}
response = buf.toString();
}catch(Exception e){
response = "<EXCEPTION>Exception occurred while sending message</EXCEPTION>";
e.printStackTrace();
}
}
releaseConnection();
return response;
}
}
Finally, we are going to add the main class of this application.
Add the package com.bhaiti.kela.ssl.client.app and add the below class to it.
package com.bhaiti.kela.ssl.client.app;
import java.net.URL;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import com.bhaiti.kela.common.config.ApplicationConfig;
import com.bhaiti.kela.ssl.client.SSLClient;
public class ClientApp {
public static void main(String[] args) {
System.out.println("In main");
Configuration config = null;
//Load (String)configuration
try {
String currentPath = System.getProperty("user.dir");
config = new PropertiesConfiguration(currentPath + "/" + "system.properties");
}catch(Exception e) {
System.out.println("Exception in reading properties file : system.properties");
e.printStackTrace();
System.exit(-1);
}
ApplicationConfig ac = ApplicationConfig.getInstance();
ac.setKEYSTOREPATH((String)config.getProperty("KEYSTOREPATH"));
ac.setTRUSTSTOREPATH((String)config.getProperty("TRUSTSTOREPATH"));
ac.setKEYSTOREPW((String)config.getProperty("KEYSTOREPW"));
ac.setTRUSTSTOREPW((String)config.getProperty("TRUSTSTOREPW"));
ac.setKEYPASS((String)config.getProperty("KEYPASS"));
ac.setKeystoreType((String)config.getProperty("keystoreType"));
ac.setTrustAllCertificate((String)config.getProperty("trustAllCertificate"));
ac.setKeymanageralgorithm((String)config.getProperty("keymanageralgorithm"));
try {
//A SOAP web service call
SSLClient sslClient = SSLClient.getSSLClient();
String strurl ="https://localhost:23521/app/v1/myservice";//you can add all the urls in config file
URL url = new URL(strurl);
String method = "POST";
String message = "your soap message body";
String msgtype = "text/xml";
String response = sslClient.sendRequest(url, method, message, msgtype);
//A RESTFul GET web service call
strurl ="https://localhost:23521/app/v1/test/Student.json?studentId=9999";
url = new URL(strurl);
method = "GET";
message = "";
msgtype = "text/xml";
response = sslClient.sendRequest(url, method, message, msgtype);
//A RESTFul POST web service call
strurl ="https://localhost:23521/app/v1/test/Student.json";
url = new URL(strurl);
method = "POST";
message = "your json message body";
msgtype = "text/xml";
response = sslClient.sendRequest(url, method, message, msgtype);
}catch(Exception e) {
e.printStackTrace();
}
}
}
Now you can select this file by right-clicking and selecting, 'Run as Java Application.' Also, you can create a jar file and run it. For any help or information leave a comment.
Opinions expressed by DZone contributors are their own.
Comments