Java DOM appendChild:名称空间和签名文档

时间:2014-07-18 20:58:43

标签: java xml jaxb xml-dsig

我在生成带有签名节点的文档时遇到问题。我有一堆文本格式的签名XML。它们的签名是有效的,我已经用xmlsec1对它进行了测试。我必须加载所有XML并将它们放在另一个XML文档中,以便将其发送到另一个服务。 所以,首先我创建容器文档(" sobre"是一个局部变量,一个JAXB根元素):

JAXBContext context = JAXBContext.newInstance("org.importe.test");
StringWriter writer = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(sobre, writer);
String xml = writer.toString();
Document doc = loadXMLFromString(xml);

然后我将XML添加到容器中:

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>

但是当容器文档中导入节点时,它会被修改(实际上我已经注意到它没有松散的命名空间声明):

<?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>

如何在保留命名空间声明的容器中添加节点?更一般地说,我可以添加它确保它已添加&#34;原样是#34;,没有任何修改? (我使用glassfish 4和Java 7)

谢谢

编辑:

这是loadXMLFromString:

的代码
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)));
}

1 个答案:

答案 0 :(得分:0)

好的,我做过研究,我发现了问题:

  • 如果我使用xalan-2.7.1.jar,xercesImpl-2.9.1.jar,xml-apis-1.3.04.jar和xmlsec-1.5.6.jar进行DOM和XML安全实现,它就像我一样工作expect:添加节点不会修改内容,因此数字签名有效;
  • 如果我使用标准的java库,不仅添加节点会改变节点本身,但有时数字签名不会通过xmlsec1检查,我想象从DOM到String的转换中存在问题。

我希望这可以帮助某人,无论如何我不知道为什么会发生这种情况,我确信我不是在做奇怪的事情,但我现在没有时间去深入了。

实际上我很难找到告诉glassfish如何加载我想要的DOM实现,或者设置优先级:我发现没办法说“加载xerces而不是标准库”。