1

I have Mule ESB deployed to a Linux server and Anypoint Studio running in my local windows dev environment. I have a fairly simple flow that includes a SalesForce connector. Salesforce REST API has a valid cert signed by VeriSign and my local instance of Mule happily accepts it and connects with no problems. However, when Mule runs on the server it always throws "PKIX path building failed, unable to find valid certification path to requested target".

I've tried using the default java keystore, specifying a keystore with javax.net.ssl.keystore, nothing works.

On my local machine I've ended up doing the following to show that Mule is using the right trust store:

I generated an empty truststore and added it to my AnyPoint project as a resource. I created an HTTPS connector configuration in order to explicitly specify the truststore I want to be used for my SalesForce connector, and pointed it to my empty truststore. When I try to run the project locally, I get the exact same SSL error (as I would expect, since it's an empty truststore). I then take the VeriSign CA cert and add it to my empty truststore. After that, locally everything works just fine. To me, this confirms that my mule project is using the truststore that I've added as a resource to the project itself. I then export this project and deploy it to my server. On the server it throws the SSL error.

Can there be some weird JVM config differences that could cause this?

Egor
  • 1,622
  • 12
  • 26
  • possible duplicate of [Setting multiple truststore on the same JVM](http://stackoverflow.com/questions/7591281/setting-multiple-truststore-on-the-same-jvm) – jww Aug 16 '14 at 11:21
  • @jww It's a similar issue, certainly, but that question deals specifically with setting a truststore in code. For someone working with Mule (mostly XML configuration), I think it would only be useful if they were to get the Mule source and start modifying default behaviour with a custom build. – Egor Aug 18 '14 at 16:07

2 Answers2

3

It turns out that Mule does not use a different trust store for each service. If you have multiple services deployed to it, the last service to declare a trust store explicitly will force all other services to use that same trust store, overwriting whatever configuration they may have. This was happening in my case. I found this out by echoing out System.getProperty("javax.net.ssl.trustStore"); to log and realized it's a trust store that was a resource in some completely different deployed project but being used by mine. Seems like a pretty bad screw up by the Mule guys.

Egor
  • 1,622
  • 12
  • 26
  • Independently of what the Mule team has done, the `System.getProperty("javax.net.ssl.trustStore")` is only read once to initialise the default `SSLContext`. Changing it after the default `SSLContext` has been initialised (i.e. the first time SSL/TLS is used without a specific `SSLContext` loaded programmatically) will have no effect. Therefore, echoing out `System.getProperty("javax.net.ssl.trustStore")` will not necessarily reflect what's being used. – Bruno Aug 16 '14 at 11:47
  • @Bruno Fair enough. I was fortunate that the property pointed me in the right direction. I'm not sure why Mule sets the default context instead of using unique contexts for each service. Taking a look at JIRA I found an old bug that appears to be this exact issue, was fixed a couple years ago but looks like it regressed. – Egor Aug 18 '14 at 16:02
0

I agree with your suspicion that the JDK on your linux server doesn't trust the proper certificates. However, this doesn't need to stop your application from doing so.

I've been able to make the salesforce connector trust a given certificate by doing the following:

KeyStore truststore = KeyStore.getInstance("JKS");
truststore.load(myKeystoreInputStream, myKeystorePassword.toCharArray());

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(truststore);

SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

The key is the last line. The salesforce connector uses HttpsURLConnection directly to connect to the server, while the HTTPS connector doesn't. This will allow your mule application to use a different trust store for salesforce than it uses for one or more HTTPS connectors. You can use this to control the SSL certificates that your application will trust, independently from the certificates that the server's JVM trusts.

Ryan Hoegg
  • 2,415
  • 2
  • 14
  • 15
  • Thanks for the tip. So far I've been just doing XML and using OOTB connectors, but I may have to change some of the java code to get this problem resolved. My real issue was finding out WHY the problem happens, and not only for SalesForce connectors but standard HTTPS ones as well. – Egor Aug 18 '14 at 16:12