Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way to send a client certificate with every request made by the resttemplate in spring?

i want to consume a REST service with my spring application. To access that service i have a client certificate (self signed and in .jks format) for authorization. What is the proper way to authenticate against the rest service?

This is my request:

public List<Info> getInfo() throws RestClientException, URISyntaxException {

    HttpEntity<?> httpEntity = new HttpEntity<>(null, new HttpHeaders());

    ResponseEntity<Info[]> resp = restOperations.exchange(
            new URI(BASE_URL + "/Info"), HttpMethod.GET, 
            httpEntity, Info[].class);
    return Arrays.asList(resp.getBody());
}
like image 919
Nas3nmann Avatar asked Aug 16 '17 12:08

Nas3nmann


People also ask

How are client certificates sent?

A server certificate is sent from the server to the client at the start of a session and is used by the client to authenticate the server. A client certificate, on the other hand, is sent from the client to the server at the start of a session and is used by the server to authenticate the client.

How is certificate based authentication implemented in Java?

Client Java Implementation First, we create an SSLSocket that establishes a connection with the server. In the background, the socket will set up the TLS connection establishment handshake. As part of this handshake, the client will verify the server's certificate and check that it's in the client truststore.

How do I send client certificates from Chrome?

Chrome: Backing Up (Exporting) Your Client CertificateIn Chrome, go to Settings. On the Settings page, below Default browser, click Show advanced settings. Under HTTPS/SSL, click Manage certificates. In the Certificates window, on the Personal tab, select your Client Certificate and click Export.


1 Answers

Here is example how to do this using RestTemplate and Apache HttpClient

You should define your own RestTemplate with configured SSL context:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
    char[] password = "password".toCharArray();

    SSLContext sslContext = SSLContextBuilder.create()
            .loadKeyMaterial(keyStore("classpath:cert.jks", password), password)
            .loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();

    HttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
    return builder
            .requestFactory(new HttpComponentsClientHttpRequestFactory(client))
            .build();
}

 private KeyStore keyStore(String file, char[] password) throws Exception {
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    File key = ResourceUtils.getFile(file);
    try (InputStream in = new FileInputStream(key)) {
        keyStore.load(in, password);
    }
    return keyStore;
}

Now all remote calls performed by this template will be signed with cert.jks. Note: You would need to put cert.jks into your classpath

@Autowired
private RestTemplate restTemplate;

public List<Info> getInfo() throws RestClientException, URISyntaxException {
    HttpEntity<?> httpEntity = new HttpEntity<>(null, new HttpHeaders());

    ResponseEntity<Info[]> resp = restTemplate.exchange(
            new URI(BASE_URL + "/Info"), HttpMethod.GET, 
            httpEntity, Info[].class);
    return Arrays.asList(resp.getBody());
}
like image 91
Ruslan Poshuk Avatar answered Oct 03 '22 21:10

Ruslan Poshuk