2011-09-29 143 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(); 

这将保存更改。