2011-09-29 138 views
21

我想編寫一個JAX-WS Web服務,使用http://www.w3.org/TR/xmldsig-core/推薦標記我的SOAP消息。簽名JAX-WS SOAP請求

與我在因特網上發現我寫的是設法改變SOAP請求副本的JAX-WS處理程序(SOAPHandler<SOAPMessageContext>):

@Override 
public boolean handleMessage(SOAPMessageContext smc) { 
    Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
    SOAPMessage message = smc.getMessage(); 

    if (outboundProperty) { 
     try { 
      SOAPPart soapPart = message.getSOAPPart(); 
      SOAPEnvelope soapEnvelope = soapPart.getEnvelope(); 

      Source source = soapPart.getContent(); 

      Node root = null; 
      Document doc22 = null; 
      if (source instanceof DOMSource) { 
       root = ((DOMSource) source).getNode(); 
      } else if (source instanceof SAXSource) { 
       InputSource inSource = ((SAXSource) source).getInputSource(); 
       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
       dbf.setNamespaceAware(true); 
       DocumentBuilder db = null; 

       db = dbf.newDocumentBuilder(); 

       doc22 = db.parse(inSource); 
       root = (Node) doc22.getDocumentElement(); 
      } 

      XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 

      Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), 
        Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), 
        null, null); 

      SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, 
        (C14NMethodParameterSpec) null), 
        fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
        Collections.singletonList(ref)); 

      // Load the KeyStore and get the signing key and certificate. 
      KeyStore ks = KeyStore.getInstance("JKS"); 
      ks.load(new FileInputStream("client_keystore.jks"), "changeit".toCharArray()); 
      KeyStore.PrivateKeyEntry keyEntry = 
        (KeyStore.PrivateKeyEntry) ks.getEntry("client", new KeyStore.PasswordProtection("changeit".toCharArray())); 
      X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); 
      // Create the KeyInfo containing the X509Data. 
      KeyInfoFactory kif2 = fac.getKeyInfoFactory(); 
      List x509Content = new ArrayList(); 
      x509Content.add(cert.getSubjectX500Principal().getName()); 
      x509Content.add(cert); 
      X509Data xd = kif2.newX509Data(x509Content); 
      KeyInfo ki = kif2.newKeyInfo(Collections.singletonList(xd)); 

      Element header = getFirstChildElement(root/*.getDocumentElement()*/); 
      DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), header /*doc.getDocumentElement()*/); 

      XMLSignature signature = fac.newXMLSignature(si, ki); 

      signature.sign(dsc); 

      //TODO: change this to update the SOAP message, not write it to disks 
      OutputStream os = new FileOutputStream("out.xml"); 
      TransformerFactory tf = TransformerFactory.newInstance(); 
      Transformer trans = tf.newTransformer(); 
      trans.transform(new DOMSource(root), new StreamResult(os)); 

     } catch (Exception ex) { 
      System.out.println(ex); 
     } 
    } 

    return true; 
} 

但我無法弄清楚如何更新SOAP請求?

+0

請問soapPart.setContent(新的DOMSource(root))不起作用嗎?我只是猜測,我自己沒有做過。 –

+0

不幸的是,這清空了波特和標題元素。不過謝謝您的期待! – AndrewBourgeois

+0

你有沒有找到解決這個問題呢?我很好奇,因爲我打算做類似的事情 –

回答

6

最簡單的方法是使用集成在應用程序服務器中的功能。例如:Securing JAX-WS Web services using message-level security with WebSphere App Server

如何在WAS上配置簽名,您可以找到here

這裏是WebLogic documentation about Configuring Message-Level Security

+0

這是關於簽名,而不是一般的固定,這是很好理解。也許你可以提供更詳細的鏈接和/或示例? –

+0

@LukasEder:消息級安全性也是指簽名。在此頁面上,您還可以找到指向簽名配置的鏈接。我現在將其添加到響應中。 – zacheusz

+1

非常好。特別是第二個環節!非常感謝 –

6

我爲Soap Request的Xml Digital Signature開發了一個SOAPHandler。

public class SOAPSecurityHandler implements 
     LogicalHandler<LogicalMessageContext> { 

    static final String KEYSTORE_FILE = "keystore_name.jks"; 
    static final String KEYSTORE_INSTANCE = "JKS"; 
    static final String KEYSTORE_PWD = "123456"; 
    static final String KEYSTORE_ALIAS = "keystore"; 

    public Set<QName> getHeaders() { 
     return Collections.emptySet(); 
    } 

    @Override 
    public boolean handleMessage(LogicalMessageContext smc) { 
     Boolean outboundProperty = (Boolean) smc 
       .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 

     try { 

      if (outboundProperty) { 

       Source source = smc.getMessage().getPayload(); 

       Node root = null; 

       root = ((DOMSource) source).getNode(); 

       XMLSignatureFactory fac = XMLSignatureFactory 
         .getInstance("DOM"); 

       Reference ref = fac.newReference("", fac.newDigestMethod(
         DigestMethod.SHA1, null), Collections.singletonList(fac 
         .newTransform(Transform.ENVELOPED, 
           (TransformParameterSpec) null)), null, null); 

       SignedInfo si = fac.newSignedInfo(fac 
         .newCanonicalizationMethod(
           CanonicalizationMethod.INCLUSIVE, 
           (C14NMethodParameterSpec) null), fac 
         .newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
         Collections.singletonList(ref)); 

       // Load the KeyStore and get the signing key and certificate. 
       KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE); 
       ks.load(new FileInputStream(KEYSTORE_FILE), 
         KEYSTORE_PWD.toCharArray()); 
       KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks 
         .getEntry(
           KEYSTORE_ALIAS, 
           new KeyStore.PasswordProtection(KEYSTORE_PWD 
             .toCharArray())); 
       X509Certificate cert = (X509Certificate) keyEntry 
         .getCertificate(); 
       // Create the KeyInfo containing the X509Data. 
       KeyInfoFactory kif2 = fac.getKeyInfoFactory(); 
       List x509Content = new ArrayList(); 
       x509Content.add(cert.getSubjectX500Principal().getName()); 
       x509Content.add(cert); 
       X509Data xd = kif2.newX509Data(x509Content); 
       KeyInfo ki = kif2.newKeyInfo(Collections.singletonList(xd)); 

       Element header = DOMUtils.getFirstChildElement(root); 
       DOMSignContext dsc = new DOMSignContext(
         keyEntry.getPrivateKey(), header); 

       XMLSignature signature = fac.newXMLSignature(si, ki); 

       signature.sign(dsc); 

      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return true; 

    } 

    public boolean handleFault(SOAPMessageContext smc) { 
     // addDigitalSignature(smc); 
     return true; 
    } 

    // nothing to clean up 
    public void close(MessageContext messageContext) { 
    } 

    @Override 
    public boolean handleFault(LogicalMessageContext arg0) { 
     // TODO Auto-generated method stub 
     return false; 
    } 

} 

我認爲@AndrewBourgeois代碼中的問題是獲取Source的方式。

問候,

+0

DomUtils的邏輯在哪裏? – lordoku

1

您可以嘗試soapPart.saveChanges();

0

的代碼行後:

signature.sign(dsc); 

插入這樣的說法:

soapMsg.saveChanges(); 

這將保存更改。