5

I want to connect to a secure server endpoint. The service provider has provided me with a .p12 file and the password. I tried the API call on postman after adding the certificate under settings --> certificates--> client certificates and it was a success.

Now I want to integrate this to my java code. I am developing this application using Spring boot and I followed a couple of guides for this.I added the the .p12 file to my keystore using this command.

keytool -importkeystore -srckeystore uat_client.p12 -destkeystore store.keys -srcstoretype pkcs12 -alias myownkeyname 

But every time I get "No SSL Client Certificate Provided"which is the same response I got when I did not add the certificate in the postman.

I know this is not the ideal way to ask help since I do not have much code to show.And I am very new to this area of java. I am merely asking for some guide. If I have a .p12 file what are the steps I need to follow to connect to the service successfull.

public void someMethod()
{
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders httpHeaders = new HttpHeaders();

    String uri = "https://xx.net/api/v2/somemethod";

    httpHeaders.setContentType(MediaType.APPLICATION_JSON);

    String result = restTemplate.getForObject(uri, String.class);

    System.out.println("Result " + result);
}
  • https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-7D9F43B8-AABF-4C5B-93E6-3AFB18B66150 – erickson Aug 22 '22 at 15:33

2 Answers2

10

You must configure your RestTemplate to use the client certificate in an HTTPS connection as follows.

@Bean
public RestTemplate restTemplate() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
    KeyStore clientStore = KeyStore.getInstance("PKCS12");
    clientStore.load(new FileInputStream("certfile-path"), "certificate-password".toCharArray());
 
    SSLContext sslContext = SSLContextBuilder.create()
            .setProtocol("TLS")
            .loadKeyMaterial(clientStore, "certificate-password".toCharArray())
            .loadTrustMaterial(new TrustSelfSignedStrategy())
            .build();
 
    SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
    CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLSocketFactory(sslConnectionSocketFactory)
            .build();

    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(requestFactory);
}

and Inject restTemplate for using:

@Autowired
RestTemplate restTemplate;

public void someMethod() {
    HttpHeaders httpHeaders = new HttpHeaders();
    String uri = "https://xx.net/api/v2/somemethod";
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    String result = restTemplate.getForObject(uri, String.class);
    System.out.println("Result " + result);
}
fatih
  • 1,285
  • 11
  • 27
  • I wonder why you have to repeat the "certificate-password" twice and pass it to two different methods. – Stephane Aug 22 '22 at 12:12
  • 1
    While not exactly sure, the password you specify for `KeyStore` gives you access to the key store for you. However, the password you specify for `SSLContextBuilder.loadKeyMaterial` is for the management authority of a key store. – fatih Aug 22 '22 at 14:56
  • 1
    When loading `KeyStore`, the load method requires a password to verify the integrity of any trust entries the store contains. A password-based MAC is used to ensure that an attacker doesn't replace or add a bogus root certificate. This isn't very relevant for a key store that only contains the server's private key and certificate chain, but the API requires it. The second password (which can be different, at least for some `KeyStore` implementations) is required to decrypt the `PrivateKey` of a given entry. Apparently this builder API (incorrectly) assumes every entry has the same password. – erickson Aug 23 '22 at 15:09
0

Nothing works, simply throw this feign thing away and use rest template. It worked from the first attempt after spending an entire day on feigns bugs.

Imran
  • 1,732
  • 3
  • 21
  • 46