Does calling https service by Resttemplate work for all services whose certificate has been imported in the trustore of my client service? - spring-boot

I have a restemplate which can make call to multiple external systems over https.
I configured the resttemplate like so :
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(key, keyPassword)
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
client);
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
httpComponentsClientHttpRequestFactory.setReadTimeout(30000);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
I have setup 2 mock services on 2 separate VMs with ssl enabled and I am testing this restemplate by calling those services over https. And it works.
What I want to confirm is that configuring the restemplate as shown in the above code and importing the certificates of the different services to be called in by the client truststore should work without any additional configurations right?
I am confused because in the code in this example here : https://github.com/jonashackt/spring-boot-rest-clientcertificates-docker-compose the author has used 2 different factories i.e. serverTomClientHttpRequestFactory & serverAliceClientHttpRequestFactory, however mine works with a single restemplate. can someone please shed some light on this topic?

Related

Spring Gateway - multiple httpclients in Spring Gateway?

I have many filters that I use to manipulate different requests.
I'm overriding the default netty httpClient provided by Spring Gateway so I can set programatically some sslContext - mTLS in my case. This is fine, but I will also need to have a second netty httpClient so I can connect to other server with no ssl at all, or just regular tls.
I was wondering if it's possible either to set sslContext on specific filters or to decide what httpClient to use based on the filter or some other extension point that spring gateway provides.
Do you think it is possible to have multiple httpClients and decide which one to use?
I tried to create a new bean which configures a httpClient and set some sslContext like this:
#Bean
public reactor.netty.http.client.HttpClient httpClient() {
final PrivateKey privateKey = getPrivateKey();
final X509Certificate x509Certificate = getX509Certificate();
final SslContext sslContext =
SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.keyManager(privateKey, x509Certificate)
.build();
return reactor.netty.http.client.HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
}
While I use this httpClient to connect via mTLS it works fine, but I'd like to decide what httpClient to use based on specific filters.

How can I authenticate a Ribbon load balancer and Zuul proxy using a certificate?

I have a Spring application, that acts as an authentication proxy for two backend servers. A user will access the Spring application and be forwarded to the backend once he is successfully authenticated. To prevent unwanted access without prior authentication the backend servers require a certificate as authentication.
My Spring application uses Netflix-Ribbon as a load balancer and Netflix-Zuul as a Proxy for the users requests. How can I configure them to use the client certificate that is required for the authentication on the backend servers?
Ok, I figured it out. You can configure your own CloasableHttpClient as a #Bean and create a custom SSL context. You can provide a certificate to a server through .loadKeyMaterial(). Zuul will then use these settings.
#Configuration
public class HttpClientConfig {
#Bean
public CloseableHttpClient httpClient() throws Throwable {
String keyPassphrase = "yourCertificatePassword";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("Path/to/your/clientCert.pfx"), keyPassphrase.toCharArray());
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, keyPassphrase.toCharArray())
.build();
return HttpClients.custom()
.setSSLContext(sslContext)
.build();
}
}

Certificate Based authentication, client share certificate to server

I have a requirement from a server application to share a SSL certificate. step i did:
I generated a self signed certificate against the Domain IP address(don't have domain name) where my application is deployed.
i shared the certificate to the server. they will keep the certificate in their trust store.
server is validating the request for the IP address. if the request are not coming from the IP address they are stopping them.
My question:
i have a spring boot application. do i need to make any change in my code for the certificate i have generated. if yes then what is the change.
Yes you need to make changes in your code. You need to load your keystore(with keypair) and if required also load your truststore into your http client. Most of the http clients require a SSLContext, so this would be sufficient for you:
KeyStore keyStore = ...;
TrustStore trustStore = ...;
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
// Spring provides by default RestTemplate as HTTP Client, this client is an Apache HTTP Client wrapper
// The setup would be:
HttpClient httpClient = HttpClient.newBuilder();
.sslContext(sslFactory.getSslContext());
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory)

Spring RestTemplate call to HTTPS *without* HttpClient

Trying to make REST calls with RestTemplate using the server cert as the client cert to make calls with.
Don't ask me why :-), but I don't want to use Apache's HttpClient. I just think it's overkill.
I've seen code that uses regular JDK's SSLContext to set things up system-wide, i.e., set up SSLContext and the call SSLContext.setDefault(sslContext) as in this code:
// ... keymanagers, trustmanagers are omitted here
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keymanagers, trustmanagers, new SecureRandom());
SSLContext.setDefault(sslContext);
However, I saw a GitHub comment here (https://github.com/spring-projects/spring-boot/issues/6493) that states that setting SSLContext as default like that isn't really a good idea.
So, my question is: outside of having to use HttpClient, is there a way to use the sslContext configured in the code snippet above in RestTemplate setup somehow?
You can override the default requestFactory in the restTemplate by doing
restTemplate.setRequestFactory(new MyCustomRequestFactory());
Have a look at org.springframework.http.client.SkipSslVerificationHttpRequestFactory here for an example of setting SSLContext in your request factory.

How to trust ssl certificate programatically while using Spring Rest Client

I am using resttemplate from spring for consuming the Rest Json Webservice
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<Object> entity = new HttpEntity<Object>(glassRequest, headers);
postForObject = restTemplate.postForObject(url, entity, responseClass );
I am using above code for same. It works fine if there is no ssl certification at provider end. However , I get 403 if he uses certificate.
I know this can be handled by below two approches :-
1. Add certificate in trust store of application server.[But i am not running this code from application server but my junit test class]
2. Two add the certificate in java trust store. [However , i want to schedule this junit from enviroment where I don't have access ]
Is this can be done programmatically ?? Like i will include the certificates in my source code itself and then refer them by reading from classpath while making call to service.

Resources