Spring WebClient - SSL configuration - spring

Below is the old code which I am trying to replace. How can I use webclient to follow same behavior?
If anyone can guide me on this it will be great.
I check for code to use HostnameVerifier but i did not find any link which can help me.
public void initSSL() {
if (logger.isDebugEnabled()) {
logger.debug("HttpBasedUrlConnection - Initializing SSL");
}
// Configure truststore location for everybody
final String homePath = getHomePath();
synchronized (this) {
trustStorePath = homePath + "/conf/cert/client.keystore";
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
}
// HEADSUP: This violates HTTPS host verification, since we arnt setting up SSL certs right.
final HostnameVerifier hv = new HostnameVerifier() {
#Override
public boolean verify(final String urlHostName, final SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
// Prepare SSL socket factory with all available certificates
loadCertificates();
}
I came across StackOverflow link which suggests how to accept all the certificates.
That is not exactly what I need but I can use it as temp solution until i find proper one.
public static WebClient getWebClient() throws SSLException {
String baseUrl = "https://localhost:3454/stackoverflow";
SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
HttpClient httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient);
return WebClient.builder().clientConnector(httpConnector).baseUrl(baseUrl).build();
}
I tried it but getting the following error
Runtime exception: 'long io.netty.util.internal.PlatformDependent.objectFieldOffset(java.lang.reflect.Field)' java.lang.NoSuchMethodError: 'long io.netty.util.internal.PlatformDependent.objectFieldOffset(java.lang.reflect.Field)'
at io.netty.channel.nio.NioEventLoop$4.run(NioEventLoop.java:213) ~[netty-transport.jar:4.1.34.Final]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[?:?]
at io.netty.channel.nio.NioEventLoop.openSelector(NioEventLoop.java:203) ~[netty-transport.jar:4.1.34.Final]
at io.netty.channel.nio.NioEventLoop.<init>(NioEventLoop.java:143) ~[netty-transport.jar:4.1.34.Final]
at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:127) ~[netty-transport.jar:4.1.34.Final]
at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:36) ~[netty-transport.jar:4.1.34.Final]
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:84) ~[jboss-client.jar:16.0.0.Final]
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:58) ~[jboss-client.jar:16.0.0.Final]
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:47) ~[jboss-client.jar:16.0.0.Final]
at io.netty.channel.MultithreadEventLoopGroup.<init>(MultithreadEventLoopGroup.java:59) ~[netty-transport.jar:4.1.34.Final]
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:77) ~[netty-transport.jar:4.1.34.Final]
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:72) ~[netty-transport.jar:4.1.34.Final]
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:59) ~[netty-transport.jar:4.1.34.Final]
at reactor.netty.resources.DefaultLoopResources.cacheNioServerLoops(DefaultLoopResources.java:171) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.resources.DefaultLoopResources.cacheNioClientLoops(DefaultLoopResources.java:191) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.resources.DefaultLoopResources.onClient(DefaultLoopResources.java:185) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.tcp.TcpResources.onClient(TcpResources.java:168) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.http.client.HttpClientConnect$HttpTcpClient.connect(HttpClientConnect.java:143) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.tcp.TcpClientOperator.connect(TcpClientOperator.java:43) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.tcp.TcpClientOperator.connect(TcpClientOperator.java:43) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.tcp.TcpClientOperator.connect(TcpClientOperator.java:43) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.tcp.TcpClientOperator.connect(TcpClientOperator.java:43) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.tcp.TcpClient.connect(TcpClient.java:186) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.http.client.HttpClientFinalizer.connect(HttpClientFinalizer.java:68) ~[reactor-netty.jar:0.8.6.RELEASE]
at reactor.netty.http.client.HttpClientFinalizer.responseConnection(HttpClientFinalizer.java:85) ~[reactor-netty.jar:0.8.6.RELEASE]
at org.springframework.http.client.reactive.ReactorClientHttpConnector.connect(ReactorClientHttpConnector.java:111) ~[spring-web.jar:5.1.6.RELEASE]
at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.exchange(ExchangeFunctions.java:103) ~[spring-webflux.jar:5.1.6.RELEASE]
at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.exchange(DefaultWebClient.java:319) ~[spring-webflux.jar:5.1.6.RELEASE]
at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.retrieve(DefaultWebClient.java:368) ~[spring-webflux.jar:5.1.6.RELEASE]

Related

AWS Oracle with SSL java.sql.SQLRecoverableException: IO Error: Connection reset AWS

