Enable TLS in HTTP client with Post request - java

I want to add TLS 1.2 to the below code, Tried by creating socket but no luck. Can someone help on it ? Can we add it after creating a client ?
private static int executeSOAPRequest(String req, String targetURL)
throws Exception {
PostMethod post = new PostMethod(targetURL);
post.setRequestBody(req);
post.setRequestHeader("Content-type",
"text/xml; characterset=ISO-8859-1");
post.setRequestHeader("SOAPAction", "\"\"");
// prepare HTTP Client
HttpClient client = new HttpClient();
client.getParams().setParameter("SOAPAction", "\"\"");
// Post the request
int respCode = client.executeMethod(post);
System.out.println(post.getResponseBodyAsString());
// If response is not success
if (respCode != 200)
throw new Exception("Executing SOAP request has failed.");
// Convert the response into NOM XML
int resp = 0;
Document doc = nomDocPool.lendDocument();
try {
resp = doc.parseString(post.getResponseBodyAsString());
nomDocPool.returnDocument(doc);
} catch (XMLException e) {
nomDocPool.returnDocument(doc);
//logger.error("Exception while generating SAML : "
//+ e);
throw e;
}
System.out.println("resp: "+resp);
return resp;
}

HttpClient already handles TLS for you. This is documented:
http://hc.apache.org/httpclient-3.x/sslguide.html
HttpClient provides full support for HTTP over Secure Sockets Layer (SSL) or IETF Transport Layer Security (TLS) protocols by leveraging the Java Secure Socket Extension (JSSE). JSSE has been integrated into the Java 2 platform as of version 1.4 and works with HttpClient out of the box.
All you have to do is make sure your targetURL is using https:// instead of http://, then HttpClient handles the rest for you.

Forget HttpClient. Use javax.net.ssl.HttpsURLConnection.
String myResponse = null;
URL url = new URL(targetURL);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestProperty("Content-Type", "text/xml; characterset=ISO-8859-1");
con.setRequestProperty("SOAPAction", "\"\"");
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.setSSLSocketFactory(My_Lovely_CertificateHelper.getSslSocketFactory());
con.connect();
OutputStream os = con.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "ISO-8859-1");
osw.write(req);
osw.flush();
osw.close();
InputStream is = null;
if (con.getResponseCode() < HttpsURLConnection.HTTP_BAD_REQUEST) {
is = con.getInputStream();
} else {
is = con.getErrorStream();
}
InputStreamReader isr = new InputStreamReader(is, "ISO-8859-1");
int read = -1;
char[] buff = new char[1024];
StringBuilder sb = new StringBuilder();
while ((read = isr.read(buff)) != -1) {
sb.append(buff, 0, read);
}
myResponse = sb.toString();
return myResponse;
getSslSocketFactory()
public static SSLSocketFactory getSslSocketFactory() throws Exception {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
String trustStorePath = getcertPath(); //"user.dir" + "\ohHappyDays.jks";
String password = "finallyFoundLoveIn2021";
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(trustStorePath), password.toCharArray());
kmf.init(ks, password.toCharArray());
sc.init(kmf.getKeyManagers(), (TrustManager[]) null, (SecureRandom) null);
return sc.getSocketFactory();
}

Related

Custom Implementation of Trust Manager and Hostname Verifier

