无法将mongodb与ssl连接,获取异常com.mongodb.MongoSocketOpenException:异常打开套接字

时间:2017-06-21 10:30:17

标签: java mongodb sockets ssl

尝试创建一个java客户端以连接到安全的Mongodb服务器(使用身份验证和自签名证书。)

它失败,异常为“com.mongodb.MongoSocketOpenException:异常打开套接字。”

我可以使用robomongo客户端通过autom和ssl选项连接到服务器,该客户端安装在我运行代码的同一台机器上。

此外,我验证了java客户端工作正常,只有mongodb服务器中的身份验证,只有ssl才会失败。

我的代码如下:

com.mongodb.MongoSocketWriteException: Exception sending message
    at com.mongodb.connection.InternalStreamConnection.translateWriteException(InternalStreamConnection.java:462)
    at com.mongodb.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:205)
    at com.mongodb.connection.CommandHelper.sendMessage(CommandHelper.java:89)
    at com.mongodb.connection.CommandHelper.executeCommand(CommandHelper.java:32)
    at com.mongodb.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:83)
    at com.mongodb.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:43)
    at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115)
    at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:128)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
    at sun.security.ssl.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
    at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
    at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
    at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
    at sun.security.ssl.Handshaker.processLoop(Unknown Source)
    at sun.security.ssl.Handshaker.process_record(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source)
    at sun.security.ssl.AppOutputStream.write(Unknown Source)
    at com.mongodb.connection.SocketStream.write(SocketStream.java:75)
    at com.mongodb.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:201)
    ... 7 more
Caused by: java.security.cert.CertificateException: No subject alternative names present
    at sun.security.util.HostnameChecker.matchIP(Unknown Source)
    at sun.security.util.HostnameChecker.match(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    ... 17 more

版本:

Mongo v3.4.5

Jdk 1.8

Mongo-java-driver 3.2.2

完整堆栈跟踪:

@"^[^\W_](?:[\w.-]*[^\W_])?@(([a-zA-Z0-9]+)(\.))([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$"))"

2 个答案:

答案 0 :(得分:0)

这是证书的问题,您在uri中使用IP。尝试使用主机名或为证书添加备用名称。

以下是另一种可能的解决方案:https://www.ibm.com/support/knowledgecenter/SS3NGB_5.1.0.3/ioc/ts_liberty_ip.html

答案 1 :(得分:0)

最后,我发现问题并正确解决问题。 第一个问题是证书,因为我使用的是自签名证书,我必须在创建客户端时明确地传递它,但我不相信SSL。因为代码是:

public static SSLSocketFactory validateCert(String hostIP) {
        HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals(hostIP));
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

            }

            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

            }
        } };

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, null);
            return sc.getSocketFactory();
        } catch (GeneralSecurityException e) {
        }
        return null;
    }

第二个问题是我使用凭据的方式。实际上,如果你使用URL方法,默认类型的mongo凭证是“MONGODB-CR”,但当我使用其他方式的身份验证,即“SCRAM-SHA-1”时,它工作正常。代码是:

ServerAddress seeds = new ServerAddress(mongodbIP, Integer.parseInt(mongodbPort));
        List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();
        credentialsList
                .add(MongoCredential.createScramSha1Credential(mongoUser, mongoDefaultDB, mongoPassword.toCharArray()));
        SSLSocketFactory socketFactory = CertificateHelper.validateCert(mongodbIP);
        MongoClientOptions optionsBuilder = builder().sslEnabled(true).socketFactory(socketFactory)
                .sslInvalidHostNameAllowed(true).build();
        this.mongoClient = new MongoClient(seeds, credentialsList, optionsBuilder);