在前面的文章中,我们实现了最简单的 AXIS 服务。现在我们一起来讨论一下 Web 服务的安全问题。
根据应用的对安全要求的级别不同,可以采用不同的方式来实现安全性,以下是目前最常用的一些实现方式(从低到高排列):
1 、 J2EE Web 应用默认的访问控制(数据是明文的);
2 、使用 axis 的 Handler 进行访问控制(数据是明文的);
3 、使用 Servlet 过滤器( Filter )进行访问控制(数据是明文的);
4 、使用 SSL/HTTPS 协议来传输(加密的数据传输协议);
5 、使用 WS-Security 规范对信息进行加密与身份认证(数据被加密传输)。
我们仅讨论第 2 、 4 、 5 种实现方式。在此之前我们先来了解一下 AXIS 自带的一个工具 SOAPMonitor 。
一、 SOAPMonitor 的使用
打开 http://localhost:8080/axis/ 进入 AXIS 的主页面,你会看见:
SOAPMonitor-[disabled by default for security reasons] ,默认状态下其是不可用的,现在我们就来激活它。
1 、到目录 %TOMCAT_HOME%\webapps\axis 下,你会找到 SOAPMonitorApplet.java ,在命令行中编译它:
javac -classpath %AXIS_HOME%\lib\axis.jar SOAPMonitorApplet.java
编译完之后你会看见目录下多了很多 CLASS 文件,它们的名字是 SOAPMonitorApplet*.class
2 、在目录 %TOMCAT_HOME%\webapps\axis\WEB-INF 下打开 server-config.wsdd 文件,将下面的两部分代码直
接加入其中相应的位置
第一部分:
< handler name = " soapmonitor " type = " java:org.apache.axis.handlers.SOAPMonitorHandler " >
< parameter name = " wsdlURL " value = " /axis/SOAPMonitorService-impl.wsdl " />
< parameter name = " namespace " value = " http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl " />
< parameter name = " serviceName " value = " SOAPMonitorService " />
< parameter name = " portName " value = " Demo " />
</ handler >
第二部分:
< service name = " SOAPMonitorService " provider = " java:RPC " >
< parameter name = " allowedMethods " value = " publishMessage " />
< parameter name = " className " value = " org.apache.axis.monitor.SOAPMonitorService " />
< parameter name = " scope " value = " Application " />
</ service >
3 、选择你要监控的服务
以上次的 HelloWorld 服务为例,在 server-config.wsdd 中你会找到这段代码
< service name = " HelloWorld " provider = " java:RPC " >
< parameter name = " allowedMethods " value = " sayHello " />
< parameter name = " className " value = " HelloWorld " />
</ service >
在这段代码中加入以下的代码:
< requestFlow >
< handler type = " soapmonitor " />
</ requestFlow >
< responseFlow >
< handler type = " soapmonitor " />
</ responseFlow >
最后的样子是:
< service name = " HelloWorld " provider = " java:RPC " >
< requestFlow >
< handler type = " soapmonitor " />
</ requestFlow >
< responseFlow >
< handler type = " soapmonitor " />
</ responseFlow >
< parameter name = " allowedMethods " value = " sayHello " />
< parameter name = " className " value = " HelloWorld " />
</ service >
这样 HelloWorld 服务就被监控了
4 、启动 Tomcat, 打开 http://localhost:8080/axis/SOAPMonitor ,你就会看到 Applet 界面,在
jbuilder2005 中运行我们上次写的客户端程序 TestClient.java 。 OK !你会在 Applet 界面看
见客户端与服务器端互发的 XML 内容,注意这里是明文!
二、使用 axis 的 Handler 进行访问控制(对安全要求不高时推荐)
axis 为 Web 服务的访问控制提供了相关的配置描述符,并且提供了一个访问控制的简单 Handler 。默认情况下,你只要在配置描述符中添加用户,然后在 Web 服务器的部署描述符中自动允许的角色即可。
1 、在 axis 的配置文件 users.lst (位于 WEB-INF 目录下)中添加一个用户,如 "ronghao1111" ,表示
用户名为 ronghao ,密码为 1111 。
2 、把例 HelloWorld 的 Web 服务重新部署(新加的部分已标出)
< service name = " HelloWorld " provider = " java:RPC " >
< requestFlow >
< handler type = " soapmonitor " />
< handler type = " Authenticate " /> // 新加的AXIS自带的Handler
</ requestFlow >
< responseFlow >
< handler type = " soapmonitor " />
</ responseFlow >
< parameter name = " allowedMethods " value = " sayHello " />
< parameter name = " allowedRoles " value = " ronghao " /> // 注意,这里是新加的部分!
< parameter name = " className " value = " HelloWorld " />
</ service >
在这个部署描述符中,指定 HelloWorld 服务只能被 ronghao 访问
3 、修改客户端程序 TestClient.java ,增加访问用户名、密码(新加的部分已标出)
TestClient.java
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.rpc.ParameterMode;
public class TestClient
{
public static void main(String [] args) throws Exception {
String endpoint = " http://localhost: " + " 8080 " + " /axis/HelloWorld " ;
Service service = new Service();
Call call = (Call) service.createCall();
call.getMessageContext().setUsername( " ronghao " ); // 用户名。
call.getMessageContext().setPassword( " 1111 " ); // 密码
call.setTargetEndpointAddress( new java.net.URL(endpoint) );
call.setOperationName( " sayHello " );
String res = (String) call.invoke( new Object[] {} );
System.out.println( res );
}
}
执行 TestClient ,能够顺利访问 Web 服务;如果修改用户名或者密码,那么就不能访问 。同样,
你在 http://localhost:8080/axis/SOAPMonitor 中看到的请求和响应的 XML 是明文!
三、使用 SSL/HTTPS 协议来传输
Web 服务也可以使用 SSL 作为传输协议。虽然 JAX-RPC 并没有强制规定是否使用 SSL 协议,但在 tomcat 下使用 HTTPS 协议。
1 、使用 JDK 自带的工具创建密匙库和信任库。
1 )通过使用以下的命令来创建服务器端的密匙库:
keytool - genkey - alias Server - keystore server.keystore - keyalg RSA
输入keystore密码: changeit
您的名字与姓氏是什么?
[Unknown]: Server
您的组织单位名称是什么?
[Unknown]: ec
您的组织名称是什么?
[Unknown]: ec
您所在的城市或区域名称是什么?
[Unknown]: beijing
您所在的州或省份名称是什么?
[Unknown]: beijing
该单位的两字母国家代码是什么
[Unknown]: CN
CN = Server, OU = ec, O = ec, L = beijing, ST = beijing, C = CN 正确吗?
[否]: y
输入 < Server > 的主密码
(如果和 keystore 密码相同,按回车):
以上命令执行完成后,将获得一个名为 server.keystore 的密匙库。
2) 生成客户端的信任库。首先输出 RSA 证书:
keytool - export - alias Server - file test_axis.cer - storepass changeit - keystore server.keystore
然后把 RSA 证书输入到一个新的信任库文件中。这个信任库被客户端使用,被用来验证服务器端的身份。
keytool - import - file test_axis.cer - storepass changeit - keystore client.truststore - alias serverkey - noprompt
以上命令执行完成后,将获得一个名为 client.truststore 的信任库。
3 )同理生成客户端的密匙库 client.keystore 和服务器端的信任库 server.truststore. 方便起见给出 .bat 文件
gen-cer-store.bat 内容如下:
set SERVER_DN = " CN=Server, OU=ec, O=ec, L=BEIJINGC, S=BEIJING, C=CN "
set CLIENT_DN = " CN=Client, OU=ec, O=ec, L=BEIJING, S=BEIJING, C=CN "
set KS_PASS =- storepass changeit
set KEYINFO =- keyalg RSA
keytool - genkey - alias Server - dname % SERVER_DN % % KS_PASS % - keystore server.keystore % KEYINFO % - keypass changeit
keytool - export - alias Server - file test_axis.cer % KS_PASS % - keystore server.keystore
keytool - import - file test_axis.cer % KS_PASS % - keystore client.truststore - alias serverkey - noprompt
keytool - genkey - alias Client - dname % CLIENT_DN % % KS_PASS % - keystore client.keystore % KEYINFO % - keypass changeit
keytool - export - alias Client - file test_axis.cer % KS_PASS % - keystore client.keystore
keytool - import - file test_axis.cer % KS_PASS % - keystore server.truststore - alias clientkey - noprompt
好的,现在我们就有了四个文件: server.keystore , server.truststore , client.keystore , client.truststore
2 、更改 Tomcat 的配置文件( server.xml ),增加以下部署描述符:(其实里面有,只是被注释掉了)
< Connector port = " 8440 "
maxThreads = " 150 " minSpareThreads = " 25 " maxSpareThreads = " 75 "
enableLookups = " false " disableUploadTimeout = " true "
acceptCount = " 100 " scheme = " https " secure = " true "
clientAuth = " true " keystoreFile = " f:\server.keystore " keystorePass = " changeit "
truststoreFile = " f:\server.truststore " truststorePass = " changeit "
sslProtocol = " TLS " />
3 、把 HelloWorld 重新部署一次,在 server-config.wsdd 中修改如下部署代码。(还原了而已)
< service name = " HelloWorld " provider = " java:RPC " >
< requestFlow >
< handler type = " soapmonitor " />
</ requestFlow >
< responseFlow >
< handler type = " soapmonitor " />
</ responseFlow >
< parameter name = " allowedMethods " value = " sayHello " />
< parameter name = " className " value = " HelloWorld " />
</ service >
4 、修改客户端程序 TestClient.java (修改的部分已标出)
public class TestClient
{
public static void main(String [] args) throws Exception {
String endpoint = " https://localhost: " + " 8440 " + " /axis/HelloWorld " ; // 注意区别在这里!https!
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new java.net.URL(endpoint) );
call.setOperationName( " sayHello " );
String res = (String) call.invoke( new Object[] {} );
System.out.println( res );
}
}
5 、最后使用命令来执行客户端程序
java - cp % AXISCLASSPATH %
- Djavax.net.ssl.keyStore = client.keystore
- Djavax.net.ssl.keyStorePassword = changeit
- Djavax.net.ssl.trustStore = client.truststore
TestClient