I have one requirement i.e. to bypass SSL verification while connecting to webservice using rest template.
Currently I am implementing proxy to rest template via below code.
SimpleClientHttpRequestFactory clientHttpRequestFactory = new
SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(proxyHost,
Integer.parseInt(proxyPort)));
clientHttpRequestFactory.setProxy(proxy);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
ResponseEntity<String> responseEntity= restTemplate.exchange(url,HttpMethod.POST,
entity,String.class);
response = responseEntity.getBody();
How can I modify my Rest template so while connecting to URL it doesn't look for SSL certificate Validation.
I do checked couple of solutions online for this but all are implemented with
HttpComponentsClientHttpRequestFactory
which don't have provision to pass proxy host and server (Java.net.proxy object).
Can anyone help me here, I am stuck from long on this.
Solution I found online is below
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
restTemplate = new RestTemplate(requestFactory);
Thanks,
Anshu
Related
I have a requirement to use springboot rest template which calls 3rd party and connects over 2-way ssl but it should go through the proxy, but I am getting "
Encountered connectivity issue while reaching APIsun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
" exception. This is very generic exception. Keystore and certificate are accessible. Without proxy I can able to call same 3rd party API with same set of certificates in different environement. So no issue with certs and location.
Looks like proxy is not able to forward/find certificates to server. Anyone knows how to solve this? following is the code for creating rest template.
HttpClientBuilder httpClientBuilder = null;
if(proxyEnabled){
httpClientBuilder = getHttpClientBuilderWithProxy();
} else{
httpClientBuilder = getHttpClientBuilderWithoutProxy();
}
CloseableHttpClient client = null;
if(isSslEnabled){
logger.info("SSL enabled for closable http client");
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory( new SSLContextBuilder()
.loadKeyMaterial( ResourceUtils.getFile(keyStore) , keyStorePassword.toCharArray(), keyStorePassword.toCharArray())
.loadTrustMaterial(ResourceUtils.getFile(trustStore), trustStorePassword.toCharArray()) .build());
client = httpClientBuilder
.setSSLSocketFactory(csf)
.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
.build();
} else{
logger.info("SSL disabled for closable http client");
client = httpClientBuilder
.build();
}
clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
private HttpClientBuilder getHttpClientBuilderWithoutProxy(){
return HttpClientBuilder.create()
.disableAutomaticRetries();
}
private HttpClientBuilder getHttpClientBuilderWithProxy(){
HttpHost proxy = new HttpHost(httpProxyHost, httpProxyPort);
return HttpClientBuilder.create()
.setProxy(proxy)
.disableAutomaticRetries();
}
I am expecting it to call 3rd party API with proxy and ssl.
my client side i have attached the certificate in the restTemplate code below . using this rest template i am calling other API(server side) . how to get the certificate in that server side
#Bean(name="custRest")
#Primary
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
char[] password = "changeit".toCharArray();
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = SSLContextBuilder
.create().loadKeyMaterial(new File("C:\\java\\java-certificate.der"),null,null)
.loadTrustMaterial(ResourceUtils.getFile("C:\\java\\java-certificate.der"), null,
acceptingTrustStrategy)
.build();
HttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
return builder.requestFactory(new HttpComponentsClientHttpRequestFactory(client))
.build();
}
You can find all step for configuring HTTPS for Spring Boot in article:
https://www.baeldung.com/spring-boot-https-self-signed-certificate
When I I am making outgoing requests with SSLConnectionSocketFactory request factory, only two parallel outgoing calls are getting response at a time. Subsequent calls reaches outside endpoint only when first two requests finish responding.
This is the RestTemplate config,
private RestTemplate createSSLRestTemplate(String keyStorePath, String keyStorePassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new ClassPathResource(keyStorePath).getInputStream(), 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).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
httpClient);
BufferingClientHttpRequestFactory bufferingRequestFactory = new BufferingClientHttpRequestFactory(requestFactory);
RestTemplate restTemplate = new RestTemplate(bufferingRequestFactory);
restTemplate.setInterceptors(Collections.singletonList(restTemplateLoggingInterceptor));
return restTemplate;
}
However if I replaced the RestTemplate with simple RestTeamplate all the calls goes to outside and responds in parallel.
public RestTemplate restTemplateDefault() {
return new RestTemplate();
}
Code that make the outgoing http request
HttpEntity<Req> request = new HttpEntity(req, this.prepareHttpHeaders());
return this.xmlUnmarshaller.unmarshall((String)this.restTemplate.postForObject(host, request, String.class, new Object[0]), responseClass);
How do I have sslcontext and have achieve parallelism?
I am trying to create one http client using useSystemProperties() as i need to default the ssl properties to that of WAS [like to get the WAS ciphers in runtime ]. And I have to set some max connections and connection manager also to the httpclient. This is a very high traffic rest call.
I have tried 3 ways,
-- This did not set the WAS ssl properties and thus the connection got failed.
httpclient = HttpClients.custom().useSystemProperties()
.setConnectionManager("some value")
.setMaxConnPerRoute("some value")
.setMaxConnTotal("some value")
.setUserAgent("Custom Browser")
.disableCookieManagement().build();
-- This did not set the WAS ssl properties and thus the connection failed.
httpclient1 = HttpClientBuilder.create().useSystemProperties()
.setConnectionManager(connManager)
.setMaxConnPerRoute(maxConnPerRoute)
.setMaxConnTotal(maxConnTotal)
.setUserAgent("Custom Browser")
.disableCookieManagement().build();
-- This one defaulted to WAS ssl configurations and connection was fine but other params are missing here.
httpclient2 = HttpClientBuilder.create().useSystemProperties().build();
Can I really achieve both these options?
You would need to override the SSLConnectionSocketFactory for your ConnectionManager, for example, on the example below will be created default SSLConnectionSocketFactory if you would use useSystemProperties
DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
(SSLSocketFactory) SSLSocketFactory.getDefault(), null, null, hostnameVerifier
);
final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build()
);
connManager.setDefaultMaxPerRoute(20);
connManager.setMaxTotal(20);
final HttpClientBuilder builder = HttpClientBuilder
.create()
.setConnectionManager(connManager);
You can also set useSystemProperties() as below to your HttpClient:
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.useSystemProperties()
.setDefaultRequestConfig(requestConfig).build();
i want to do a HTTP POST request, which is secured by ssl.
the client is my java program, which is posting to a https-url (https:// ...). the certificate of the website is verified, i am using Apache HttpClient 4.5.1
with a normal post-request and a custom httpclient.
HttpContext context = HttpClientContext.create();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);
cm.setMaxTotal(MAX_TOTAL_CONNECTIONS);
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(cm)
.build();
HttpContext context = HttpClientContext.create();
HttpPost login = new HttpPost("https://example.org"); // example url
login.addHeader("Content-Type", "application/json; charset=UTF-8");
login.addHeader("Accept", "application/json; charset=UTF-
login.setEntity(new StringEntity(loginData, ContentType.create("application/json", "UTF-8")));
JSONResponseHandler<JSONObject> rh = new JSONResponseHandler<>();
JSONObject test = client.execute(login, rh, context);
is this sufficend to get a ssl-secured connection or do i have to work with KeyStore, SSLContext and SSLConnectionFactory?
if i have to use those, how would i do this in an efficent way. i only saw examples how to allow self-signed certificates.