Spring Boot HTTPS Server & Client Template

In my previous post, I shared a template to run a Spring Boot server in a https self-signed secured connection. However, that template is only valid to serve static content and this is not what I really wanted.

In this post, using a gradle multi-module project, I am going to share an enhanced version comprised of a server and a client.

The code is available to be cloned at Github

git clone https://github.com/immontilla/spring-boot-https-server.git && cd spring-boot-https-server

The most significant difference between the previous version and this one, is the scenario. Back then, I just configured a secure connection for the server and simply proved it in a browser because it had no more to serve than a single index.html file. Now, I am going to expose a REST operation too onto the server at /chuck/norris end-point, and I want any client having the server self-signed certificate public key could access to it.

To do that, I had to change my certificate generation strategy. Now, I am securing the server connection using a key store file with no store type defined.

Before I continue, I had to give all the credit to a couple of great posts, specially this one viniciusccarvalho/boot-two-way-ssl-example as well as <a href="https://github.com/robinhowlett/everything-ssl" title"Everything You Ever Wanted to Know About SSL (but Were Afraid to Ask)" target="_blank">robinhowlett/everything-ssl. I have followed their instructions, updated its components, and merged the project management into a single multi-module Spring Boot project.

To begin with, I recommend to delete all .jks and .cer project's files and create a new version of each. Assuming the current directory is spring-boot-https-server execute:

find . -type f -name "*.jks" -exec rm -f {} \; 
find . -type f -name "*.cer" -exec rm -f {} \;

Then, create a new temp folder:

mkdir temp && cd temp

Now, follow these steps:

1.Generate a couple of random passwords to use in the next steps:

srvpass=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo '')

clipass=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo '')

2.Create the client and server key store files

keytool -genkeypair -alias serverkey -keyalg RSA -dname "CN=localhost,OU=OrgUnit,O=Org,L=Madrid,S=Madrid,C=ES" -keypass $srvpass -keystore server.jks -storepass $srvpass 

keytool -genkeypair -alias clientkey -keyalg RSA -dname "CN=localhost,OU=OrgUnit,O=Org,L=Madrid,S=Madrid,C=ES" -keypass $clipass -keystore client.jks -storepass $clipass

3.Export the public key of each .jks file:

keytool -exportcert -alias clientkey -file client-public.cer -keystore client.jks -storepass $clipass

keytool -exportcert -alias serverkey -file server-public.cer -keystore server.jks -storepass $srvpass

4.Import public client certificate onto server keystore (and viceversa):

keytool -importcert -keystore server.jks -alias clientcert -file client-public.cer -storepass $srvpass -noprompt 

keytool -importcert -keystore client.jks -alias servercert -file server-public.cer -storepass $clipass -noprompt

5.Move the files from the temp directory, and then remove it:

mv temp/server.jks server/src/main/resources/
mv temp/client-public.cer server/src/main/resources/
mv temp/client.jks client/src/main/resources/
mv temp/server-public.cer client/src/main/resources/
rm -rf temp/

6.Update the key-password and trust-password properties in server/srv/main/resources/application.yml with the output of:

echo $srvpass

7.Update final static String kpass="s3cr3t"; in client/src/main/java/eu/immontilla/poc/sbtemplate/App.java file with the output of:

echo $clipass

8.Build

gradle build

9.Run the server

gradle :server:bootRun

9.Open a new terminal and run the client

gradle :client:bootRun

10.Finally, open your web browser at http://localhost:8088/

You will see something like this

with some random IT facts about Chuck Norris just like:

The class object inherits from Chuck Norris.
Chuck Norris can access private methods.

and many more (thanks to https://github.com/DiUS/java-faker)

As you might have noticed, the http client has called a https REST end-point successfully and no exception has been raised.

On the Internet I have found very dangerous but popular solutions to manage the javax.net.ssl.SSLHandshakeException. The most insane is to post code to disable the Java certificate validation process which is like letting your home door open to everybody because you want people you trust could get into when they need it.

To end up, let me invite you to no relay your code in the old-fashioned ways to solve the javax.net.ssl.SSLHandshakeException published on the Internet few years ago. If you are using modern tools like Spring Security and/or Spring Boot, check their documentation: Spring Security Reference and Spring Boot Common application properties specifically the embedded server configuration properties starting with server.ssl. Let's create new solutions to replace the old ones!