建立安全的AXIS服务(下)

建立安全的AXIS服务(下)

四、使用WS-Security规范对信息进行加密与身份认证
    
我们打算用Handler结合WSSecurity实现Web服务安全
    
设想流程:用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.jartsik.jarws-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  //
帮助类,DocumentSOAP消息互相转换
  
 5
、具体分析(在此强烈建议看一下tsik.jarAPI
    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/ 。不过这个东西也应该够用了暂时。



http://www.blogjava.net/ronghao 荣浩原创,转载请注明出处:)

你可能感兴趣的:(建立安全的AXIS服务(下))