【问题标题】:Java Rconnection hangs when Rserve has TLS enabled当 Rserve 启用 TLS 时,Java Rconnection 挂起
【发布时间】:2019-08-16 03:29:42
【问题描述】:

我有一个安装了 R 和 Rserve 的 Ubuntu VM,用于远程调用。我从终端以调试模式启动 Rserve:

R CMD Rserve.dbg

这是输出:

Rserve 1.8-6 () (C)Copyright 2002-2013 Simon Urbanek

Loading config file /etc/Rserv.conf
conf> command="remote", parameter="enable"
conf> command="plaintext", parameter="disable"
conf> command="encoding", parameter="utf8"
conf> command="pwdfile", parameter="/etc/RserveAuth.txt"
conf> command="auth", parameter="required"
conf> command="qap", parameter="disable"
conf> command="qap.tls.port", parameter="6311"
conf> command="tls.key", parameter="server.key"
conf> command="tls.cert", parameter="server.crt"
conf> command="tls.ca", parameter="rootCA.crt"
Loaded config file /etc/Rserv.conf

R version 3.5.3 (2019-03-11) -- "Great Truth"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

 - create_server(port = 6311, socket = <NULL>, mode = 0, flags = 0x800)
INFO: adding server 0x5618de18b9d0 (total 1 servers)
Rserve: Ok, ready to answer queries.

我使用 OPENSSL 生成了密钥和自签名证书。

现在在客户端,我有一个 Java 应用程序,它只是请求 Rserve 所在的 R 版本作为功能测试:

import org.rosuda.REngine.REXP;
import org.rosuda.REngine.Rserve.RConnection;

public class RJava {
    public static void main(String[] args) throws Exception{
        //Run R code on remote R installation via Rserve.
        String remoteIP="10.16.24.63"; //Ubuntu VM Box
        int port=6311;
        String user="TEST";
        String pass="12345";

        //Connect to the remote server.
        RConnection connection = new RConnection(remoteIP,port);//Remote server
        connection.login(user, pass);

        //Run a command.
        REXP x = connection.eval("R.version.string");
        System.out.println(x.asString());

        //Disconnect.
        connection.close();
    }
}

问题是客户端代码在调用RConnection 构造函数时挂起。我已经让它走了十分钟,在我杀死服务器之前没有任何变化。在服务器端我只看到:

INFO: accepted connection for server 0x5618de18b9d0, calling connected
connection accepted.

目前我找不到任何可提供帮助的文档。这可能是客户端配置问题吗?

另外,如果我从 Rserv.conf 中删除所有 TLS 配置项,Rserve 将按预期工作,此客户端代码没有问题,所以我知道它设置正确。

【问题讨论】:

    标签: java tls1.2 rserve jri


    【解决方案1】:

    这是我自己想出来的。这实际上是一个客户端配置问题。我需要使用 SSLSocket 创建 RConnection,并将服务器证书导入 java 信任库。

    相关客户端代码改成这样:

    SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
    SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(remoteIP, port);
    //Connect to the remote server.
    RConnection connection = new RConnection(sslsocket);
    

    注意构造函数RConnection(Socket s) 显然不在REngine jar 中,所以我抓住the source itself 并将其放入我的项目中,因为它包含在那里。

    此时运行会抛出javax.net.ssl.SSLHandshakeException,因为证书不在信任库中。所以我使用 OPENSSL 从服务器中撤回了证书,如下所示:

    echo "" | openssl s_client -connect 10.16.24.63:6311 | openssl x509 -out server.crt

    然后我将该证书文件移动到%JAVA_HOME%\jre\lib\security 并运行它来导入证书:

    keytool -import -alias myAlias -file server.crt -keystore cacerts -storepass changeit

    而且它有效! Wireshark 确认所有数据包现在都已加密。

    资源:

    https://stats-rosuda-devel.listserv.uni-augsburg.narkive.com/g5VM1afB/encryption-with-rserve-1-8-1

    https://www.baeldung.com/java-ssl

    Digital Certificate: How to import .cer file in to .truststore file using?

    【讨论】: