I recently set up a server using a self-signed certificate and I just cannot get it to work on Java. My process was to create a ca pem and a key pem and use them for TLS. With this, I've gotten Mongo compass able to connect as well as a basic Python program. When i try to do the same thing in Java I constantly get this error: Hi, I recently set up a server using a self-signed certificate and I just cannot get it to work on Java. My process was to create a ca pem and a key pem and use them for TLS. With this, I've gotten Mongo compass able to connect as well as a basic Python program. When i try to do the same thing in Java I constantly get this error:
Caused by: javax.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
Because it' s java, I also had to remove the extra tls stuff at the end of the uri and use trust and key stores to get it working, but it never ended up working. Below is my code:
System.setProperty("javax.ssl.trustStore","C:/Program Files/Java/jdk-21/lib/security/cacerts");
System.setProperty("javax.ssl.trustStorePassword","changeit");
System.setProperty("javax.ssl.keyStore", "C:/Program Files/Java/jdk-21/lib/security/mongodb.pkcs12");
System.setProperty("javax.ssl.keyStorePassword","changeit");
System.out.println(System.getProperties());
String connectionString = "<mongodb-uri>?tls=true";
MongoClientSettings settings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.applyToSslSettings(builder -> {
builder.enabled(true);
builder.invalidHostNameAllowed(true);
})
.build();
MongoClient client = MongoClients.create(settings);
To try to set up the trust store, I ran:
keytool -import -trustcacerts -file mongodbca.pem -keystore cacerts -storepass "changeit"
and for the key store I simply changed my pem file to a pkcs12 file with openssl with the following:
openssl pkcs12 -export -out mongodb.pkcs12 -in mongodbkey.pem
What is so strange to me, is that it works with everything else except for Java, and unfortunately the only one I need it to work on is Java lol. If you have any ideas, that would be awesome.
I recently set up a server using a self-signed certificate and I just cannot get it to work on Java. My process was to create a ca pem and a key pem and use them for TLS. With this, I've gotten Mongo compass able to connect as well as a basic Python program. When i try to do the same thing in Java I constantly get this error: Hi, I recently set up a server using a self-signed certificate and I just cannot get it to work on Java. My process was to create a ca pem and a key pem and use them for TLS. With this, I've gotten Mongo compass able to connect as well as a basic Python program. When i try to do the same thing in Java I constantly get this error:
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
Because it' s java, I also had to remove the extra tls stuff at the end of the uri and use trust and key stores to get it working, but it never ended up working. Below is my code:
System.setProperty("javax.net.ssl.trustStore","C:/Program Files/Java/jdk-21/lib/security/cacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");
System.setProperty("javax.net.ssl.keyStore", "C:/Program Files/Java/jdk-21/lib/security/mongodb.pkcs12");
System.setProperty("javax.net.ssl.keyStorePassword","changeit");
System.out.println(System.getProperties());
String connectionString = "<mongodb-uri>?tls=true";
MongoClientSettings settings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.applyToSslSettings(builder -> {
builder.enabled(true);
builder.invalidHostNameAllowed(true);
})
.build();
MongoClient client = MongoClients.create(settings);
To try to set up the trust store, I ran:
keytool -import -trustcacerts -file mongodbca.pem -keystore cacerts -storepass "changeit"
and for the key store I simply changed my pem file to a pkcs12 file with openssl with the following:
openssl pkcs12 -export -out mongodb.pkcs12 -in mongodbkey.pem
What is so strange to me, is that it works with everything else except for Java, and unfortunately the only one I need it to work on is Java lol. If you have any ideas, that would be awesome.
Share Improve this question asked Feb 6 at 4:37 AVGAVG 112 bronze badges 2 |1 Answer
Reset to default 0The applyToSslSettings
method has the option to provide an sslContext object. You can configure this sslContext with the key and trust material. I tested it with mongodb cloud and it works. Can you also give it a try?
The full code snippet which I have used is:
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerApi;
import com.mongodb.ServerApiVersion;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.TransactionBody;
import org.bson.Document;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class App {
public static void main(String[] args) {
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(Paths.get("C:/Program Files/Java/jdk-21/lib/security/mongodb.pkcs12"), "changeit".toCharArray())
.withTrustMaterial(Paths.get("C:/Program Files/Java/jdk-21/lib/security/cacerts"), "changeit".toCharArray())
.withLoggingTrustMaterial()
.build();
String connectionString = "YOUR_CONNECTION_URL";
ServerApi serverApi = ServerApi.builder()
.version(ServerApiVersion.V1)
.build();
MongoClientSettings settings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.applyToSslSettings(builder -> builder.enabled(true).context(sslFactory.getSslContext()))
.serverApi(serverApi)
.build();
try (MongoClient mongoClient = MongoClients.create(settings)) {
System.out.println("=> Print list of databases:");
List<Document> databases = mongoClient.listDatabases().into(new ArrayList<>());
databases.forEach(db -> System.out.println(db.toJson()));
ClientSession clientSession = mongoClient.startSession();
TransactionOptions transactionOptions = TransactionOptions.builder()
.writeConcern(WriteConcern.MAJORITY)
.build();
TransactionBody<String> transactionBody = () -> {
MongoCollection<Document> coll1 = mongoClient.getDatabase("mydb1").getCollection("foo");
coll1.insertOne(clientSession, new Document("abc", 1));
return "Inserted into collections in different databases";
};
clientSession.withTransaction(transactionBody, transactionOptions);
}
}
}
In the above example I demonstrated loading the keystores with my own ssl library, which you can find here: GitHub - SSLContext Kickstart It makes the creation of an sslcontext easy, however if you don't want to use additional library, then you can use the snippet below to create it with just plain java.
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Objects;
public class App {
public static void main(String[] args) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
Path keyStorePath = Paths.get("C:/Program Files/Java/jdk-21/lib/security/mongodb.pkcs12");
Path trustStorePath = Paths.get("C:/Program Files/Java/jdk-21/lib/security/cacerts");
char[] password = "changeit".toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
KeyStore trustStore = KeyStore.getInstance("PKCS12");
try(InputStream keyStoreInputStream = Files.newInputStream(keyStorePath) ;
InputStream trustStoreInputStream = Files.newInputStream(trustStorePath)) {
Objects.requireNonNull(keyStoreInputStream);
Objects.requireNonNull(trustStoreInputStream);
keyStore.load(keyStoreInputStream, password);
trustStore.load(trustStoreInputStream, password);
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
}
}
settings
? Perhaps you need to add optionbuilder.tlsCAFile(mongodbca.pem)
or similar. – Wernfried Domscheit Commented Feb 6 at 7:16