Skip to content

Commit 904e36b

Browse files
committed
Project basic Maven setup and working server-alice and server-tom.
1 parent 3be1cbf commit 904e36b

File tree

33 files changed

+804
-0
lines changed

33 files changed

+804
-0
lines changed

.gitignore

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
*.class
2+
*.springBeans
3+
4+
# Package Files #
5+
*.jar
6+
*.war
7+
*.ear
8+
9+
# Eclipse #
10+
.settings
11+
.project
12+
.classpath
13+
.studio
14+
target
15+
16+
# Apple #
17+
.DS_Store
18+
19+
# Intellij #
20+
.idea
21+
*.iml
22+
*.log
23+
24+
# logback
25+
logback.out.xml
26+
27+
# certificate stuff
28+
*.key
29+
*.csr
30+
*.crt
31+
*.p12

.travis.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
language: java
2+
jdk:
3+
- oraclejdk8
4+
5+
script: mvn clean install

README.md

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
REST Client uses clientcertificate to authenticate to Spring Boot Server
2+
=============================
3+
[![Build Status](https://travis-ci.org/jonashackt/spring-boot-rest-clientcertificate.svg?branch=master)](https://travis-ci.org/jonashackt/spring-boot-rest-clientcertificate)
4+
5+
This repository basically forks all the ground work that was done in https://github.com/jonashackt/spring-boot-rest-clientcertificate. This is a basic example, where the client certificate secured server is a Spring Boot Application and the client is just a Testcase that uses Spring´s RestTemplate which is configured to use the client certificate.
6+
7+
In contrast the present project focusses on the configuration of more than one client certificates and how to access REST endpoints from multiple servers that are secured by different client certificates with Spring´s RestTemplate.
8+
9+
Therefore we use several Spring Boot based microservices that provide different client certificate secured REST endpoint and a separate microservice that accesses these services:
10+
11+
```
12+
================
13+
= =
14+
= server-alice =
15+
============== = =
16+
= = ------------------> ================
17+
= client-bob =
18+
= = ------------------> ================
19+
============== = =
20+
= server-tom =
21+
= =
22+
================
23+
```
24+
25+
26+
For a general approach on how to generate private keys and certificates and create Java Keystores, have a look into https://github.com/jonashackt/spring-boot-rest-clientcertificate#generate-the-usual-key-and-crt---and-import-them-into-needed-keystore-jks-files
27+
28+
## server-alice client certificate & truststore (see /server-alice/src/main/resources)
29+
30+
#### 1. Private Key: aliceprivate.key
31+
32+
```
33+
openssl genrsa -des3 -out aliceprivate.key 128
34+
```
35+
36+
- passphrase `alicepassword`
37+
38+
39+
#### 2. Certificate Signing Request (CSR): alice.csr
40+
41+
```
42+
openssl req -new -key aliceprivate.key -out alice.csr
43+
```
44+
45+
__Common Name__: `server-alice`, which will later be a DNS alias inside the Docker network
46+
47+
48+
#### 3. self-signed Certificate: alice.crt
49+
50+
```
51+
openssl x509 -req -days 3650 -in alice.csr -signkey aliceprivate.key -out alice.crt
52+
```
53+
54+
55+
#### 4. Java Truststore Keystore, that inherits the generated self-signed Certificate: alice-truststore.jks
56+
57+
```
58+
keytool -import -file alice.crt -alias alicesCA -keystore alice-truststore.jks
59+
```
60+
61+
__the same password__ `alicepassword`
62+
63+
64+
#### 5. Java Keystore, that inherits Public and Private Keys (keypair): alice-keystore.jks
65+
66+
```
67+
openssl pkcs12 -export -in alice.crt -inkey aliceprivate.key -certfile alice.crt -name "alicecert" -out alice-keystore.p12
68+
```
69+
70+
__the same password__ `alicepassword`
71+
72+
73+
74+
## server-tom client certificate & truststore (see /server-tom/src/main/resources)
75+
76+
#### 1. Private Key: tomprivate.key
77+
78+
```
79+
openssl genrsa -des3 -out tomprivate.key 1024
80+
```
81+
82+
- passphrase `tompassword`
83+
84+
85+
#### 2. Certificate Signing Request (CSR): tom.csr
86+
87+
```
88+
openssl req -new -key tomprivate.key -out tom.csr
89+
```
90+
91+
__Common Name__: `server-tom`, which will later be a DNS alias inside the Docker network
92+
93+
94+
#### 3. self-signed Certificate: tom.crt
95+
96+
```
97+
openssl x509 -req -days 3650 -in tom.csr -signkey tomprivate.key -out tom.crt
98+
```
99+
100+
101+
#### 4. Java Truststore Keystore, that inherits the generated self-signed Certificate: tom-truststore.jks
102+
103+
```
104+
keytool -import -file tom.crt -alias tomsCA -keystore tom-truststore.jks
105+
```
106+
107+
__the same password__ `tompassword`
108+
109+
110+
#### #### 5. Java Keystore, that inherits Public and Private Keys (keypair): tom-keystore.p12
111+
112+
```
113+
openssl pkcs12 -export -in tom.crt -inkey tomprivate.key -certfile tom.crt -name "tomcert" -out tom-keystore.p12
114+
```
115+
116+
__the same password__ `tompassword`
117+
118+
119+
120+
## client-bob truststore & keystore (see /server-alice/src/main/resources)
121+
122+
#### 1. Java Truststore Keystore, that inherits the generated self-signed Certificate: client-truststore.jks
123+
124+
```
125+
keytool -import -file alice.crt -alias alicesCA -keystore client-truststore.jks
126+
keytool -import -file tom.crt -alias tomsCA -keystore client-truststore.jks
127+
```
128+
129+
__password__ `bobpassword`
130+
131+
132+
#### 2. Java Keystore, that inherits Public and Private Keys (keypair): server-tom-keystore.p12
133+
134+
```
135+
openssl pkcs12 -export -in tom.crt -inkey tomprivate.key -certfile tom.crt -name "tomcert" -out server-tom-keystore.p12
136+
```
137+
138+
__the same password__ `tompassword`
139+

client-bob/pom.xml

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>de.jonashackt</groupId>
7+
<artifactId>client-bob</artifactId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
<packaging>jar</packaging>
10+
11+
<parent>
12+
<groupId>de.jonashackt</groupId>
13+
<artifactId>spring-boot-rest-clientcertificates-docker-compose</artifactId>
14+
<version>0.0.1-SNAPSHOT</version>
15+
</parent>
16+
17+
<properties>
18+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19+
<java.version>1.8</java.version>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>org.springframework.boot</groupId>
25+
<artifactId>spring-boot-starter-web</artifactId>
26+
</dependency>
27+
28+
<!-- we need this here for server certificate handling -->
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-security</artifactId>
32+
</dependency>
33+
34+
<!-- we need httpclient here for client certificate handling -->
35+
<dependency>
36+
<groupId>org.apache.httpcomponents</groupId>
37+
<artifactId>httpclient</artifactId>
38+
</dependency>
39+
40+
<!-- Testing -->
41+
<dependency>
42+
<groupId>org.springframework.boot</groupId>
43+
<artifactId>spring-boot-starter-test</artifactId>
44+
<scope>test</scope>
45+
</dependency>
46+
47+
</dependencies>
48+
49+
<build>
50+
<plugins>
51+
<plugin>
52+
<groupId>org.springframework.boot</groupId>
53+
<artifactId>spring-boot-maven-plugin</artifactId>
54+
</plugin>
55+
</plugins>
56+
</build>
57+
58+
59+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package de.jonashackt.restexamples;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.PropertySource;
6+
7+
@SpringBootApplication
8+
public class ServerApplication {
9+
10+
public static void main(String[] args) {
11+
SpringApplication.run(ServerApplication.class, args);
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package de.jonashackt.restexamples.configuration;
2+
3+
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
5+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
7+
8+
@Configuration
9+
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
10+
11+
/*
12+
* Enable x509 client authentication.
13+
*/
14+
@Override
15+
protected void configure(HttpSecurity http) throws Exception {
16+
http.x509();
17+
}
18+
19+
/*
20+
* Create an in-memory authentication manager. We create 1 user (localhost which
21+
* is the CN of the client certificate) which has a role of USER.
22+
*/
23+
@Override
24+
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
25+
auth.inMemoryAuthentication()
26+
.withUser("localhost")
27+
.password("none")
28+
.roles("USER");
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package de.jonashackt.restexamples.controller;
2+
3+
import org.springframework.web.bind.annotation.RequestMapping;
4+
import org.springframework.web.bind.annotation.RequestMethod;
5+
import org.springframework.web.bind.annotation.RestController;
6+
7+
@RestController
8+
@RequestMapping("/restexamples")
9+
public class ServerController {
10+
11+
public static final String RESPONSE = "Hello Rest-User!";
12+
13+
@RequestMapping(path="/hello", method=RequestMethod.GET)
14+
public String helloWorld() {
15+
System.out.println("Rocking REST!");
16+
return RESPONSE;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
server:
2+
port: 8443
3+
ssl:
4+
key-store: classpath:keystore.jks
5+
key-store-password: allpassword
6+
trust-store: classpath:truststore.jks
7+
trust-store-password: allpassword
8+
client-auth: need
9+
security:
10+
headers:
11+
hsts: NONE
1.42 KB
Binary file not shown.
741 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package de.jonashackt.restexamples;
2+
3+
import de.jonashackt.restexamples.controller.ServerController;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.boot.context.embedded.LocalServerPort;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.springframework.test.context.junit4.SpringRunner;
10+
import org.springframework.web.client.RestTemplate;
11+
12+
import static org.junit.Assert.assertEquals;
13+
14+
@RunWith(SpringRunner.class)
15+
@SpringBootTest(
16+
classes = ServerApplication.class,
17+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
18+
)
19+
public class RestClientCertTest {
20+
21+
@LocalServerPort
22+
private int port;
23+
24+
@Autowired
25+
private RestTemplate restTemplate;
26+
27+
@Test
28+
public void is_hello_resource_callable_with_client_cert() {
29+
String response = restTemplate.getForObject("https://localhost:" + port + "/restexamples/hello", String.class);
30+
31+
assertEquals(ServerController.RESPONSE, response);
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package de.jonashackt.restexamples;
2+
3+
import org.apache.http.client.HttpClient;
4+
import org.apache.http.impl.client.HttpClients;
5+
import org.apache.http.ssl.SSLContextBuilder;
6+
import org.springframework.boot.web.client.RestTemplateBuilder;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
10+
import org.springframework.util.ResourceUtils;
11+
import org.springframework.web.client.RestTemplate;
12+
13+
import javax.net.ssl.SSLContext;
14+
15+
@Configuration
16+
public class RestClientCertTestConfiguration {
17+
18+
private char[] allPassword = "allpassword".toCharArray();
19+
20+
@Bean
21+
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
22+
23+
SSLContext sslContext = SSLContextBuilder
24+
.create()
25+
.loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword, allPassword)
26+
.loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword)
27+
.build();
28+
29+
HttpClient client = HttpClients.custom()
30+
.setSSLContext(sslContext)
31+
.build();
32+
33+
return builder
34+
.requestFactory(new HttpComponentsClientHttpRequestFactory(client))
35+
.build();
36+
}
37+
}
1.42 KB
Binary file not shown.
741 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)