最近公司要把web services傳輸内容全加密用到wss4j,于是上網看了篇文章照着做沒有跑通,于是做了下修改,如下:
一、wss4j簡介
Wss4j是apache開發的,标準實作WS-Security(WebService安全)的開源項目,它提供了使用者名令牌環驗證(UsernameToken)和傳遞消息時保證資訊的完整性和真實性等一些WebService安全保障。
二、環境準備
2.1開發環境準備
在正式開始前還要去apche網站下載下傳一個rampart-1.5.mar
把這個東東放到WEB-INF\modules下去
這個東東是在AXIS2上實作WSS4J必需要的一個元件。把wss4j的相關jar包導到lib下。
三、用KEYTOOL生成一對JKS檔案
首先我們用keytool生成一對JKS檔案, service.jks和client.jks。
service.jks存放了service的私鑰和client的公鑰。
client.jks存放了client的私鑰和service的公鑰。
本人生成的
service.jks的私鑰和公鑰keystore的密碼是apache
client.jks的私鑰和公鑰keystore的密碼是apache,
(注如果不會用keytool請自己看相關資料,我用的是apache提供sample的檔案)
生成方法如下:
C:\Documents and Settings\Administrator>keytool -genkey -keyalg RSA -keysize 512
-dname "cn=service,o=qinan,c=cn" -alias service -keypass administrator -keystor
e d:/keystore/service.jks -storepass qinanehome
-dname "cn=client,o=qinan,c=cn" -alias client -keypass administrator -keystore
d:/keystore/client.jks -storepass qinanadminehome
2.2搭建webservice環境
将axis2.war包拷貝到tomcat安裝目錄下的webapps目錄下。
啟動Tomcat(D:\Tomcat5.5\bin\startup.bat),打開浏覽器輸入并通路:http://127.0.0.1:8080/axis2 來檢視,結果如下圖,表示axis2已經工作正常。
四、建立web應用
4.1 編寫伺服器端代碼
首先簡單介紹我的Wss4j實作WS-Security功能,很簡單就是用戶端發送一個字元串,伺服器端得到該字元串,同時把字元串在發送給用戶端,首先自己建立一個web應用工程, 這裡就以我的wsc應用工程為例
在src下建一個包com.neusoft.wss4j.rempart.demo.services 在這裡寫一個類SimpleService作為伺服器端
該類的内容是:
package com.neusoft.wss4j.rempart.demo.services;
public class SimpleService
{
public String echo(String arg)
{
return arg;
}
}
這個類的作用就是接收用戶端的字元串,并且把該字元串傳回給用戶端。
這裡還有個類,該類是實作UsernameToken和傳送資訊的安全性和完整性的核心,該類被配置在axis2.xml和service.xml中,進而能得到使用者配置的axis2.xml中的資訊,和伺服器端配置的service.xml的資訊。每當用戶端發送請求時,它都要首先通過該類獲得通路服務端的權限和獲得發送資料所需要的加密密碼,然後把資料加密發送給伺服器端,如果沒有權限則不能把資料發送到伺服器端,每當伺服器端想要把資料傳送到用戶端時,也要經過次類獲得發送資料所需要的加密密碼,然後把資料加密傳回給用戶端,用戶端通過解密獲得明文資訊。它的内容如下:
import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
public class PWCBHandler implements CallbackHandler
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException
{
for (int i = 0; i < callbacks.length; i++)
{
WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
String id = pwcb.getIdentifer();
if("client".equals(id))
{
pwcb.setPassword("apache");
}
else if("service".equals(id))
else
{
throw new UnsupportedCallbackException(callbacks[i],
"對不起,您不是授權使用者,不能通路該WEB服務!");
}
}
}
4.2 編寫伺服器端的描述檔案services.xml
然後寫一個解析該伺服器類services.xml檔案該檔案的内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<service name="wsc">
<operation name="echo">
<messageReceiver
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<parameter name="ServiceClass" locked="false">
com.neusoft.wss4j.rempart.demo.services.SimpleService
</parameter>
<module ref="rampart" />
<parameter name="InflowSecurity">
<action>
<items>Timestamp Signature</items>
<signaturePropFile>
keys/service.properties
</signaturePropFile>
</action>
<parameter name="OutflowSecurity">
<user>service</user>
<passwordCallbackClass>
com.neusoft.wss4j.rempart.demo.services.PWCBHandler
</passwordCallbackClass>
<signatureKeyIdentifier>
DirectReference
</signatureKeyIdentifier>
</service>
伺服器wsc中有幾個方法就需要配置幾個<operation></operation>
echo為wsc伺服器類中的方法。wsc為服務的名字也就是後邊的打包伺服器端wsc.aar的名字。着重看下紅色和粉色字型部分,紅色這部分是用戶端傳來資訊用數字簽名來解密用戶端傳過來的加密資訊本例通過keys檔案夾下的service.properties這個檔案找到service.jks對資訊進行解密,粉色部分是伺服器端把輸出向用戶端的資訊加密用的,本例通過keys檔案夾下的service.properties這個檔案找到service.jks對資訊加密的。
service.properties的内容如下:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=apache
org.apache.ws.security.crypto.merlin.file=keys/service.jks
寫明了加密檔案的類型,檔案密碼,檔案名稱。
4.3 生成.aar服務包
下邊就可以根據一個伺服器類SimpleService一個service.xml打包生成一個wsc.aar做為伺服器端的程式。首先将這個SimpleService類打包,然後把service.xml放在打包後的MATE-INFO下邊
這樣伺服器端程式wsc.aar就完成了。下邊把wsc.aar copy到D:\program\Tomcat6.0\webapps\axis2\WEB-INF\services目錄下(這裡是以我的機器做為例子的)
然後重新開機tomcat輸入
http://127.0.0.1:8080/axis2/services/listServices就可以看到我們部署到伺服器上的服務了。
4.4 編寫模拟第三方測試程式
下面我寫一個模拟第三方的程式調用webservice的一個例子
在包com.neusoft.wss4j.rempart.demo.client中的Client
它的内容如下:
package com.neusoft.wss4j.rempart.demo.client;
import java.io.Reader;
import java.io.StringReader;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
public class Client
public static void main(String[] args) throws Exception
ConfigurationContext ctx = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(
"D:/eclipse3.2/workspace/wsc/WebRoot/WEB-INF", "D:/eclipse3.2/workspace/wsc/WebRoot/WEB-INF/conf/axis2.xml");
ServiceClient client = new ServiceClient(ctx, null);
Options options = new Options();
options.setAction("urn:echo");
options.setTo(new EndpointReference(
"
http://localhost:8080/wsc/services/wsc"));
client.setOptions(options);
OMElement response = client.sendReceive(getPayload("(*^__^*) 嘻嘻……"));
OMElement element = response.getFirstElement();
//把傳回的OMElement對象轉換為 xml資料
SAXBuilder builder = new SAXBuilder();
Reader in = new StringReader(element.toString());
Document doc = null;
try
{
doc = builder.build(in);
Element Element = doc.getRootElement();
String aa = Element.getTextTrim();
System.out.println(aa);
}
catch (Exception e)
System.out.println(e.getMessage());
private static OMElement getPayload(String value)
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace ns = factory.createOMNamespace(
http://services.demo.rempart.wss4j.neusoft.com);","ns1OMElement elem = factory.createOMElement("echo", ns);
OMElement childElem = factory.createOMElement("param0", null);
childElem.setText(value);
elem.addChild(childElem);
return elem;
這個測試類就不多說了,粉色的部分是需要注意的地方。
還有個用戶端的axis2.xml需要說明一下
他的主要内容如下隻要把這部分粘貼到原來的axis2.xml即可:
<module ref="rampart" />
<parameter name="OutflowSecurity">
<items>Timestamp Signature</items>
<user>client</user>
<signaturePropFile>keys/client.properties</signaturePropFile>
<passwordCallbackClass>com.neusoft.wss4j.rempart.demo.services.PWCBHandler</passwordCallbackClass>
<signatureKeyIdentifier>DirectReference</signatureKeyIdentifier>
</parameter>
<parameter name="InflowSecurity">
注意一下紅色的部分他是當用戶端向伺服器端發送資料時,首先通路com.neusoft.wss4j.rempart.demo.services.PWCBHandler這個類,得到通路權限和加密資訊的檔案密碼,然後通過加密資訊的檔案密碼和keys/client.properties檔案找到加密需要的檔案client.jks把資訊加密發送給伺服器端,粉色部分是通過keys/client.properties檔案找到解密需要的檔案client.jks來解密伺服器端傳回的加密資訊。
Keys檔案下的client.properties内容如下:
org.apache.ws.security.crypto.merlin.file=keys/client.jks
五、總 結
整理一下思路
1 用戶端發送消息給伺服器端:如果用戶端想請求伺服器端首先讀取用戶端配置檔案axis2.xml檔案,得到通路的使用者<user>client</user>然後找到com.neusoft.wss4j.rempart.demo.services.PWCBHandler類,看使用者是否有通路服務的權限,如果有則把client.jks檔案的密碼給使用者client,client通過密碼在axis2.xml檔案中找到<signaturePropFile>keys/client.properties</signaturePropFile>找到client.properties檔案,在client.properties檔案中找到client.jks檔案,使用該檔案的client私鑰進而實作把傳送的資訊加密,然後把加密的資訊發送到伺服器端。
2 伺服器端接收用戶端發送來的消息:伺服器端接收到消息,然後讀取service.xml檔案找到<signaturePropFile>keys/service.properties</signaturePropFile>進而找到service.properties檔案,通過該檔案找到service.jks檔案使用該檔案的client的公鑰
解密用戶端傳送來的資訊。
3 伺服器端傳回資訊給用戶端: 獲得用戶端傳送過來的明文資訊後,從service.xml檔案
得到加密的使用者<user>service</user>通過
<passwordCallbackClass>
com.neusoft.wss4j.rempart.demo.services.PWCBHandler
</passwordCallbackClass>
找到驗證類PWCBHandler得到加密需要的service.jks的加密密碼apache
通過<signaturePropFile>
keys/service.properties
</signaturePropFile>找到service.properties檔案,通過該檔案找到service.jks檔案,通過該檔案的service的私鑰把需要發送給用戶端的資訊加密。然後發送給用戶端
4 用戶端接收伺服器端傳回的消息:用戶端端接收到消息,然後讀取axis2.xml檔案找到<signaturePropFile>keys/service.properties</signaturePropFile>進而找到client.properties檔案,通過該檔案找到client.jks檔案使用該檔案的service的公鑰
解密伺服器端傳回來的資訊。