Reaching a HTTPS Rest api using Spring RestTemplate by-passing host verification - spring

I've read many things about this problem, and I thought I had found the most simple workaround (last code example from here : http://www.baeldung.com/httpclient-ssl), but it doesn't work.
Here is how I declare my RestTemplate with hostname verification turned off (and a proxy setting) :
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setProxy(new HttpHost("10.xx.xx.xx", 3128, "http"))
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return builder.requestFactory(requestFactory).build();
//return builder.build();
}
And here is the code to create my POST request :
LoginResponse loginResponse = restTemplate.postForObject("https://interflex.svc.suezsmartsolutions.com/path/to/my/api", loginRequest, LoginResponse.class);
And here is the exception I get (just like if I had not turned off hostname verifier) :
16:15:27 ERROR org.springframework.boot.SpringApplication:771 - Application startup failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:735)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716)
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:304)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
at hello.Application.main(Application.java:23)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://interflex.svc.suezsmartsolutions.com/path/to/api": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:673)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:387)
at hello.Application.lambda$0(Application.java:45)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732)
... 6 common frames omitted
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.upgrade(DefaultHttpClientConnectionOperator.java:193)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.upgrade(PoolingHttpClientConnectionManager.java:375)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:416)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:89)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:659)
... 10 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
... 32 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 38 common frames omitted
Could someone help me get rid of this exception ?
Also I don't know why this exception appears in the first place, since the root CA used to generate the site certificate (VeriSign) is present in my truststore (cacerts) (the intermediate authority is not present though, could it be the reason ?).

Simple Fix, just skip the certificate
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, acceptingTrustStrategy).build();

