四、使用WS-Security規範對信息進行加密與身份認證
我們打算用Handler結合WSSecurity實現Web服務安全(Handler的有關內容請參閱AXIS學習筆記(二))
設想流程:用WSClientRequestHandler.java位於客戶端對客戶端發出的XML文檔進行加密
WSServerRequestHandler.java位於服務器端對客戶端發出的加密後的XML文檔進行解密
WSServerResponseHandler.java位於服務器端對服務器端返回的XML文檔進行加密
WSClientResponseHandler.java位於客戶端對服務器端返回的XML文檔進行解密
1、使用ISNetworks安全提供者,ISNetworks實現了RSA加密、解密算法。
當然,你也可以使用其它的安全提供者,並且可以使用不同的加密算法。
ISNetworks相關包ISNetworksProvider.jar。拷貝到%TOMCAT_HOME% //webapps//axis//WEB-INF//lib
2、Trust Services Integration Kit提供了一個WS-Security實現。你可以從http://www.xmltrustcenter.org獲得相關庫文件,分別是ws-security.jar和tsik.jar。ws-security.jar中包含一個WSSecurity類,我們使用它來對XML進行數字簽名和驗證,加密與解密。同樣拷貝到%TOMCAT_HOME%//webapps//axis//WEB-INF//lib
3、創建密匙庫和信任庫。(見上文,一模一樣!)
4、框架結構
WSClientHandler.java //基類,包含了一些公用方法
WSClientRequestHandler.java //繼承於WSClientHandler.java,調用WSHelper.java對客戶端發出的XML文檔進行加密
WSClientResponseHandler.java //繼承於WSClientHandler.java,調用WSHelper.java對服務器端返回的XML文檔進行解密
WSServerHandler.java //基類,包含了一些公用方法
WSServerRequestHandler.java //繼承於WSServerHandler.java,調用WSHelper.java對客戶端發出的加密後的XML文檔進行解密
WSServerResponseHandler.java//繼承於WSServerHandler.java,調用WSHelper.java對服務器端返回的XML文檔進行加密
WSHelper.java //核心類,對SOAP消息簽名、加密、解密、身份驗證
MessageConverter.java //幫助類,Document、SOAP消息互相轉換
5、具體分析(在此強烈建議看一下tsik.jar的API)
WSHelper.java
public class WSHelper {
static String PROVIDER=ISNetworks;//JSSE安全提供者。
//添加JSSE安全提供者,你也可以使用其它安全提供者。只要支持DESede算法。這是程序裏動態加載還可以在JDK中靜態加載
static
{
java.security.Security.addProvider(new com.isnetworks.provider.jce.ISNetworksProvider());
}
/**
*對XML文檔進行數字簽名。
*/
public static void sign(Document doc, String keystore, String storetype,
String storepass, String alias, String keypass) throws Exception {
FileInputStream fileInputStream = new FileInputStream(keystore);
java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
keyStore.load(fileInputStream, storepass.toCharArray());
PrivateKey key = (PrivateKey)keyStore.getKey(alias, keypass.toCharArray());
X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
SigningKey sk = SigningKeyFactory.makeSigningKey(key);
KeyInfo ki = new KeyInfo();
ki.setCertificate(cert);
WSSecurity wSSecurity = new WSSecurity();//ws-security.jar中包含的WSSecurity類
wSSecurity.sign(doc, sk, ki);//簽名。
}
/**
*對XML文檔進行身份驗證。
*/
public static boolean verify(Document doc, String keystore, String storetype,
String storepass) throws Exception {
FileInputStream fileInputStream = new FileInputStream(keystore);
java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
keyStore.load(fileInputStream, storepass.toCharArray());
TrustVerifier verifier = new X509TrustVerifier(keyStore);
WSSecurity wSSecurity = new WSSecurity();
MessageValidity[] resa = wSSecurity.verify(doc, verifier, null,null);
if (resa.length > 0)
return resa[0].isValid();
return false;
}
/**
*對XML文檔進行加密。必須有JSSE提供者才能加密。
*/
public static void encrypt(Document doc, String keystore, String storetype,
String storepass, String alias) throws Exception {
try
{
FileInputStream fileInputStream = new FileInputStream(keystore);
java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
keyStore.load(fileInputStream, storepass.toCharArray());
X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
PublicKey pubk = cert.getPublicKey();
KeyGenerator keyGenerator = KeyGenerator.getInstance(DESede,PROVIDER);
keyGenerator.init(168, new SecureRandom());
SecretKey key = keyGenerator.generateKey();
KeyInfo ki = new KeyInfo();
ki.setCertificate(cert);
WSSecurity wSSecurity = new WSSecurity();
//加密。
wSSecurity.encrypt(doc, key, AlgorithmType.TRIPLEDES, pubk, AlgorithmType.RSA1_5, ki);
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
*對文檔進行解密。
*/
public static void decrypt(Document doc, String keystore, String storetype,
String storepass, String alias, String keypass) throws Exception {
FileInputStream fileInputStream = new FileInputStream(keystore);
java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
keyStore.load(fileInputStream, storepass.toCharArray());
PrivateKey prvk2 = (PrivateKey)keyStore.getKey(alias, keypass.toCharArray());
WSSecurity wSSecurity = new WSSecurity();
//解密。
wSSecurity.decrypt(doc, prvk2, null);
WsUtils.removeEncryptedKey(doc);//從 WS-Security Header中刪除 EncryptedKey 元素
}
public static void removeWSSElements(Document doc) throws Exception {
WsUtils.removeWSSElements(doc);// 刪除WSS相關的元素。
}
}
WSClientHandler.java
//繼承自org.apache.axis.handlers.BasicHandler即AXIS內在的
public class WSClientHandler extends BasicHandler{
protected String keyStoreFile ;
protected String keyStoreType =JKS;//默認
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = JKS;//默認
protected String trustStorePassword ;
protected String certAlias ;
public void setInitialization(String keyStoreFile,String keyStoreType,String keyStorePassword,
String keyAlias,String keyEntryPassword,String trustStoreFile,
String trustStoreType,String trustStorePassword,String certAlias){
this.keyStoreFile=keyStoreFile;
this.keyStoreType=keyStoreType;
this.keyStorePassword=keyStorePassword;
this.keyAlias=keyAlias;
this.keyEntryPassword=keyEntryPassword;
this.trustStoreFile=trustStoreFile;
this.trustStoreType=trustStoreType;
this.trustStorePassword=trustStorePassword;
this.certAlias=certAlias;
}
public void setInitialization(String keyStoreFile,String keyStorePassword,
String keyAlias,String keyEntryPassword,String trustStoreFile,
String trustStorePassword,String certAlias){
this.keyStoreFile=keyStoreFile;
this.keyStorePassword=keyStorePassword;
this.keyAlias=keyAlias;
this.keyEntryPassword=keyEntryPassword;
this.trustStoreFile=trustStoreFile;
this.trustStorePassword=trustStorePassword;
this.certAlias=certAlias;
}
public void invoke(MessageContext messageContext) throws AxisFault {//在這個方法裏對XML文檔進行處理
//do nothing now!
}
public void onFault(MessageContext msgContext) {
System.out.println(處理錯誤,這裏忽略!);
}
}
WSClientRequestHandler.java
public class WSClientRequestHandler extends WSClientHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
try {
SOAPMessage soapMessage = messageContext.getMessage();
Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage); //soapMessage轉換爲Document
WSHelper.sign(doc, keyStoreFile, keyStoreType,keyStorePassword, keyAlias, keyEntryPassword); //數字簽名
WSHelper.encrypt(doc, trustStoreFile, trustStoreType, trustStorePassword, certAlias); //加密
soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc);
//處理後的Document再轉換回soapMessage
messageContext.setMessage(soapMessage);
} catch (Exception e){
System.err.println(在處理響應時發生以下錯誤: + e);
e.printStackTrace(); }
}
}
WSClientResponseHandler.java
public class WSClientResponseHandler extends WSClientHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
try {
SOAPMessage soapMessage = messageContext.getCurrentMessage();
Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage);
WSHelper.decrypt(doc, keyStoreFile, keyStoreType,
keyStorePassword, keyAlias, keyEntryPassword);//解密
WSHelper.verify(doc, trustStoreFile, trustStoreType, trustStorePassword);//驗證
WSHelper.removeWSSElements(doc);
soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc);
messageContext.setMessage(soapMessage);
} catch (Exception e){
e.printStackTrace();
System.err.println(在處理響應時發生以下錯誤: + e);
}
}
}
WSServerHandler.java
public class WSServerHandler extends BasicHandler{
protected String keyStoreFile ;
protected String keyStoreType =JKS;//默認
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = JKS;//默認
protected String trustStorePassword ;
protected String certAlias ;
public void invoke(MessageContext messageContext) throws AxisFault {
//do nothing now!
}
public void onFault(MessageContext msgContext) {
System.out.println(處理錯誤,這裏忽略!);
}
public void init() { //初始化,從配置文件server-config.wsdd中讀取屬性
keyStoreFile = (String)getOption(keyStoreFile);
if(( keyStoreFile== null) )
System.err.println(Please keyStoreFile configured for the Handler!);
trustStoreFile = (String)getOption(trustStoreFile);
if(( trustStoreFile== null) )
System.err.println(Please trustStoreFile configured for the Handler!);
keyStorePassword = (String)getOption(keyStorePassword);
if(( keyStorePassword== null) )
System.err.println(Please keyStorePassword configured for the Handler!);
keyAlias = (String)getOption(keyAlias);
if(( keyAlias== null) )
System.err.println(Please keyAlias configured for the Handler!);
keyEntryPassword = (String)getOption(keyEntryPassword);
if(( keyEntryPassword== null) )
System.err.println(Please keyEntryPassword configured for the Handler!);
trustStorePassword = (String)getOption(trustStorePassword);
if(( trustStorePassword== null) )
System.err.println(Please trustStorePassword configured for the Handler!);
certAlias = (String)getOption(certAlias);
if ((certAlias==null))
System.err.println(Please certAlias configured for the Handler!);
if ((getOption(keyStoreType)) != null)
keyStoreType = (String)getOption(keyStoreType);
if ((getOption(trustStoreType)) != null)
trustStoreType = (String)getOption(trustStoreType);
}
}
WSServerRequestHandler.java
public class WSServerRequestHandler extends WSServerHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
try {
SOAPMessage msg = messageContext.getCurrentMessage();
Document doc = MessageConverter.convertSoapMessageToDocument(msg);
System.out.println(接收的原始消息:);
msg.writeTo(System.out);
WSHelper.decrypt(doc, keyStoreFile, keyStoreType,
keyStorePassword, keyAlias, keyEntryPassword);//解密
WSHelper.verify(doc, trustStoreFile, trustStoreType, trustStorePassword);//驗證
WSHelper.removeWSSElements(doc);
msg = MessageConverter.convertDocumentToSOAPMessage(doc);
System.out.println(懷原後的原始消息:);
msg.writeTo(System.out);
messageContext.setMessage(msg);
} catch (Exception e){
e.printStackTrace();
System.err.println(在處理響應時發生以下錯誤: + e);
}
}
}
WSServerResponseHandler.java
public class WSServerResponseHandler extends WSServerHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
try {
SOAPMessage soapMessage = messageContext.getMessage();
System.out.println(返回的原始消息:);
soapMessage.writeTo(System.out);
Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage);
WSHelper.sign(doc, keyStoreFile, keyStoreType,
keyStorePassword, keyAlias, keyEntryPassword);//數字簽名
WSHelper.encrypt(doc, trustStoreFile, trustStoreType,//加密
trustStorePassword, certAlias);
soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc);
System.out.println(返回的加密後的消息:);
soapMessage.writeTo(System.out);
messageContext.setMessage(soapMessage);
} catch (Exception e){
System.err.println(在處理響應時發生以下錯誤: + e);
e.printStackTrace();
}
}
}
6、應用
爲方便使用,把上述文件打包爲ws-axis.jar,放入%TOMCAT_HOME%//webapps//axis//WEB-INF//lib
1)把HelloWorld重新部署一次,在server-config.wsdd中修改如下部署代碼。
<service name=HelloWorld provider=java:RPC>
<parameter name=allowedMethods value=*/>
<parameter name=className value=HelloWorld/>
<requestFlow>
<handler type=soapmonitor/>
<handler type=java:com.ronghao.WSAxis.WSServerRequestHandler>
<parameter name=keyStoreFile value=f://server.keystore/>
<parameter name=trustStoreFile value=f://server.truststore/>
<parameter name=keyStorePassword value=changeit/>
<parameter name=keyAlias value=Server/>
<parameter name=keyEntryPassword value=changeit/>
<parameter name=trustStorePassword value=changeit/>
<parameter name=certAlias value=clientkey/>
</handler>
</requestFlow>
<responseFlow>
<handler type=soapmonitor/>
<handler type=java:com.ronghao.WSAxis.WSServerResponseHandler>
<parameter name=keyStoreFile value=f://server.keystore/>
<parameter name=trustStoreFile value=f://server.truststore/>
<parameter name=keyStorePassword value=changeit/>
<parameter name=keyAlias value=Server/>
<parameter name=keyEntryPassword value=changeit/>
<parameter name=trustStorePassword value=changeit/>
<parameter name=certAlias value=clientkey/>
</handler>
</responseFlow>
</service>
2)修改客戶端程序 TestClient.java(修改的部分已標出,記着導入ws-axis.jar)
import javax.xml.namespace.QName;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import com.ronghao.WSAxis.*;
public class WSSClient1
{
public static void main(String [] args)
{
try {
//服務端的url,需要根據情況更改。
String endpointURL = http://localhost:8080/axis/services/HelloWorld;
Service svc = new Service();
WSClientHandler handler=new WSClientRequestHandler();
//注意新加的HANDLER
handler.setInitialization(f:/client.keystore,changeit,Client,changeit,
f:/client.truststore,changeit,serverkey);//初始化
WSClientHandler handlee=new WSClientResponseHandler();
//注意新加的HANDLER
handlee.setInitialization(f:/client.keystore,changeit,Client,changeit,
f:/client.truststore,changeit,serverkey);//初始化
Call call =(Call)svc.createCall();
call.setClientHandlers(handler,handlee);//添加Handler
call.setTargetEndpointAddress(new java.net.URL(endpointURL));
call.setOperationName(new QName(sayHello));
String result = (String) call.invoke( new Object [] {});
System.out.println(the result+result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
運行的時候http://localhost:8080/axis/SOAPMonitor中看到的請求的XML就已加密!
總結
這裏對代碼的解釋是不夠的,很多概念沒有提到。建議你最好看tsik.jar和AXIS的API深入瞭解。另外對ws-axis.jar的加解密實現打算運用apache的wss4j,相關網址http://ws.apache.org/ws-fx/wss4j/。不過這個東西也應該夠用了暫時
WS安全性(3)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
WSE2.0中X509安全令牌的使用
raylynn
2018-08-27 19:52:59
Web Service簡介
jt3056
2018-08-27 18:10:15
WebService中的方法是否允許重載
jt3056
2018-08-27 18:10:13
安卓調用WebService(ksoap2)
2B的It青年
2018-08-27 13:27:15
Web Service滿足SOA的需求
qqqcommoner
2018-08-27 12:05:56
window cmd命令行中對於空格是敏感的
autoair
2018-08-27 10:30:27
WS安全性問題(2)
autoair
2018-08-27 10:30:26
AXIS-》WS安全-》1
autoair
2018-08-27 10:30:26
慚愧,WS的時候Tomcat竟然出問題,而且自己沒能力解決
autoair
2018-08-27 10:30:08
昨天Java版被問的問題,關於WS的
autoair
2018-08-27 10:30:08
基於REST架構的Web Service設計
banleihncj
2018-08-27 10:22:40
asp.net webservice 概述與使用
zhou__zhou
2018-08-27 10:12:49
發佈JAX-Ws Web服務到Tomcat
byml
2018-08-27 07:13:35