posts - 0,comments - 7,trackbacks - 0
<2025年4月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

留言簿(1)

文章分类

文章档案

Favor

技术网站

相关技术文档

网友Blog

搜索

  •  

最新评论

四、使用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/。不过这个东西也应该够用了暂时。所有的源文件在附件中附件:soapTest.zip(279K) 

posted on 2007-01-31 11:30 坚持学习,每天进步一些 阅读(348) 评论(0)  编辑  收藏 所属分类: Web Service

只有注册用户登录后才能发表评论。


网站导航: