WS安全性(3)

    技术2022-05-11  152

    四、使用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/。不过这个东西也应该够用了暂时

    最新回复(0)