签署JAX-WS SOAP请求

我想编写一个JAX-WS Web服务,使用http://www.w3.org/TR/xmldsig-core/建议来签署我的SOAP消息。

通过我在互联网上找到的内容,我编写了一个JAX-WS处理程序( SOAPHandler ),它可以管理更改SOAP请求的副本:

 @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请求?

最简单的方法是使用集成在应用程序服务器中的function。 例如: 使用WebSphere App Server的消息级安全性保护JAX-WS Web服务

如何在WAS上配置签名,您可以在此处找到。

以下是有关配置消息级安全性的WebLogic文档 。

我开发了一个SOAPHandler用于Xml数字签名的肥皂请求。

 public class SOAPSecurityHandler implements LogicalHandler { 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 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的方式。

问候,

你可以试试soapPart.saveChanges();

代码行之后:

 signature.sign(dsc); 

插入此声明:

 soapMsg.saveChanges(); 

它会保存您的更改。