Java DOM appendChild:名称空间和签名文档
生成带有签名节点的文档时遇到问题。我有一堆签名的XML,是文本格式的。他们的签名是有效的,我已经用xmlsec1测试过了。我必须加载所有XML并将它们放在另一个XML文档中,以便将其发送到另一个服务。 因此,首先我创建容器文档(“sobre”是一个局部变量,一个JAXB根元素): 然后我将XML添加到容器中:Java DOM appendChild:名称空间和签名文档,java,xml,jaxb,xml-dsig,Java,Xml,Jaxb,Xml Dsig,生成带有签名节点的文档时遇到问题。我有一堆签名的XML,是文本格式的。他们的签名是有效的,我已经用xmlsec1测试过了。我必须加载所有XML并将它们放在另一个XML文档中,以便将其发送到另一个服务。 因此,首先我创建容器文档(“sobre”是一个局部变量,一个JAXB根元素): 然后我将XML添加到容器中: for (String cfexml : cfexmls) { Document cfe = loadXMLFromString(cfexml); Node newNode = d
for (String cfexml : cfexmls) {
Document cfe = loadXMLFromString(cfexml);
Node newNode = doc.importNode(cfe.getDocumentElement(), true);
doc.getElementsByTagName("EnvioCFE").item(0).appendChild(newNode);
}
最后,我从容器文档中获取xml:
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
StringWriter outputWriter = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(outputWriter));
String signedxml = outputWriter.toString();
关键是我正在修改子节点,没有名称空间,因此提取节点的签名验证失败。下面是我必须添加为子节点的XML摘录:
<?xml version="1.0" encoding="UTF-8"?>
<CFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
<data>
[...]
</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
[...]
</Signature>
</CFE>
好的,我做了研究,发现了问题:
- 如果我使用xalan-2.7.1.jar、xercesImpl-2.9.1.jar、xml-api-1.3.04.jar和xmlsec-1.5.6.jar实现DOM和xml安全性,它的工作原理与我预期的一样:添加节点不会修改内容,因此数字签名是有效的李>
- 如果我使用标准java库,不仅是添加节点更改节点本身,而且有时数字签名没有通过xmlsec1检查,我认为从DOM到字符串的转换会出现问题
实际上,我一直在寻找如何告诉glassfish加载我想要的DOM实现,或者设置优先级:我没有找到说“加载xerces而不是标准库”的方法。您能显示
loadXMLFromString
的代码吗?我怀疑问题就在那里。特别是如果您使用的是DocumentBuilderFactory,那么默认情况下它不支持名称空间,您需要在创建DocumentBuilder之前调用setter来打开名称空间。当然,请参阅我的编辑(正如您所看到的,我使用的是setNamespaceAware)。嗯,我现在明白您的意思了。XML序列化程序从CFE元素中省略这三个名称空间声明是正确的,因为它们已经在其父元素上生效。我不知道有什么办法可以推翻这一点。我想您可以尝试在故意关闭名称空间的情况下构建DOM树,以便名称空间声明仅被视为属性。不过,如果这样做,您可能需要切换到使用DomImplementals进行序列化,而不是使用转换器,我不确定XSLT工具能否很好地处理不支持名称空间的DOM。@IanRoberts你说:“你可以尝试在故意关闭名称空间的情况下构建DOM树”,我如何才能做到这一点?
<?xml version="1.0" encoding="UTF-8"?>
<CFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
<data>
[...]
</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
[...]
</Signature>
</CFE>
<?xml version="1.0" encoding="UTF-8"?>
<EnvioCFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
<Header version="1.0">
</Header>
<CFE version="1.0">
<data>
[...]
</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
[...]
</Signature>
</CFE>
</EnvioCFE>
public Document loadXMLFromString(String xml) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(xml)));
}