从JAVA应用程序使用SSL连接到MongoDb

时间:2017-02-17 14:18:29

标签: java mongodb ssl

我有一个MongoDb实例正在运行(单个实例)且启用了SSL。我可以使用RoboMongoSSL标签进行连接,我提供以下内容:

CA File : /path to my certificate/testCA.pem 
PEM certificate/key: /path to my key/testKey.pem

成功连接。现在我正在尝试从java应用程序连接到相同的mondodb。我使用以下命令将testCA.pem导入cacerts:

keytool -import -keystore cacerts -file testCA.pem -storepass changeit

我可以看到添加到商店的新条目。试图将其他密钥添加到其中,它表示无效的证书。在Java应用程序中,我将系统属性设置如下:

System.setProperty ("javax.net.ssl.trustStore","C:\\Program Files\\Java\\jre1.8.0_91\\lib\\security\\cacerts");
System.setProperty ("javax.net.ssl.trustStorePassword","changeit");

我收到以下错误:

org.springframework.dao.DataAccessResourceFailureException: Timed out after 10000 ms while waiting to connect. Client view of cluster state is {type=Unknown, servers=[{address=test.mongo.com:27017, type=Unknown, state=Connecting, exception={com.mongodb.MongoException$Network: Exception opening the socket}, caused by {java.io.EOFException}}]; nested exception is com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting to connect. Client view of cluster state is {type=Unknown, servers=[{address=test.mongo.com:27017, type=Unknown, state=Connecting, exception={com.mongodb.MongoException$Network: Exception opening the socket}, caused by {java.io.EOFException}}]
    at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:75)
    at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2075)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1918)

我在这里错过了什么,提前谢谢!

6 个答案:

答案 0 :(得分:1)

您需要配置monog db驱动程序以使用SSL。您可以在@Configuration类中手动配置它来执行此操作。

{{1}}

答案 1 :(得分:1)

除了使用以下命令导入CAFile.pem

(导航到java_home/jre/lib/security以运行命令)

1. keytool -import -trustcacerts -file testCA.pem -keystore cacerts -storepass "changeit"

我还必须将key.pem导出为pkcs12格式(默认密码'changeit'

2. openssl pkcs12 -export -out mongodb.pkcs12 -in testKey.pem

除了设置系统属性trustStore / password之外,还应该设置keyStore / password:

System.setProperty ("javax.net.ssl.trustStore",JAVA_HOME + "\\lib\\security\\cacerts");
System.setProperty ("javax.net.ssl.trustStorePassword","changeit");
System.setProperty ("javax.net.ssl.keyStore",JAVA_HOME + "\\lib\\security\\mongodb.pkcs12");
System.setProperty ("javax.net.ssl.keyStorePassword","changeit");

答案 2 :(得分:1)

下面提到的两种方法通常在论坛上建议' work' 但是不安全,因为他们禁用主机名验证基本上否定了SSL。因此,特别是如果您的代码将在生产中部署,则不建议使用它们:

// 1. For any HTTPS connection
    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
        new javax.net.ssl.HostnameVerifier(){
            public boolean verify(String hostname,
                javax.net.ssl.SSLSession sslSession) {
                    if(hostname.equals("<hostname>")) {
                        return true; 
                    }
                }
            });

// 2. MongoDB SSL specific 
MongoClientOptions.builder().sslEnabled(true).sslInvalidHostNameAllowed(true).build();

参考:https://wiki.openssl.org/index.php/Hostname_validation

要解决此问题,您需要一个包含服务器DNS的证书作为主题备用名称条目,您可以将其导入JDK cacerts

或者,如果您想在应用程序级别建立SSL,我建议为该特定连接创建SSLContext,而不是使用System.setProperty()来设置密钥库/信任存储。如果您的应用程序连接到具有不同SSL实现的不同外部服务,这将有助于避免冲突。

特别是对于MongoDB,您只需要在上述步骤之后在MongoDBURI的末尾附加?ssl=true。如果仍然无效,我建议您按https://jira.mongodb.org/browse/JAVA-2184更新JDK版本

希望这有帮助

答案 3 :(得分:0)

如果将RAD与WAS本地服务器一起使用,则必须将pem文件添加到该服务器的Java VM中。

因此,如果您已将WAS安装到X:\ IBM \ WASx,则X:\ IBM \ WASx \ java_17 \ jre是要导航的目录,然后在其中执行keytool导入。希望这对其他人有帮助。

答案 4 :(得分:0)

如代码中提到的Redlab,可以将其禁用以限制ssl验证。特别是这种情况是在本地设置上发生的。不需要额外的精力。

public @Bean MongoClient mongo()  {
    MongoClientOptions.Builder options = MongoClientOptions.builder().sslEnabled(false);
    // add more options to the builder with your config
    MongoClient mongoClient = new MongoClient("localhost", options.build());
    return mongoClient;
}

我刚刚修改了- sslEnabled(true)===> sslEnabled(false)。

答案 5 :(得分:0)

请检查下面的 MongoDB Java驱动程序 4.x和 MongoDB 3.x

代码

必须根据您的MongoDB 配置 spring.data.mongodb.xxxx 属性的位置

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

@Configuration
public class MongoClientConfig {

    @Value("${spring.data.mongodb.username}")
    private String user;
    
    @Value("${spring.data.mongodb.password}")
    private char[] password;
    
    @Value("${spring.data.mongodb.host}")
    private String host;
    
    @Value("${spring.data.mongodb.port}")
    private int port;
    
    @Value("${spring.data.mongodb.database}")
    private String database;
    
    @Bean
    public MongoClient mongo() {
        List<ServerAddress> hosts = Arrays.asList(new ServerAddress(host, port));
        MongoCredential credential = MongoCredential.createCredential(user, database, password);

        MongoClientSettings settings = MongoClientSettings.builder().credential(credential)
                .applyToSslSettings(builder -> builder.enabled(true))
                .applyToClusterSettings(builder -> builder.hosts(hosts)).build();
        MongoClient mongoClient = MongoClients.create(settings);
        System.out.println("====================================================================");
        System.out.println("========= MongoClientConfig: " + mongoClient.toString() + "=========");
        System.out.println("====================================================================");
        return mongoClient;
    }
}