Egor
Egor

Reputation: 1660

Mule ESB does not accept SSL cert when deployed on server, but works fine on local dev machine

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?

Upvotes: 1

Views: 3051

Answers (2)

Ryan Hoegg
Ryan Hoegg

Reputation: 2475

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.

Upvotes: 0

Egor
Egor

Reputation: 1660

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.

Upvotes: 3

Related Questions