I am making post request to a third party service setting the hostname verifier and trust manager. The default pass all implementation however doesn't pass sonarcloud checks and gives errors which are attached in screenshots below. Have browsed for hours searching for custom implementation but haven't found anything. Please suggest of any resources or implementation you may have with yourself. Here is the code for the same:
public static class DummyTrustManager implements X509TrustManager {
public DummyTrustManager() {
}
public boolean isClientTrusted(X509Certificate cert[]) {
return true;
}
public boolean isServerTrusted(X509Certificate cert[]) {
return true;
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
}
public static class DummyHostnameVerifier implements HostnameVerifier {
public boolean verify(String urlHostname, String certHostname) {
return true;
}
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
}
public String nsdlResponseLine(String data, String signature){
String line = null;
try {
String urlOfNsdl = nsdlKycVerificationUrl;
final String version = nsdlKycVerificationVersion;
SSLContext sslcontext = SSLContext.getInstance("TLSv1.2");
sslcontext.init(new KeyManager[0],
new TrustManager[]{new DummyTrustManager()},
new SecureRandom());
SSLSocketFactory factory = sslcontext.getSocketFactory();
String urlParameters = getUrlParameters(data, signature, version);
URL url = new URL(urlOfNsdl);
connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setSSLSocketFactory(factory);
connection.setHostnameVerifier(new DummyHostnameVerifier());
OutputStream os = connection.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
osw.write(urlParameters);
osw.flush();
osw.close();
InputStream is = connection.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
line = in.readLine();
is.close();
in.close();
} catch (Exception e) {
log.debug("::Exception: {}",e.getMessage());
}
return line;
}
private String getUrlParameters(String data, String signature, String version) throws UnsupportedEncodingException {
return "data=" + URLEncoder.encode(data, "UTF-8") + "&signature=" + URLEncoder.encode(signature, "UTF-8") + "&version=" + URLEncoder.encode(version, "UTF-8");
}
Errors which come in Sonarcloud:
1: https://i.stack.imgur.com/y5qWJ.png
ChatGPT came to rescue and solved the issue. I used default JSSE implementation for both. For sslcontext How do I provide a specific TrustStore while using the default KeyStore in Java (JSSE) ,this answer served as guiding light while for hostname verifier HttpsURLConnection.getDefaultHostnameVerifier() method can be used. My final code looks like this:
public String nsdlResponseLine(String data, String signature){
String line = null;
try {
String urlOfNsdl = nsdlKycVerificationUrl;
final String version = nsdlKycVerificationVersion;
SSLContext sslcontext = SSLContext.getInstance("TLSv1.2");
String keyStore = System.getProperty("javax.net.ssl.keyStore");
String keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType());
String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword","");
KeyManager[] kms = null;
if (keyStore != null) {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(keyStoreType);
if (keyStore != null && !keyStore.equals("NONE")) {
FileInputStream fs = new FileInputStream(keyStore);
ks.load(fs, keyStorePassword.toCharArray());
if (fs != null)
fs.close();
char[] password = null;
if (keyStorePassword.length() > 0)
password = keyStorePassword.toCharArray();
kmf.init(ks, password);
kms = kmf.getKeyManagers();
}
sslcontext.init(kms, null, null);
}
SSLSocketFactory factory = sslcontext.getSocketFactory();
String urlParameters = getUrlParameters(data, signature, version);
URL url = new URL(urlOfNsdl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setSSLSocketFactory(factory);
connection.setHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier());
OutputStream os = connection.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
osw.write(urlParameters);
osw.flush();
osw.close();
InputStream is = connection.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
line = in.readLine();
is.close();
in.close();
} catch (Exception e) {
log.debug("::Exception: {}",e.getMessage());
}
log.debug("line;{}",line);
return line;
}
private String getUrlParameters(String data, String signature, String version) throws UnsupportedEncodingException {
return "data=" + URLEncoder.encode(data, "UTF-8") + "&signature=" + URLEncoder.encode(signature, "UTF-8") + "&version=" + URLEncoder.encode(version, "UTF-8");
}

How to Enable a TLS 1.2 in IBM java 1.6?

I need to Enable a TLS 1.2 connection in IBM Java 1.6[SR16 FP60]. I tried establishing the connection by
public static void TLS() throws NoSuchAlgorithmException, KeyManagementException, IOException{
System.setProperty("https.protocols", "TLSv1.2");
URL url = new URL("https://jsonplaceholder.typicode.com/posts");
String XML = "<Test></test>"
SSLContext ssl = SSLContext.getInstance("TLSv1.2");
// ctx.init(null, null, null);
ssl.init(null, null, null);
SSLContext.setDefault(ssl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(ssl.getSocketFactory());
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/xml");
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
os.write(XML.getBytes());
os.flush();
os.close();
System.out.println(">>>Connection certificate"+connection.getServerCertificates());
System.out.println(">>>Connection"+connection.getContent());
int responseCode = connection.getResponseCode();
System.out.println("POST Response Code : " + responseCode);
System.out.println("POST Response Message : " + connection.getResponseMessage());
if (responseCode == HttpsURLConnection.HTTP_OK) { //success
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in .readLine()) != null) {
response.append(inputLine);
} in .close();
System.out.println(response.toString());}
}
While establishing the connection it's throwing an error
Received Fatal alert : handshake_failure
Please advise us the resolve this issue.
I guess you are using WebSphere 6? You have to upgrade to 7.0.0.23, 8.0.0.3 or 8.5.
See https://developer.ibm.com/answers/questions/206952/how-do-i-configure-websphere-application-server-ss.html

How to POST xml data while calling API through JAVA?