Your issue seems more related to a certificate issue than to proxy configuration.
Anyway in my projects I'm using this configuration:
#Bean
#Autowired
public RestTemplate restTemplate(ClientHttpRequestFactory factory)
{
RestTemplate result = new RestTemplate(factory);
return result;
}
#Bean
public ClientHttpRequestFactory requestFactory() throws Exception
{
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient());
return factory;
}
#Bean
public HttpClient httpClient() throws Exception
{
int timeout = new Integer(env.getProperty("web.http.client.timeout"));
CloseableHttpClient httpClient = null;
//I load a JSON where I specify the name and the PWD of keystores I want to use
String keystores = "keyStoreInfo.json";
PoolingHttpClientConnectionManager pcm = null;
if(StringUtils.hasText(keystores))
{
Resource jsonRes = new ClassPathResource(keystores);
if( jsonRes.exists() )
{
List<KeyStoreInfo> ksInfo = objectMapper().readValue(jsonRes.getInputStream(), new TypeReference<List<KeyStoreInfo>>()
{
});
SSLContext sslCtx = SSLContext.getInstance("TLS");
List<KeyManager> keymanagers = new ArrayList<KeyManager>();
for (KeyStoreInfo ksi : ksInfo)
{
String keystoreName = ksi.getNomeKeyStore();
String keyStorePwd = ksi.getPasswordKeyStore();
if( StringUtils.hasText(keystoreName) )
{
Resource keystoreRes = new ClassPathResource(keystoreName);
KeyMaterial km = new KeyMaterial(keystoreRes.getInputStream(), keyStorePwd.toCharArray());
KeyStore clientStore = km.getKeyStore();
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(clientStore, keyStorePwd != null ? keyStorePwd.toCharArray() : null);
keymanagers.addAll(Arrays.asList(kmfactory.getKeyManagers()));
}
}
if( !keymanagers.isEmpty() )
{
X509TrustManager tm = new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslCtx.init(keymanagers.toArray(new KeyManager[keymanagers.size()]), new TrustManager[]{tm}, null);
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslCtx);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionFactory).register("http", new PlainConnectionSocketFactory()).build();
pcm = new PoolingHttpClientConnectionManager(registry);
}
else
{
if( logger.isInfoEnabled() )
{
logger.info("Nessun keystore presente nel JSON di configurazione {}. Creo un PoolingHttpClientConnectionManager di default",keystores);
}
pcm = new PoolingHttpClientConnectionManager();
}
}
}
else
{
if( logger.isInfoEnabled() )
{
logger.info("Nessun keystore da caricare. Creo un PoolingHttpClientConnectionManager di default");
}
pcm = new PoolingHttpClientConnectionManager();
}
HttpClientBuilder hcb = HttpClientBuilder.create();
pcm.closeIdleConnections(timeout, TimeUnit.MILLISECONDS);
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).setConnectTimeout(timeout).build();
hcb.setDefaultRequestConfig(config);
hcb.setConnectionManager(pcm).setConnectionManagerShared(true);
boolean proxyEnable = new Boolean(env.getProperty("web.http.client.proxyEnable"));
if (proxyEnable)
{
int proxyPort = new Integer(env.getProperty("web.http.client.portProxy"));
String proxyHost = env.getProperty("web.http.client.hostProxy");
BasicCredentialsProvider credentialProvider = new BasicCredentialsProvider();
AuthScope scope = new AuthScope(proxyHost, proxyPort);
String usernameProxy = env.getProperty("web.http.client.usernameProxy");
String passwordProxy = env.getProperty("web.http.client.passwordProxy");
if (StringUtils.hasText(usernameProxy) && StringUtils.hasText(passwordProxy))
{
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(usernameProxy, passwordProxy);
credentialProvider.setCredentials(scope, credentials);
}
ProxyRoutePlanner proxyRoutPlanner = new ProxyRoutePlanner(new HttpHost(proxyHost, proxyPort), env.getProperty("web.http.client.urlNotProxy"));
hcb.setDefaultCredentialsProvider(credentialProvider).setRoutePlanner(proxyRoutPlanner);
}
WsKeepAliveStrategy cas = new WsKeepAliveStrategy();
cas.setTimeout(new Long(timeout));
hcb.setKeepAliveStrategy(cas);
httpClient = hcb.build();
return httpClient;
}
Where WsKeepAliveStrategy is:
public class WsKeepAliveStrategy implements ConnectionKeepAliveStrategy
{
private Long timeout;
#Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context)
{
return timeout;
}
public void setTimeout(Long timeout)
{
this.timeout = timeout;
}
}
and ProxyRoutePlanner is:
public class ProxyRoutePlanner extends DefaultProxyRoutePlanner
{
private List<String> urlsNotProxy = null;
private boolean useAlwaysSuper = false;
public ProxyRoutePlanner(HttpHost proxy, String urlNotProxy)
{
super(proxy);
if (!StringUtils.hasText(urlNotProxy))
this.useAlwaysSuper = true;
else
{
this.urlsNotProxy = Arrays.asList(urlNotProxy.split(","));
}
}
#Override
public HttpRoute determineRoute(HttpHost host, HttpRequest request, HttpContext context) throws HttpException
{
String hostname = host.getHostName();
if (this.useAlwaysSuper || this.urlsNotProxy.contains(hostname) == false)
return super.determineRoute(host, request, context);// Super method
// with proxy
if ("http".equals(host.getSchemeName()))
return new HttpRoute(host);// Direct Route
HttpClientContext clientContext = HttpClientContext.adapt(context);
RequestConfig config = clientContext.getRequestConfig();
InetAddress local = config.getLocalAddress();
return new HttpRoute(host, local, true);
}
}
I'm using this configuration and I'm having no issue
In any case you should check what kind of certificate is necessary to use in your rest invocation
I hope it's useful
Angelo

The short answer is "yes you need the intermediate authority in your truststore, not only the root CA".

Related

Micrometer with Elasticsearch over SSL

