签署 JAX-WS SOAP 请求
Posted
技术标签:
【中文标题】签署 JAX-WS SOAP 请求【英文标题】:Sign JAX-WS SOAP request 【发布时间】:2011-11-27 17:45:32 【问题描述】:我想编写一个 JAX-WS Web 服务,使用 http://www.w3.org/TR/xmldsig-core/ 建议对我的 SOAP 消息进行签名。
根据我在 Internet 上找到的内容,我编写了一个 JAX-WS 处理程序 (SOAPHandler<SOAPMessageContext>
),它设法更改 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 请求?
【问题讨论】:
soapPart.setContent(new DOMSource(root)) 不起作用吗?我只是猜测,我自己没有做过。 不幸的是,这会清空 bode 和 header 元素。不过,感谢您的关注! 您找到解决此问题的方法了吗?我很好奇,因为我要做类似的事情 我放弃了这个想法,但如果有人有解决方案,我仍然对解决方案感兴趣! 我的测试告诉我你不需要做任何事情,因为签名已经更新了 SOAP 消息。 【参考方案1】:代码行之后:
signature.sign(dsc);
插入此语句:
soapMsg.saveChanges();
它将保存您的更改。
【讨论】:
【参考方案2】:你可以试试soapPart.saveChanges();
【讨论】:
【参考方案3】:我为 Soap 请求的 Xml 数字签名开发了一个 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 代码中的问题是获取源代码的方式。
问候,
【讨论】:
DomUtils 的逻辑在哪里?【参考方案4】:最简单的方法是使用集成在应用服务器中的功能。例如:Securing JAX-WS Web services using message-level security with WebSphere App Server
如何在WAS上配置签名你可以找到here。
这里是WebLogic documentation about Configuring Message-Level Security。
【讨论】:
这是关于签名,而不是一般的保护,这是众所周知的。也许您可以提供更详细的链接和/或示例? @LukasEder:消息级安全性也指签名。在此页面上,您也可以找到指向签名配置的链接。我现在将其添加到响应中。 我没有时间检查这个答案的内容,但它解决了 Lukas 的问题吗?以上是关于签署 JAX-WS SOAP 请求的主要内容,如果未能解决你的问题,请参考以下文章
Java Paypal 集成 SOAP JAX-WS - SSL 握手异常