I am creating an application where I want to POST xml data directly (without key value pair) to API. The API needs certification authentication which is done here in code. Now I want to POST the data to same URL.
Here is what I want to do :
My current code is :
#Override
public String demoAPI(String xmlData) {
StringBuilder sb = new StringBuilder();
String output="";
try {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream(new File("path-to-pfx-file")),
"password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "password".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("path-to-jks-file"), "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kms, tms, new SecureRandom());
SSLContext.setDefault(sslContext);
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
URL url = new URL("URL");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(100000);
con.setSSLSocketFactory(sslContext.getSocketFactory());
con.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
System.out.println(sb.toString());
output = sb.toString();
} catch (Exception e) {
e.printStackTrace();
output = e.getMessage();
}
return output;
}
Whereas , for same url , I want to POST xmlData from method.
How can I do that ? What should I change in the code after
con.setRequestMethod("POST"); ?
You have a url and you have some XML to post this url via HTTP. And your post request is a SOAP request, you can send this soap message in the body of this request. So nothing special or different than many developers' do. Post your soap data via http by using java.net or Apache or others. Here are the code samples to do this:
HttpsURLConnection con = null;
try{
URL url = new URL("URL");
con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("content-type", "application/x-www-form-urlencoded");
con.setRequestProperty("Content-Language", "application/soap+xml; charset=utf-8"); // request properties, set your needs
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
os.write(xmlData.getBytes("utf-8"));
os.close();
}catch(Exception e){
e.printStackTrace();
}finally{
con.disconnect();
}
Another option would be to use Apache library. And the code:
HttpPost httpPost = new HttpPost("URL");
StringEntity strEntity = new StringEntity(xmlData, "text/xml", "UTF-8");
strEntity.setContentType("text/xml");
httpPost.setHeader("Content-Type","application/soap+xml;charset=UTF-8");
httpPost.setEntity(strEntity);
HttpClient httpclient = new DefaultHttpClient();
BasicHttpResponse httpResponse = (BasicHttpResponse) httpclient.execute(httpPost);

java https no verify certificate