I'm trying to use Micrometer with Elasticsearch over SSL.
I use Micrometer in version 1.8.0, Elasticsearch in version 7.16.3 and OpenJDK 11.0.2 .
Because I know that it's not possible to use a built-in configuration (link) I tried to inject a custom HttpUrlConnectionSender as in the following class SecureHttpSender:
public class SecureHttpSender extends HttpUrlConnectionSender {
...
public SecureHttpSender(ElasticProperties properties, SecureElasticProperties secureElasticProperties) {
super(properties.getConnectTimeout(), properties.getReadTimeout());
this.secureElasticProperties = secureElasticProperties;
this.sslSocketFactory = buildSslSocketFactory();
}
#Override
public Response send(Request request) throws IOException {
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) request.getUrl().openConnection();
// if the connection is an instance of the HttpsURLConnection class, the ssl configuration will always been applied.
if (httpURLConnection instanceof HttpsURLConnection) {
// - hostname verifier
if (!secureElasticProperties.isVerifyHostname()) {
logger.debug("setting the hostname verifier to: {}", NoopHostnameVerifier.INSTANCE);
((HttpsURLConnection) httpURLConnection).setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
}
// - trust store configuration
((HttpsURLConnection) httpURLConnection).setSSLSocketFactory(sslSocketFactory);
}
return super.send(request);
} finally {
try {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception ignore) {
}
}
}
private SSLSocketFactory buildSslSocketFactory() {
SSLSocketFactory sslSocketFactory;
try (InputStream is = getInputStream(secureElasticProperties.getTrustStorePath())) {
KeyStore truststore = KeyStore.getInstance(secureElasticProperties.getTrustStoreType());
truststore.load(is, secureElasticProperties.getTrustStorePassword().toCharArray());
SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
final SSLContext sslContext = sslBuilder.build();
sslSocketFactory = sslContext.getSocketFactory();
} catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
String message = String.format("error while loading the security configuration from: %s", secureElasticProperties);
logger.error(message, e);
throw new RuntimeException("management.metrics.export.elastic.ssl");
}
return sslSocketFactory;
}
private InputStream getInputStream(String trustStorePathString) throws IOException {
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource resource = pathMatchingResourcePatternResolver.getResource(trustStorePathString);
return resource.getInputStream();
}
}
that I injected with Spring Boot so I can apply the desired configuration, but I got the following error:
ERROR 10912 --- [trics-publisher] i.m.elastic.ElasticMeterRegistry : failed to send metrics to elastic
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
The server certificate and the client truststore are valid because I already used them with success.
I also tried to force a specific version of the TLS protocol during the handshake phase: TLSv1.3 and TLSv1.2 but the error still occurs.
Anyone have any suggestions on how to fix it? thanks
Check what super.send does, it creates a new connection without using the one you created. I'm not recommending using a self-signed cert and a custom truststore but you can set a default HostnameVerifier using
HttpsURLConnection.setDefaultHostnameVerifier.
Since this is static, it will work for all HttpsURLConnection instances so you don't need to inject anything into Micrometer.
The right solution would be either using a non-self-signed cert or a proper truststore (e.g.: via javax.net.ssl.trustStore).
I did a test with a simple change to the code I had posted and I solved it:
I copied all code of the super.send() method, adding the additional code to set the custom SslSocketFactory and all was OK!
so the reason was that
it creates a new connection without using the one you created
as Jonatan said... a my trivial mistake. :)

Websphere - Spring Integration SSL issue

