如何在 Java 11 客户端 - MongoDB 4.4 (SSL) 之间进行身份验证?
Posted
技术标签:
【中文标题】如何在 Java 11 客户端 - MongoDB 4.4 (SSL) 之间进行身份验证?【英文标题】:How to authenticate between a Java 11 Client - MongoDB 4.4 (SSL)? 【发布时间】:2021-04-23 04:09:21 【问题描述】:有人要求我将 Java 8(spring)微服务迁移到 Java 11 微服务(Quarkus 框架)。 微服务使用 X509 证书对 MongoDB 4.4 数据库进行身份验证。这适用于 Java 8 版本,没有任何错误或问题。 尽管如此,Java 11 版本将无法运行,并且在部署时会显示以下堆栈跟踪:
com.mongodb.MongoSocketWriteException: Exception sending message
at com.mongodb.internal.connection.InternalStreamConnection.translateWriteException(InternalStreamConnection.java:619)
at com.mongodb.internal.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:497)
at com.mongodb.internal.connection.InternalStreamConnection.sendCommandMessage(InternalStreamConnection.java:328)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:278)
at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:83)
at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:33)
at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:107)
at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:62)
at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:144)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:188)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:144)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
相关源码:
package everest.onecd.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
public class MongoConfiguration
private static final String PATH = "/usr/share/easy-rsa/keys/java11/mongo.jks";
private static final Logger LOG = LoggerFactory.getLogger(MongoConfiguration.class);
private static final String IP = "XX.XX.XX.XX";
private static final String PORT = "27017";
public static MongoDatabase getDatabase()
SSLContext context = getSSLContext();
MongoClientSettings.Builder settings = MongoClientSettings.builder();
settings.applyToSslSettings(builder -> builder.context(context); builder.invalidHostNameAllowed(true); builder.enabled(true); );
settings.applyConnectionString(new ConnectionString("mongodb://" + IP + ":" + PORT + "/test?ssl=true&authMechanism=MONGODB-X509&connectTimeoutMS=60000&socketTimeoutMS=60000&retryWrites=true&maxIdleTimeMS=60000"));
MongoClient client = MongoClients.create(settings.build());
MongoDatabase database = client.getDatabase("test");
return database;
private static SSLContext getSSLContext()
SSLContext sslContext = null;
try (FileInputStream fis = new FileInputStream(new File(PATH)))
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(fis, ".sevenzip".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
LOG.info("Se ejecuto SSLContext exitosamente");
catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e)
LOG.error(e.toString(), e);
return sslContext;
我已经尝试过了:Java 11 and 12 SSL sockets fail on a handshake_failure error with TLSv1.3 enabled 因此,我使用 -keyalg RSA 生成了新的 JKS,但它也不起作用。我还将 TLS 版本更改为 1.2 和 1.3 并得到了相同的异常。
【问题讨论】:
【参考方案1】:这是解决方案,经过所有的斗争。在 Quarkus 中,需要完全初始化所有的信任库和密钥库。因此,显然,它忽略了 JVM args -Djavax.net.ssl.keyStore 和 -Djavax.net.ssl.trustStore。
private static SSLContext getSSLContext()
SSLContext sslContext = null;
try (FileInputStream fis = new FileInputStream(new File(TPATH)))
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(fis, ".sevenzip".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
FileInputStream fKS = new FileInputStream(new File(PATH));
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(fKS, ".sevenzip".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, ".sevenzip".toCharArray());
sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
LOG.info("Se ejecuto SSLContext exitosamente");
catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e)
LOG.error(e.toString(), e);
catch (UnrecoverableKeyException e)
LOG.error(e.toString(), e);
return sslContext;
【讨论】:
我将 Java 11 与 Spring boot 2.4.5 一起使用,您的解决方案对我帮助很大。谢谢以上是关于如何在 Java 11 客户端 - MongoDB 4.4 (SSL) 之间进行身份验证?的主要内容,如果未能解决你的问题,请参考以下文章
在 Meteor 运行时,如何从另一个客户端访问 Meteor 的 MongoDB?