We will see how to call an application which is HTTPS enabled using Spring Boot
RestTemplate in a client application.
Prerequisites:
1) Maven
2) Java 1.8+
We need a sample HTTPS server application which we need to call from a client
application.
1) Create a 'Sample Server' Spring Boot application
Use https://start.spring.io/ to create a sample server application.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>info.code2learn.springboot</groupId>
<artifactId>sample-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Sample Server</name>
<description>Spring boot sample server application</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
SampleServerApplication.java
package info.code2learn.springboot.sampleserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleServerApplication {
public static void main(String[] args) {
SpringApplication.run(SampleServerApplication.class, args);
}
}
SampleServerController.java
package info.code2learn.springboot.sampleserver.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sampleserver")
public class SampleServerController {
@GetMapping("/message")
public ResponseEntity<String> message() {
return new ResponseEntity<>("Message from https server.", HttpStatus.OK);
}
}
Generate Key Store of type PKCS12 using below command. This is required for
making the application as HTTPS/SSL enabled.
$ keytool -genkey -alias sampleserver -keyalg RSA -keystore sampleserver.keystore -validity 3650 -storetype PKCS12 -dname "CN=localhost, OU=Spring, O=Pivotal, L=Holualoa, ST=HI, C=US" -keypass changeit -storepass changeit
application.yml
server:
port: 8443
ssl:
enabled: true
key-alias: sampleserver
key-password: changeit
key-store: classpath:sampleserver.keystore
key-store-password: changeit
key-store-type: PKCS12
2) Create a 'Sample Client' Spring Boot application
Use https://start.spring.io/ to create a sample client application.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.6</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>info.code2learn.springboot</groupId>
<artifactId>sample-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Sample Client</name>
<description>Spring boot sample client application</description>
<repositories>
<repository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
SampleClientApplication.java
package info.code2learn.springboot.sampleclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleClientApplication {
public static void main(String[] args) {
SpringApplication.run(SampleClientApplication.class, args);
}
}
SampleClientConfig.java
package info.code2learn.springboot.sampleclient.config;
import java.io.InputStream;
import java.security.KeyStore;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class SampleClientConfig {
@Value("${app.key-store-type}")
private String keyStoreType;
@Value("${app.key-store-password}")
private String keyStorePassword;
@Value("${app.key-store}")
private String keyStoreFile;
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
KeyStore keyStore;
HttpComponentsClientHttpRequestFactory requestFactory = null;
try {
keyStore = KeyStore.getInstance(keyStoreType);
ClassPathResource classPathResource = new ClassPathResource(keyStoreFile);
InputStream inputStream = classPathResource.getInputStream();
keyStore.load(inputStream, keyStorePassword.toCharArray());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(new SSLContextBuilder()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, keyStorePassword.toCharArray()).build(),
NoopHostnameVerifier.INSTANCE);
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory)
.setMaxConnTotal(Integer.valueOf(5))
.setMaxConnPerRoute(Integer.valueOf(5))
.build();
requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
requestFactory.setReadTimeout(Integer.valueOf(10000));
requestFactory.setConnectTimeout(Integer.valueOf(10000));
restTemplate.setRequestFactory(requestFactory);
} catch (Exception exception) {
System.out.println("Exception Occured while creating restTemplate "+exception);
exception.printStackTrace();
}
return restTemplate;
}
}
SampleClientController.java
package info.code2learn.springboot.sampleclient.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/sampleclient")
public class SampleClientController {
@Autowired
private RestTemplate restTemplate;
@Value("${sampleserver.url}")
private String sampleServerUrl;
@GetMapping("/welcome")
public ResponseEntity<String> welcome() {
ResponseEntity<String> responseEntity = restTemplate.getForEntity(sampleServerUrl + "/sampleserver/message", String.class);
return new ResponseEntity<>(responseEntity.getBody(), HttpStatus.OK);
}
}
application.yml
server:
port: 9090
sampleserver:
url: https://localhost:8443/
app:
key-alias: sampleserver
key-password: changeit
key-store: sampleclient.truststore
key-store-password: changeit
key-store-type: JKS
Run Sample Server application and Import Server application certificate into
client application truststore
Click certificate icon next to the sample server application URL on browser.
Click Details
Select DER format and save as
sampleserver.cer and save it in client
application resources folder.
Run the below command to import above exported sample server certificate into
sample client application trust store.
$ keytool -importcert -keystore sampleclient.truststore -alias sampleserver
-storepass changeit -file sampleserver.cer -noprompt
Start the Sample Client application and access the endpoint at
http://localhost:9090/sampleclient/welcome