Our Spring Integration application runs on Websphere. It is a client to an SSL external service.
I've imported a certificate using Retrive from port [into default trust store], giving host and 443 port. Enabled tracing on WebSphere and it seems it is looking at cacert file and not trust.p12.
[18-2-19 13:44:59:154 CET] 00000063 SystemOut O 2019-02-18 13:44:59.153 INFO 30426 --- [ver.startup : 0] pertySourcedRequestMappingHandlerMapping : Mapped URL path [/v2/api-docs] onto method [public org.springframework.http.ResponseEntity<springfox.documentation.spring.web.json.Json> springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest)]
[18-2-19 13:44:59:826 CET] 00000063 SystemOut O keyStore is: /srv/opt/IBM/WebSphere/AppServer/java/8.0/jre/lib/security/cacerts
Code:
public class PreemptiveMessageSender extends HttpComponentsMessageSender {
#Autowired
private Environment env;
private String host;
private String userId;
private String password;
public PreemptiveMessageSender() {
super();
}
public PreemptiveMessageSender(HttpClient httpClient) {
super(httpClient);
}
#Override
protected HttpContext createContext(URI uri) {
HttpHost targetHost = new HttpHost(host, 443, "https");
String decryptedPassword = getDecryptedPassword();
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(userId, decryptedPassword));
AuthCache authCache = new BasicAuthCache();
authCache.put(targetHost, new BasicScheme());
// Add AuthCache to the execution context
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);
return context;
}
private String getDecryptedPassword() {
BasicTextEncryptor textEncrypt = new BasicTextEncryptor();
textEncrypt.setPassword(env.getProperty("KEY_PASSWORD"));
return textEncrypt.decrypt(password);
}
#Override
public WebServiceConnection createConnection(URI uri) throws IOException {
HttpPost httpPost = new HttpPost(uri);
if (isAcceptGzipEncoding()) {
httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING,
HttpTransportConstants.CONTENT_ENCODING_GZIP);
}
HttpContext httpContext = createContext(uri);
return new CustomHttpComponentsConnection(getHttpClient(), httpPost, httpContext);
}
...
}
Error:
"exception": "org.springframework.ws.client.WebServiceIOException",
"message": "I/O error: com.ibm.jsse2.util.h: PKIX path building failed: java.security.cert.CertPathBuilderException:
PKIXCertPathBuilderImpl could not build a valid CertPath.; internal
cause is: \n\tjava.security.cert.CertPathValidatorException: The
certificate issued by CN=ODC Test Root CA - G1, O=ODC Test, C=TU is
not trusted; internal cause is:
\n\tjava.security.cert.CertPathValidatorException: Certificate
chaining error; nested exception is
javax.net.ssl.SSLHandshakeException: com.ibm.jsse2.util.h: PKIX path
building failed: java.security.cert.CertPathBuilderException:
PKIXCertPathBuilderImpl could not build a valid CertPath.; internal
cause is: \n\tjava.security.cert.CertPathValidatorException: The
certificate issued by CN=ODC Test Root CA - G1, O=ODC Test, C=TU is
not trusted; internal cause is:
\n\tjava.security.cert.CertPathValidatorException: Certificate
chaining error",
Question:
Is this problem with Spring Integration using the java cacert? How to make it use the trust store of WebSphere?
I'll start with I don't know anything about Spring. But given the behavior you talk about it must be creating its own instance of the SSLContext. This will cause it to by pass WebSphere SSL settings. It must be doing something like SSLContext.getInstance() to create its own instance or it could be doing something like SSLContext.getDefault() which returns you the JDK's default SSLContext. Both will not get you a WebSphere SSLContext.
https://developer.ibm.com/answers/questions/394270/im-using-an-apache-httpclient-to-make-an-outbound/
HttpClient theClient =
HttpClientBuilder.create().useSystemProperties().addInterceptorFirst(new
RemoveSoapHeadersInterceptor()).build();
private static class RemoveSoapHeadersInterceptor implements HttpRequestInterceptor {
#Override
public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
if (request instanceof HttpEntityEnclosingRequest) {
if (request.containsHeader(HTTP.TRANSFER_ENCODING)) {
request.removeHeaders(HTTP.TRANSFER_ENCODING);
}
if (request.containsHeader(HTTP.CONTENT_LEN)) {
request.removeHeaders(HTTP.CONTENT_LEN);
}
}
}
}

ssl certificate issue in spring mvc

