UML软件工程组织

经典:实例讲解如何穿越防火墙访问EJBs
转自:http://www.ftponline.com 作者:Anand Sankaran
你是否曾想编写一个可以穿越防火墙来访问EJBs的J2EE应用程序?这会很麻烦,开发人员必须用各种迂回的方法,而没有一种是“特别好的”。开发人员通常写一个servlet来截取HTTP请求,并将它们导向到EJBs,这种方法很不正规。

另一种方法是运用信道(tunneling)技术,如HTTP上的RMI,这种方法会给性能带来很大的影响。除了上述的两种方法外,还有一种更好的方法。通过运用Java Secure Socket Extension(JSSE),你就可以很好地解决这个问题。

在一个J2EE应用程序中,Enterprise JavaBeans(EJB)通常是位于应用程序服务器中的,而且一个Web前端是用servlets、JavaServer Pages(JSP)和标签库创建的。在大多数情况下,这些组件都位于企业防火墙的同一側,他们之间没有防火墙(见图1)。



图1. 传统的J2EE应用程序


但有时侯,防火墙会把客户端同服务器隔离开(见图2)。在一个典型的例子中,一个胖客户端(thick client)(如一个基于Swing的客户端)与一个应用程序服务器交互。(这些客户端通常用诸如Java Web Start这样的技术来安装,所以最终用户既可以得到自动化部署的好处,也可以得到一个富客户端的好处。)

这就会出现一个问题。Remote Method Invocation(RMI)是在Java Remote Methods Protocol(JRMP)、Internet Inter Orb Protocol(IIOP)、或一个如T3的私有协议上实现的。要穿越防火墙实现RMI而又不在防火墙中另外打洞,就需要我们采用一些方法。

大多数可选方法都有不足,这个问题有许多解决方法,每种方法都各有利弊。你可以尝试HTTP上的RMI信道技术。JavaSoft中的RMI带有一个缺省的HTTP信道机制。如果RMI引擎不能用JRMP联系RMI服务器,它就会开一个通道,使请求穿过HTTP并与一个可以截取这个请求的Web组件对话。

JavaSoft提供了一个CGI脚本和一个servlet,它们可以截取这些请求并将这些请求导向到适当的EJBs。然而,这种方法不支持HTTPS,所以如果需要安全的访问,你就必须实现HTTPS信道。另外,甚至连JavaSoft都说,HTTP上的RMI信道可能会让性能严重下降。



图2. 被一个防火墙隔开的客户端和服务器


第二种方法是在私有的协议上(如那些用于各种应用程序服务器中的协议)用RMI信道。例如,BEA WebLogic支持T3协议上的信道。这种方法可以部分地解决我们在HTTP上的RMI信道技术中提到的性能问题。然而,这会意味着应用程序可能会依赖私有扩展,这是许多Java开发人员不惜任何代价全力想去避免的。

第三种方法是在EJBs周围编写一个瘦Web层,如一个servlet。胖客户端发送一个被该servlet截取的HTTP请求,然后它与EJB层通讯,并将响应返回给客户端。这就意味着,每个请求都必须转换成一个HTTP请求并发送回来。

但是运用JSSE,你就可以很容易地在SSL上实现RMI。这种方法只需要写少量的代码,而且对于客户端来说,就好象它在JRMP或IIOP上调用一个RMI。这是服务器和客户端之间进行通讯的一个安全的通道。

它对性能的影响最小,而且这种影响通常取决于SSL过程本身。几乎所有的防火墙都允许SSL通讯的通过,而不影响防火墙,而且你不必运用私有扩展。下面我们来看看它是如何实现的。

JSSE是一组Java包,它支持安全的Internet通讯。它实现了一个Secure Sockets Layer(SSL)的Java版本和Transport Layer Security(TLS)协议,并包括数据加密、服务器验证、消息完整性和可选的客户端验证功能。通过运用JSSE,你就可以在服务器和客户端之间提供安全的数据通道。

第一步:安全套接库

缺省情况下,RMI运用JRMP。EJB规范中提到它支持IIOP以及JRMP上的RMI。应用程序服务器的供应商负责提供对根本协议的支持。但是运用JSSE,你就可以覆盖这个层并用SSL替代它。

第一步是实现安全套接库(secure socket libraries)。你可以在JavaSoft的Java Development Kit(JDK)文件包中找到这些类。实现这个套接库的类是RMISSLServerSocketFactory.java和RMISSLClientSocketFactory.java。现在,我们来看看实现这些安全套接库的代码。

创建一个SSL server socket,并返回它让J2EE容器使用(见列表1)。通过运用JDK中捆绑的keytool就生成了keystore。该文件作为testkeys存储,可以访问该socket。这个文件必须可以在包含套接库的.jar文件的根目录中找到,而且可以从该位置下载key store。



SSLClientSocketfactory的代码更简单(见列表2)。客户端在服务器监听的端口中创建一个SSLSocket。JSSE自动处理其它事宜。

列表2. SSLClientSocketFactory 的代码更简单。客户端在服务器监听的端口中创建了一个SSLSocket。JSSE包自动处理其它事宜。



第二步:实现你的EJBs

照常实现你的EJBs。编写远程接口、home接口和bean。注意,你不必在此做任何特殊的安全套接扩展。查看一下ejb-jar.xml部署描述符,你可以看到这是普通的代码,没有特殊的扩展。

第三步:通知容器

最后一步是要让容器知道EJB应该用自定义的安全套接库,而不是缺省的套接库(通常是JRMP、IIOP和T3)。不幸的是,这并不是在EJB规范中指定的一个标准的特征,所以它必须在供应商特定的部署描述符中说明。

例如,所附的代码样例中显示了如何在Jboss(一个开放的应用程序服务器)中指定它。但是通过改变应用程序服务器特定的部署描述符文件,你就可以很容易地将它用于任何应用程序服务器中。

通过这些简单的步骤,我们就可以很容易地穿越防火墙安全地访问EJBs了,而不用在防火墙中打更多的洞。同时,性能也不会受影响。在人们的安全意识不断提高的情况下,这的确是个很好的方法。

 

 

版权所有:UML软件工程组织