0

我在生成带有签名节点的文档时遇到问题。我有一堆以文本格式签署的 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>

如何将节点添加到保留命名空间声明的容器中?更一般地说,我可以添加它以确保它是“按原样”添加的,而不进行任何修改吗?(我正在使用 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)));
}
4

1 回答 1

0

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

  • 如果我将 xalan-2.7.1.jar、xercesImpl-2.9.1.jar、xml-apis-1.3.04.jar 和 xmlsec-1.5.6.jar 用于 DOM 和 XML 安全实现,它会按我的预期工作:添加节点不修改内容,因此数字签名有效;
  • 如果我使用标准 java 库不仅添加节点更改节点本身,而且有时数字签名没有通过 xmlsec1 检查,我想在从 DOM 到字符串的转换中出现问题。

我希望这可以帮助某人,反正我不知道为什么会这样,我确定我没有做奇怪的事情,但我现在没有时间深入。

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

于 2014-07-22T13:31:21.437 回答