I am implementing a code that generate an error I don't understand. I'm googling since three days ago unsuccessfully. Find below my code :
Main class
package com.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class Test {
public static void main(String[] args) throws IOException {
URL url = new URL("https://qosic.net:8443/QosicBridge/user/deposit");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
String json = "{\"msisdn\": \"22967307747\",\"amount\": 2000,\"transref\": 56789,\"clientid\": QOS3P001}";
OutputStream os = connection.getOutputStream();
os.write(json.getBytes());
os.flush();
if(connection.getResponseCode() != 200){
throw new RuntimeException("Failed : Http Error code "+connection.getResponseCode());
}
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String output;
System.out.println("Output from server....\n");
while((output = reader.readLine()) != null){
System.out.println(output);
}
}
}
Error
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
... 13 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:146)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 19 more
If someone could help understanding what I did wrong, I will be very grateful
Thanks,
unable to find valid certification path to requested target
You need to provide a keystore with a valid certificate for the host (in this case qosic.net) you are trying to connect to via https (ssl).
You can initialise your own SSL Context, see here for examples.
Or you can ignore all certificates (WHICH IS A HACK, NOT FOR PRODUCTION) with this code
#Test
public void test1() throws Exception {
CloseableHttpClient defaultHttpClient = HttpClients.createDefault();
String uri = "https://localhost/healthcheck";
try {
defaultHttpClient.execute(new HttpGet(uri));
fail();
} catch (SSLHandshakeException e) {
// do nothing
}
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build());
CloseableHttpClient customHttpClient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
CloseableHttpResponse response = customHttpClient.execute(new HttpGet(uri));
assertEquals(200, response.getStatusLine().getStatusCode());
}

Embedded ElasticSearch can't connect to transport port in integration test

