image

Cracking Core Java Interviews 3rd Edition

A Comprehensive Guide to Crack Core Java Interviews in Investment Banks, HealthCare IT & Startups. It covers Core Java, Algorithms, Data Structures, Concurrency, Hibernate and Spring MVC.

Specifically for investment banking domain, healthcare IT and product companies i.e. UBS, RBS, Blackrock, Morgan Stanley, JP Morgan, Nomura, Barclays, Citibank, Markit, Bank of America, Goldman Sachs and other companies i.e. Global Logic, Adobe, hCentive, Edifecs, Expedia, Infosys, TCS, Sapient, Wipro, HCL etc.
Free Chapters PDF
1214 downloads
Buy Full PDF ₹250
3rd Edition
Last Updated : Friday, March 4, 2016 12:22:06 AM IST Total Page Hits 9295

Using RestTemplate for Self Signed SSL certificate communication

Transport Layer Security (TLS) and its predecessor, Secure Sockets Layer (SSL), are technologies which allow web browsers and web servers to communicate over a secured connection. This means that the data being sent is encrypted by one side, transmitted, then decrypted by the other side before processing. This is a two-way process, meaning that both the server AND the browser encrypt all traffic before sending out data.

Another important aspect of the SSL/TLS protocol is Authentication. This means that during your initial attempt to communicate with a web server over a secure connection, that server will present your web browser with a set of credentials, in the form of a “Certificate”, as proof the site is who and what it claims to be. In certain cases, the server may also request a Certificate from your web browser, asking for proof that you are who you claim to be. This is known as “Client Authentication,” although in practice this is used more for business-to-business (B2B) transactions than with individual users. Most SSL-enabled web servers do not request Client Authentication.

More information can be found here Configure SSL in Tomcat

Step 1. Create a Keystore for SSL

Java provides a tool named keytool in %JAVA_HOME%\bin directory. You can run genkey (or genkeypair, both are same) command, as shown in below code snippet.

C:\Users\munish>keytool -genkey -alias shunyafoundation -keyalg RSA -keysize 2048 -validity 700 -keypass changeit -storepass changeit -keystore keystore.jks
What is your first and last name?
  [Unknown]:  www.shunyafoundation.com
What is the name of your organizational unit?
  [Unknown]:  IT
What is the name of your organization?
  [Unknown]:  Shunya Foundation
What is the name of your City or Locality?
  [Unknown]:  Mohali
What is the name of your State or Province?
  [Unknown]:  Punjab
What is the two-letter country code for this unit?
  [Unknown]:  IN
Is CN=www.shunyafoundation.com, OU=Ecommerce, O=Shunya Foundation, L=Mohali, ST=Punjab, C=IN correct?
  [no]:  yes

Please note that you must supply hostname when keytool prompts for “First and Last name”. This can be localhost for development/testing, if you do not provide hostname while creating keystore, SSL validation will fail complaining hostname does not match domain name in the certificate.

List and Verify Certificate Entry
We can use the same keytool with list command to list the certificate details present in a given keystore.

C:\Users\munish>keytool -list -keystore keystore.jks
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 2 entries

shunyafoundation, Mar 3, 2016, PrivateKeyEntry,
Certificate fingerprint (SHA1): 60:05:46:8F:08:6B:03:7A:34:96:38:9A:6B:09:32:03:D8:FB:D6:AA
localhost, Mar 3, 2016, PrivateKeyEntry,
Certificate fingerprint (SHA1): 2F:AC:C4:94:FA:2B:4A:A7:B1:51:D8:6A:70:D6:F7:CE:92:91:67:DE

Step 2. Configure Tomcat to use Self Signed Certificate

We need to enable SSL connector in Tomcat server configuration and provide path for newly created Keystore along with keystore password, as shown below

File Path - $CATALINA_HOME/conf/server.xml

<!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the 
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->

 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
           keystoreFile="keystore.jks"
           keystorePass="changeit" />

Step 2. Import Self Signed Certificate into Java (security/lib)

First of all export public certificate (that is without private key) into a .cer file that can be distributed a public clients, below is the step to create a .cer file

D:\prod-backup>keytool -exportcert -keystore shunya_keystore.jks -alias shunya -file shunya.cer
Enter keystore password:
Certificate stored in file <shunya.cer>

Now copy this shunya.cer file to %Java_Home%\jre\lib\security folder, then run the below command to import above certificate to cacerts file

C:\Program Files\Java\jdk1.8.0_74\jre\lib\security>keytool -importcert -keystore cacerts -alias shunya -file shunya.cer
Enter keystore password:
Owner: CN=www.shunyafoundation.com, OU=Shunya, O=Shunya Foundation, L=Mohali, ST=Punjab, C=IN
Issuer: CN=www.shunyafoundation.com, OU=Shunya, O=Shunya Foundation, L=Mohali, ST=Punjab, C=IN
Serial number: 39172677
Valid from: Wed Mar 02 20:24:30 IST 2016 until: Tue May 31 20:24:30 IST 2016
Certificate fingerprints:
         MD5:  49:51:FA:1A:6B:9B:78:A3:9A:A1:4C:22:88:F2:5C:87
         SHA1: B3:A8:26:82:DE:0B:BE:CA:A3:F1:D0:2D:00:A6:0A:64:EE:CB:5C:34
         SHA256: 01:EC:6C:36:46:55:03:3A:71:EF:89:4F:C3:52:34:B2:39:99:41:D2:D6:5D:9D:EF:01:5F:4A:4D:12:40:5A:E3
         Signature algorithm name: SHA256withRSA
         Version: 3