I would like to connect to a test server in https from a java program I made. I don't want to verify anything in the certificate, how can I achieve this?
I am using:
HttpURLConnection connection = (HttpURLConnection) ( new URL(server).openConnection() );
connection.setDoOutput (true);
connection.setDoInput (true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
OutputStream out = connection.getOutputStream();
OutputStreamWriter wout = new OutputStreamWriter(out, "UTF-8");
wout.write(xml);
wout.flush();
out .close();
//READ RESPONSE.
InputStream in = connection.getInputStream();
But when I execute, I get:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
Generally you can acces https sites but Somesites wanted the certificate. So you can use under the codes. And you have to take certificate with InstallCert program.
String httpsURL = "https://www.google.com";
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
InputStream ins = con.getInputStream();
InputStreamReader isr = new InputStreamReader(ins);
BufferedReader in = new BufferedReader(isr);
You can do that this way..
URL url1;
try {
url1 = new URL(url);
if(url1.getProtocol().equalsIgnoreCase("https")){// you dont need this check
try {
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, javax.net.ssl.SSLSession session) {
if (urlHostName.equals(session.getPeerHost())) {
logger.info("Verified HTTPS "+session.getPeerHost()+" >> "+ urlHostName);
} else {
logger.info("Warning: URL host "+urlHostName+" is different to SSLSession host "+session.getPeerHost());
}
return true;
}
};
TrustManager[] trustAll = new javax.net.ssl.TrustManager[] { new javax.net.ssl.X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
} };
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
sc.init(null, trustAll, new java.security.SecureRandom());
SSLSocketFactory factory = (SSLSocketFactory) sc.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(factory);
HttpsURLConnection.setDefaultHostnameVerifier(hv);
HttpsURLConnection connection = (HttpsURLConnection) url1.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
Continue with your OutputStreamWriter write part.
You can do this without importing ssl certificate and without any third party support.
if you're trying to get from https://IP/file, it'll return the error the IP is not verified

SOAP - PKIX path building failed

I'm building a server that has to call two webservices. Webservices have the same CA certificate (PKCS12).
the first one receives request by GET, the other one by SOAP call.
follow a part of code that creates connection for GET request
InputStream inputStream = null;
// is https protocol?
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
// create connection
HttpsURLConnection httpsUrlConnection = null;
if(proxy != null){
httpsUrlConnection = (HttpsURLConnection) url.openConnection(proxy);
} else {
httpsUrlConnection = (HttpsURLConnection) url.openConnection();
}
// set the check to: do not verify
httpsUrlConnection.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
setHeaders(httpsUrlConnection, headers);
//set del certificato
log.debug("set certificate for get...");
File cerp12 = new File(Utils.getWebAppLocalPath(),"WEB-INF"+String.valueOf(File.separatorChar)+PropConfig.getProperty("cer.p12"));
((HttpsURLConnection) httpsUrlConnection).setSSLSocketFactory(security(cerp12,PropConfig.getProperty("cer.pwd")));
httpsUrlConnection.connect();
inputStream = httpsUrlConnection.getInputStream();
} else {
HttpURLConnection httpUrlConnection = null;
if(proxy != null){
httpUrlConnection = (HttpURLConnection) url.openConnection(proxy);
} else {
httpUrlConnection = (HttpURLConnection) url.openConnection();
}
setHeaders(httpUrlConnection, headers);
inputStream = httpUrlConnection.getInputStream();
}
in = new BufferedReader(new InputStreamReader(inputStream));
String inputLine;
while ((inputLine = in.readLine()) != null) {
result.append(inputLine);
}
and this part is for SOAP request
InputStream inputStream = null;
// is https protocol?
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
// create connection
HttpsURLConnection httpsUrlConnection = null;
if(proxy != null){
httpsUrlConnection = (HttpsURLConnection) url.openConnection(proxy);
} else {
httpsUrlConnection = (HttpsURLConnection) url.openConnection();
}
// set the check to: do not verify
httpsUrlConnection.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
setHeaders(httpsUrlConnection, headers);
//set del certificato
log.debug("set certificate for get...");
File cerp12 = new File(Utils.getWebAppLocalPath(),"WEB-INF"+String.valueOf(File.separatorChar)+PropConfig.getProperty("cer.p12"));
((HttpsURLConnection) httpsUrlConnection).setSSLSocketFactory(security(cerp12,PropConfig.getProperty("cer.pwd")));
httpsUrlConnection.connect();
inputStream = httpsUrlConnection.getInputStream();
} else {
HttpURLConnection httpUrlConnection = null;
if(proxy != null){
httpUrlConnection = (HttpURLConnection) url.openConnection(proxy);
} else {
httpUrlConnection = (HttpURLConnection) url.openConnection();
}
setHeaders(httpUrlConnection, headers);
inputStream = httpUrlConnection.getInputStream();
}
in = new BufferedReader(new InputStreamReader(inputStream));
String inputLine;
while ((inputLine = in.readLine()) != null) {
result.append(inputLine);
}
the code is almost the same
with GET request I have no problem, but with SOAP request httpsUrlConnection.connect(); throws
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Here is howto create ssl context for HTTPS connection.
SSLSocketFactory socketFactory = createSSLContext().getSocketFactory();
HttpsURLConnection connection = (HttpsURLConnection) (url).openConnection();
connection.setSSLSocketFactory(socketFactory);
And method to create SSL context. Note, it load root server certificate from .pem file (x509 format) and client certificate from .p12 (pkcs12 format). If server don't required client certificate, pass null for key managers. If server sertificate issued by authority, which already in $JRE_HOME/lib/security/cacerts, pass null as trust managers.
And one more note: in .pem file you should store root certificate in PKIX path of server certificate. For example, github.com That site has PKIX path CN = github.com -> CN = DigiCert High Assurance EV CA-1 -> CN = DigiCert High Assurance EV Root CA -> CN = GTE CyberTrust Global Root. So you store GTE CyberTrust Global Root
private final SSLContext createSSLContext()
throws NoSuchAlgorithmException, KeyStoreException,
CertificateException, IOException,
UnrecoverableKeyException, KeyManagementException {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(Config.getString(Config.KEYSTORE_PATH)));
} catch (Exception ex) {
throw new IOException("not found keystore file: " Config.getString(Config.KEYSTORE_PATH), ex);
}
try{
keyStore.load(fis, Config.getString(Config.KEYSTORE_PASSWORD).toCharArray());
}finally {
IOUtils.closeQuietly(fis);
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream in = new FileInputStream(Config.getString(Config.HTTPS_SERVER_CERT));
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(null);
try {
X509Certificate cacert = (X509Certificate) cf.generateCertificate(in);
trustStore.setCertificateEntry("alias", cacert);
} finally {
IOUtils.closeQuietly(in);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, Config.getString(Config.KEYSTORE_PASSWORD).toCharArray());
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
return sslContext;
}

Categories