I'm trying to create an embedded ElasticSearch node for integration testing.
Here is the code creation
private static final String THREAD_NAME = "ES-THREAD";
private static final String CLUSTER_NAME = "ES-INTEGRATION-TEST";
private static final String ES_HOME_PATH = "elastic-search-home";
private static final String ES_DATA_PATH = "elastic-search-data";
private static final String DATA_PORTS = "9500-9599";
private static final String TRANSPORT_PORTS = "9600-9699";
public void before() throws Throwable {
try {
homeDir = Files.createTempDirectory(ES_HOME_PATH);
dataDir = Files.createTempDirectory(ES_DATA_PATH);
log.info("Created temp directory {} and {}", homeDir, dataDir);
} catch (IOException ex) {
throw new IllegalStateException("Temp Elastic Search directory not created", ex);
}
Properties props = new Properties();
props.setProperty("name", THREAD_NAME);
props.setProperty("path.home", homeDir.toString());
props.setProperty("path.data", dataDir.toString());
props.setProperty("http.port", DATA_PORTS);
props.setProperty("transport.tcp.port", TRANSPORT_PORTS);
props.setProperty("node.local", "true");
props.setProperty("script.groovy.sandbox.enabled", "true");
props.setProperty("script.engine.groovy.inline.aggs", "true");
props.setProperty("script.engine.groovy.inline.search", "true");
props.setProperty("script.engine.groovy.inline.update", "true");
props.setProperty("script.engine.groovy.inline.mapping", "true");
esNode = NodeBuilder.nodeBuilder().local(false).client(false)
.settings(Settings.settingsBuilder().put(props).build()).clusterName(CLUSTER_NAME).build();
esNode.start();
}
In the code tested there is the following method which creates transport connection to ElasticSearch
private Client createClient() throws UnknownHostException {
Settings.Builder builder = Settings.builder();
builder.put("cluster.name", clusterName);
builder.put("client.transport.ignore_cluster_name", true);
Settings settings = builder.build();
return TransportClient.builder().settings(settings).build()
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(hostname), port));
}
when I run the test i receive excepetion
java.net.BindException: Can't assign requested address
at sun.nio.ch.Net.connect0(Native Method)
at sun.nio.ch.Net.connect(Net.java:454)
at sun.nio.ch.Net.connect(Net.java:446)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:648)
at org.jboss.netty.channel.socket.nio.NioClientSocketPipelineSink.connect(NioClientSocketPipelineSink.java:108)
at org.jboss.netty.channel.socket.nio.NioClientSocketPipelineSink.eventSunk(NioClientSocketPipelineSink.java:70)
at org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:574)
at org.jboss.netty.channel.Channels.connect(Channels.java:634)
at org.jboss.netty.channel.AbstractChannel.connect(AbstractChannel.java:216)
at org.jboss.netty.bootstrap.ClientBootstrap.connect(ClientBootstrap.java:229)
at org.jboss.netty.bootstrap.ClientBootstrap.connect(ClientBootstrap.java:182)
at org.elasticsearch.transport.netty.NettyTransport.connectToChannelsLight(NettyTransport.java:913)
at org.elasticsearch.transport.netty.NettyTransport.connectToNode(NettyTransport.java:880)
at org.elasticsearch.transport.netty.NettyTransport.connectToNodeLight(NettyTransport.java:852)
at org.elasticsearch.transport.TransportService.connectToNodeLight(TransportService.java:250)
at org.elasticsearch.client.transport.TransportClientNodesService$SimpleNodeSampler.doSample(TransportClientNodesService.java:354)
at org.elasticsearch.client.transport.TransportClientNodesService$NodeSampler.sample(TransportClientNodesService.java:300)
at org.elasticsearch.client.transport.TransportClientNodesService$ScheduledNodeSampler.run(TransportClientNodesService.java:333)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
The values I send for the tested code as hostname is localhost and I send the port I pull from the embedded ElasticSearch by
NodeInfo nodeInfo = esNode.client().admin().cluster().prepareNodesInfo(localNodeId).get().iterator().next();
transportAddress = nodeInfo.getTransport().address().publishAddress().getAddress();
I saw that the transport port is always 0 and when I evaluate nodeInfo.getTransport().address() its value is local[1].
What in the node creation is wrong?
Is there another configuration I need to add?
Thanks,
Daniela
when I changed props.setProperty("node.local", "true"); to props.setProperty("node.local", "false"); the transport port was created.

Caused by: org.apache.commons.net.MalformedServerReplyException: Could not parse response code

I'm developing a spring boot application which reads data from an ftp connection. Have been referring this article. http://docs.spring.io/spring-integration/reference/html/ftp.html I've added below dependency to pom.xml:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ftp</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
Here is my Spring boot application:
#SpringBootApplication
public class FtpApplication {
public static void main(String[] args) {
SpringApplication.run(FtpApplication.class, args);
}
#Bean
public SessionFactory<FTPFile> ftpSessionFactory() {
DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
sf.setHost("localhost");
sf.setPort(14147);
sf.setUsername("root");
sf.setPassword("root");
return new CachingSessionFactory<FTPFile>(sf);
}
#Bean
public FtpInboundFileSynchronizer ftpInboundFileSynchronizer() {
FtpInboundFileSynchronizer fileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
fileSynchronizer.setDeleteRemoteFiles(false);
fileSynchronizer.setRemoteDirectory("/");
fileSynchronizer.setFilter(new FtpSimplePatternFileListFilter("*.xml"));
return fileSynchronizer;
}
#Bean
#InboundChannelAdapter(channel = "ftpChannel")
public MessageSource<File> ftpMessageSource() {
FtpInboundFileSynchronizingMessageSource source = new FtpInboundFileSynchronizingMessageSource(
ftpInboundFileSynchronizer());
source.setLocalDirectory(new File("ftp-inbound"));
source.setAutoCreateLocalDirectory(true);
source.setLocalFilter(new AcceptOnceFileListFilter<File>());
return source;
}
#Bean
#ServiceActivator(inputChannel = "ftpChannel")
public MessageHandler handler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
File file = (File) message.getPayload();
BufferedReader br;
String sCurrentLine;
try {
br = new BufferedReader(new FileReader(file.getPath()));
while ((sCurrentLine = br.readLine()) != null) {
System.out.println(sCurrentLine);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(message.getPayload());
}
};
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(10));
return pollerMetadata;
}
}
From the windows explorer I'm adding a file. Now when the control comes to the MessageHandler function, I see the below error. But I can neatly get the file and I see the contents correctly when I read it. But I'm unable to figure out what is the error all about:
2016-09-27 08:25:07.548 ERROR 10292 --- [ask-scheduler-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessagingException: Problem occurred while synchronizing remote to local directory; nested exception is org.springframework.messaging.MessagingException: Failed to obtain pooled item; nested exception is java.lang.IllegalStateException: failed to create FTPClient
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer.synchronizeToLocalDirectory(AbstractInboundFileSynchronizer.java:274)
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource.doReceive(AbstractInboundFileSynchronizingMessageSource.java:193)
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource.doReceive(AbstractInboundFileSynchronizingMessageSource.java:59)
at org.springframework.integration.endpoint.AbstractMessageSource.receive(AbstractMessageSource.java:134)
at org.springframework.integration.endpoint.SourcePollingChannelAdapter.receiveMessage(SourcePollingChannelAdapter.java:209)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:245)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.access$000(AbstractPollingEndpoint.java:58)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:190)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:186)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:353)
at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.messaging.MessagingException: Failed to obtain pooled item; nested exception is java.lang.IllegalStateException: failed to create FTPClient
at org.springframework.integration.util.SimplePool.getItem(SimplePool.java:178)
at org.springframework.integration.file.remote.session.CachingSessionFactory.getSession(CachingSessionFactory.java:123)
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:433)
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer.synchronizeToLocalDirectory(AbstractInboundFileSynchronizer.java:232)
... 22 more
Caused by: java.lang.IllegalStateException: failed to create FTPClient
at org.springframework.integration.ftp.session.AbstractFtpSessionFactory.getSession(AbstractFtpSessionFactory.java:169)
at org.springframework.integration.ftp.session.AbstractFtpSessionFactory.getSession(AbstractFtpSessionFactory.java:41)
at org.springframework.integration.file.remote.session.CachingSessionFactory$1.createForPool(CachingSessionFactory.java:81)
at org.springframework.integration.file.remote.session.CachingSessionFactory$1.createForPool(CachingSessionFactory.java:78)
at org.springframework.integration.util.SimplePool.doGetItem(SimplePool.java:188)
at org.springframework.integration.util.SimplePool.getItem(SimplePool.java:169)
... 25 more
Caused by: org.apache.commons.net.MalformedServerReplyException: Could not parse response code.
Server Reply: FZS ..... some speacial characters here.....
at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:336)
at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:292)
at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:418)
at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:966)
at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:954)
at org.apache.commons.net.SocketClient.connect(SocketClient.java:189)
at org.apache.commons.net.SocketClient.connect(SocketClient.java:209)
at org.springframework.integration.ftp.session.AbstractFtpSessionFactory.createClient(AbstractFtpSessionFactory.java:191)
at org.springframework.integration.ftp.session.AbstractFtpSessionFactory.getSession(AbstractFtpSessionFactory.java:166)
... 30 more
I'm new to spring integration, please help. Let me know the concepts that I should still consider preparing.
You are most probably connecting to the FileZilla FTP server administrative port (14147).
That port uses a proprietary protocol used by a "FileZilla Server Interface", not FTP, and you are not supposed to connect to it with your application.
Connect to the FTP port instead. By default that is 21. It is configured in "FileZilla Server Interface" on "General Settings" page of the "FileZilla Server Options" as "Listen to these ports".

Resources