Extensions:
1: ObjectId: 2.5.29.14 Criticality=false
Trust this certificate? [no]:  yes
Certificate was added to keystore

You may require elevated administrative privilege to run the above command. Now you are all set for making Https Calls using Java programs that run on the same JVM where we imported our shunya.cer file. Below is an example of the same.


public final static void main(String[] args) throws Exception {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            HttpGet httpget = new HttpGet("https://www.shunyafoundation.com");
            System.out.println("Executing request " + httpget.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

Step 3. Creating a HttpClient that loads custom keystore for self signed SSL certificate

Also, you may create a another keystore that contains this public certificate, without any private key in it. This keystore can be freely distributed to public for SSL Communication

D:\prod-backup>keytool -importcert -file shunya.cer -keystore shunya.jks -alias shunya
Enter keystore password:
Re-enter new password:
Owner: CN=www.shunyafoundation.com, OU=Shunya, O=Shunya Foundation, L=Mohali, ST=Punjab, C=IN
Issuer: CN=www.shunyafoundation.com, OU=Shunya, O=Shunya Foundation, L=Mohali, ST=Punjab, C=IN
Serial number: 39172677
Valid from: Wed Mar 02 20:24:30 IST 2016 until: Tue May 31 20:24:30 IST 2016
Certificate fingerprints:
         MD5:  49:51:FA:1A:6B:9B:78:A3:9A:A1:4C:22:88:F2:5C:87
         SHA1: B3:A8:26:82:DE:0B:BE:CA:A3:F1:D0:2D:00:A6:0A:64:EE:CB:5C:34
         SHA256: 01:EC:6C:36:46:55:03:3A:71:EF:89:4F:C3:52:34:B2:39:99:41:D2:D6:5D:9D:EF:01:5F:4A:4D:12:40:5A:E3
         Signature algorithm name: SHA256withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false

Trust this certificate? [no]:  yes
Certificate was added to keystore

Now this new shunya.jks keystore can be used by httpClient for SSL communication. The code below explains the use of shunya.jks keystore by HttpClient

import java.io.File;

import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

public class ClientCustomSSL {
    public final static void main(String[] args) throws Exception {
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadTrustMaterial(new File("D:\\prod-backup\\shunya.jks"), "changeit".toCharArray(), new TrustSelfSignedStrategy())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, 
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        try {
            HttpGet httpget = new HttpGet("https://www.shunyafoundation.com");
            System.out.println("Executing request " + httpget.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                HttpEntity entity = response.getEntity();

                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

Step 4. Creating RestTemplate using HttpClient that accepts custom Self Signed Certificate (in Memory loading)

        //Load the keystore into stream inside a jar (in memory keystore loading)
        InputStream keyStoreInputStream = RemoteService.class.getClass().getClassLoader().getResourceAsStream("keystore.jks");
        if (keyStoreInputStream == null) {
            throw new FileNotFoundException("Could not find file named 'shunya_keystore' in the CLASSPATH");
        }
        final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try {
            trustStore.load(keyStoreInputStream, "shunya".toCharArray());
        } finally {
            keyStoreInputStream.close();
        }

        SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        httpComponentsClientHttpRequestFactory.setConnectTimeout(60000);
        httpComponentsClientHttpRequestFactory.setReadTimeout(180000);

        final RestTemplate restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory);

        ResponseEntity<String> response = restTemplate.exchange(urlOverHttps, HttpMethod.GET, null, String.class);

         assertThat(response.getStatusCode().value(), equalTo(200));

Step . HttpClient that ignores SSL certificate altogether (not a proper way, just for demonstration)

We can configure HttpClient to ignore all SSL certificate and proceed without doing any validation, as shown in code below

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;

public class ClientIgnoreSSLCertificate {

    public final static void main(String[] args) throws Exception {
        // Ignore All SSL certificate
        SSLContext sslcontext = SSLContexts.custom()
                .loadTrustMaterial(null, (chain, authType) -> true)
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, new NoopHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        try {
            HttpGet httpget = new HttpGet("https://www.shunyafoundation.com");
            System.out.println("Executing request " + httpget.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

Step 7. Using HttpsUrlConnection instead of HttpClient

public final static void main(String[] args) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        final FileInputStream trustStore = new FileInputStream(new File("D:\\prod-backup\\shunya_keystore.jks"));
        keyStore.load(trustStore, "shunya".toCharArray());
        trustStore.close();

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);
        SSLContext ctx = SSLContext.getInstance("TLS");
        //Older versions of SSL may use it like this
//      SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(null, tmf.getTrustManagers(), null);
        SSLSocketFactory sslFactory = ctx.getSocketFactory();

        URL url = new URL("https://www.shunyafoundation.com");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setSSLSocketFactory(sslFactory);
        conn.setRequestMethod("GET");
        conn.setDoOutput(true);
        InputStreamReader isr = new InputStreamReader(conn.getInputStream());

        // read it with BufferedReader
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }



Similar Articles

1. Synechron Java Interview Questions

Collection of Java Interview Questions (Core Java, Spring, database and other concepts) for Synechron in banking and finance domain

2. Design Metro Smart Card System for Delhi using Java

Design a program in Java for Metro Smart Card System in Delhi. Evaluation criteria will be based on code completeness, code structure and quality, modularity, usage of OO principles, choice of data structure and unit tests.

3. What does volatile keyword do in a multi-threading environment

volatile keyword helps programmers write thread safe program