1

所以,我正在滚动我自己的基于 Java 的应用程序服务器(因为 Glassfish 等人不适用于非基于 Web 的应用程序),当然,加密是绝对必须的。因此,我使用标准编写了一个基本的 ssl 解决方案SslRMIClientSocketFactory,和SSLRMIServerSocketFactory. 到目前为止,一切都很好。不过,我还有一些其他问题,例如允许但不要求使用客户端证书(就像您 ssh 进入系统时一样),但我愿意考虑改天再做一次练习。

然而,在此过程中,我注意到自 2005 年左右以来随着“Java 5.0”的出现,我们显然对使用xinetd基于 'nix 的解决方案有所帮助。在我看来,这样做的“新”帮助是能够从较低级别(如 xinetd - via )“继承”套接字信息System.inheritedChannel

我想我需要一个在 RMI 解决方案中一起使用加密和 xinetd 的示例,并在这里找到了一篇很棒的文章 The New RMI - 或者,至少,如果不是应该附带的示例代码,那就太好了文章不见了。有点烂,我猜。(有人有副本吗?!)文章中可见的示例太不完整,文本依赖于您拥有示例代码的事实。那好吧。简单地说,我不太明白 - 使用System.inheritedChannel显然不像将其插入现有的 RMI Registry 相关代码那么简单 - 你显然必须创建一个套接字工厂,或者我只是不明白 - 因此,寻找一个例子。

于是我去打猎。我发现 Apache 的人做了类似的事情,这里描述了RMI Service Exporter,但是,它使用了我宁愿避免使用的技术 - SpringBeans,如果你愿意的话。而且,因为这是一个重要的例子,坦率地说,我对如何在我的工作中使用这种类型的解决方案有点迷茫。

我一直在寻找并发现乍一看似乎是一个名为InitializeRegistry的出色解决方案,但它根本没有对 SSL 的任何引用,我马上就迷路了。例如,它将自己描述为:

创建和导出一个注册表(使用继承的通道,如果有的话,如下所示),并将指定的名称绑定到该注册表中的指定代理。

我的问题是语言。特别是,我没有使用代理,即使我使用了,我也不知道为什么这很重要。而且我认为我将对象绑定到 RMI 注册表,而不仅仅是名称。也许如果有人可以澄清他们在做什么,这是一个很好的例子......

最后,我在 StackOverflow 上偶然发现了一个很棒的回复——这是有史以来最糟糕的回复之一,谈论Java RMI、SSL 和压缩。压缩不符合我的需求,但它是一个有启发性的讨论。不过,我看不出它如何帮助我理解如何同时将 RMI 与 SSL 和 xinetd 一起使用......

谢谢你。

更新:

为了回应 EJP 提出的答案(对此我很感激),我从InitializeRegistry.java上面引用的示例开始。我将 accept() 方法更新为:

      .
      .
      .
      /* Here we wrapper our socket with SSLSocketFactory.createSocket()

         Some open questions I have are whether the arguments to createSocket()
         are all _inbound_ in nature. Here's the basic call:

            SSLSocketFactory.createSocket(socket, host, port, auto-close);

         I PRESUME args are for the REMOTE host, not "us?"

            REMOTE: serverSocket.getInetAddress()
            LOCAL:  serverSocket.getLocalAddress()

            REMOTE: serverSocket.getPort()
            LOCAL:  serverSocket.getLocalPort()

         Who Knows about auto-close?! I'll try it and see if it works OK.
      */

      boolean autoClose = true;

      return (Socket)SSLSocketFactory.createSocket(serverSocket.accept(),
       serverSocket.getInetAddress().getHostAddress(),
       serverSocket.getLocalPort(),
       autoClose).accept();

      //return serverSocket.accept();
   }

但是,此代码无法编译,抱怨:

  • createSocket()不能从静态上下文中调用 - 我找不到任何解决方案
  • 它找不到“符号”“ .accept()”——两者中的第二个。

删除 final.accept()会导致错误倒计时,只是无法createSocket()从此代码的静态上下文中使用“非静态方法”。但是当我尝试从类中删除“静态”时,它到处都是,无法使用无处不在的“ this”引用。OTOH,我不知道如何制作SSLSocketFactory.createSocket()静态!

...是否可以安全地假设accept()用于访问传递的套接字 (!!) 的那个就足够了,并且不需要我尝试包含的后续一个?嗯……

我很乐意尝试一下,看看我能不能把它建成。

顺便说一句,我想我会setUseClientMode(false)在以后使用......是吗?

进一步思考......

我意识到这可能InitializeRegistry.java是一个糟糕的起点,并回到“第一原则”,发现当它第一次接受channel它时,它可能会误入歧途System.inheritedChannel,并将其转换为 a ServerSocket,所以覆盖的想法ServerSocketFactory是,嗯,“很多工作”。然后它就撞到了我:

这里的重点是尝试确保未经请求的连接请求到达正在侦听的目标。但更重要的是,注册表中必须有一个对象才能使用它,为此,人们也需要任何创造这种情况的东西。因此,确保创建对象的代码作为 SYSTEM SERVICE 运行,而不用担心将其作为 NETWORK SERVICE 来解决,这同样好,也更容易。

因此,我在下注。...不过,删除这个问题似乎很可惜,因为这可能会为其他人提供指导——这是 StackOverflow 中唯一一个涉及这个主题的查询。

再次感谢。

4

1 回答 1

2

我看不出 的意义DelayedAcceptServerSocketFactory,这只是有点矫枉过正,但基本技术如下:

  1. 编写一个RMIServerSocketFactory返回ServerSocketaccept()方法被覆盖以委托给ServerSocket来自继承通道的覆盖的覆盖。

  2. 在该accept()方法返回之前,将接受的内容包装Socket在一个SSLSocket、 viaSSLSocketFactory.createSocket(Socket, ...)中,然后调用setUseClientMode(false)该套接字。

瞧!您的 RMI Registry 现在由 xinetd 启动,并向您的 Registry 客户端使用 SSL。假设这是您想要的,您的客户现在可以查找该注册表,只要他们通过LocateRegistry.getRegistry(host, port, csf).

同样,您的服务器可以绑定到它,只要它们以相同的方式访问它。

现在,使用 SslRMI* 套接字工厂创建远程对象,并像往常一样将它们绑定到注册表。

完毕。

于 2012-02-28T03:48:57.053 回答