I am trying to connect a simple java application to an AWS Oracle DB using the SSL connection with protocle=tcps
I have verified below
I have imported the rds-ca-2019.pem and rds-ca-2015.pem file to my trust store and the ssl handshake seems to be fine. I have used the below as outlined in AWS Doc
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class OracleSslConnectionTest {
private static final String DB_SERVER_NAME = "<dns-name-provided-by-amazon-rds>";
private static final Integer SSL_PORT = "<ssl-option-port-configured-in-option-group>";
private static final String DB_SID = "<oracle-sid>";
private static final String DB_USER = "<user name>";
private static final String DB_PASSWORD = "<password>";
// This key store has only the prod root ca.
private static final String KEY_STORE_FILE_PATH = "<file-path-to-keystore>";
private static final String KEY_STORE_PASS = "<keystore-password>";
public static void main(String[] args) throws SQLException {
final Properties properties = new Properties();
final String connectionString = String.format(
"jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=%s)(PORT=%d))(CONNECT_DATA=(SID=%s)))",
DB_SERVER_NAME, SSL_PORT, DB_SID);
properties.put("user", DB_USER);
properties.put("password", DB_PASSWORD);
properties.put("oracle.jdbc.J2EE13Compliant", "true");
properties.put("javax.net.ssl.trustStore", KEY_STORE_FILE_PATH);
properties.put("javax.net.ssl.trustStoreType", "JKS");
properties.put("javax.net.ssl.trustStorePassword", KEY_STORE_PASS);
final Connection connection = DriverManager.getConnection(connectionString, properties);
// If no exception, that means handshake has passed, and an SSL connection can be opened
}
}
Confirming that I have opened an inbound rule to the instance from teh security group of the Oracle RDS
I have used many ojdbc drivers
ojdbc14.jar
ojdbc6.jar
ojdbc8-12.2.0.1.jar
Confirming that I can access the DB without ssl , which mean protocol=tcp and with the designated port for non -ssl
It is when I used the below I get the error
With protocol=tcps
port=ssl port
Confirming the trust store path and the password are okay
Need help in the below error
java.sql.SQLRecoverableException: IO Error: Connection reset
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:682)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:711)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:385)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:30)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:558)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
at OracleCon.main(OracleCon.java:33)
Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:757)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at oracle.net.ns.Packet.send(Packet.java:419)
at oracle.net.ns.ConnectPacket.send(ConnectPacket.java:241)
at oracle.net.ns.NSProtocolStream.negotiateConnection(NSProtocolStream.java:151)
at oracle.net.ns.NSProtocol.connect(NSProtocol.java:263)
at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1360)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:486)
... 7 more

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());
}

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

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".

AuthenticationFailedException: AUTHENTICATE failed After some connections

I have a Spring-Boot (1.4.0) application and I am using springframework.boot:spring-boot-starter-mail.
I have a method annotated with #Scheduled to check my inbox every a certain period of time.
This is how I get my inbox:
private static Folder getInbox() throws MessagingException {
final String protocol = "mail.store.protocol";
final String storeType = "imaps";
final String email = "email";
final String password = "password";
final String connect = "webmail.company.com";
final String folder = "INBOX";
final Properties props = new Properties();
props.setProperty(protocol, storeType);
final Session session = Session.getInstance(props, null);
final Store store = session.getStore();
store.connect(connect, email, password);
final Folder inbox = store.getFolder(folder);
inbox.open(Folder.READ_WRITE);
return inbox;
}
Then I have this:
#Scheduled(fixedRate = 10000)
#Override
public void checkEmailCreateCompanyAndSendCsv() throws MessagingException, IOException {
log.info("Checking e-mail...");
final Folder inbox = getInbox();
final Flags seen = new Flags(Flags.Flag.SEEN);
final FlagTerm unseenFlagTerm = new FlagTerm(seen, false);
inbox.getMessages();
final Message messages[] = inbox.search(unseenFlagTerm);
.....
.....
}
When the APP is running everything works great but after some time (around 7 to 8 e-mail checks) it starts to thrown an exception:
javax.mail.AuthenticationFailedException: AUTHENTICATE failed. at
com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:717) at
javax.mail.Service.connect(Service.java:366) at
javax.mail.Service.connect(Service.java:246) at
com.opessoftware.crs.selfcertification.services.EmailServiceBasic.getInbox(EmailServiceBasic.java:183)
at
com.opessoftware.crs.selfcertification.services.EmailServiceBasic.checkEmailCreateCompanyAndSendCsv(EmailServiceBasic.java:50)
at sun.reflect.GeneratedMethodAccessor28.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at
org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
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)
If I stop the application and run it again the error disappears and the cicle starts again.
Any suggestions?
I just solved it.
I was calling the connection too many times and I was exceeding the connection pool of my e-mail server. So what I did is to define the getInbox() and the getSession() as #Bean and Inject them to my EmailService.
Now it creates the connection only once. It is working fine.

Resources