One way to do this is as follows:
Step 1 - get the signature XML as a string.
Change the sample GenDetached
code in your link as follows, so that the output is a string.
The following changes are made at the bottom of the class:
// output the resulting document
OutputStream os = System.out;
//if (args.length > 0) {
// os = new FileOutputStream(args[0]);
//} else {
// os = System.out;
//}
// my changes, to write to a string:
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
StringWriter writer = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(writer));
return writer.toString();
Also change the method signature so it returns a string - for example:
public class GenDetached {
public static String generate() throws Exception {
// code not shown
}
}
Step 2 - Add the signature data to your target XML document.
Assume we have the following target doc:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<data>all your data in here...</data>
</root>
The following code extracts the <Signature>
node from the signature XML and adds it as a child of the <root>
node in your document:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.StringReader;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
...
String signatureXml = GenDetached.generate();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// My test document to hold the data and the signature:
String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><root><data>foo</data></root>";
Document doc = db.parse(new InputSource(new StringReader(xmlString)));
Node docRootNode = doc.getFirstChild();
Document sig = db.parse(new InputSource(new StringReader(signatureXml)));
NodeList sigNodeList = sig.getElementsByTagName("Signature");
Node sigNode = sigNodeList.item(0);
// First import the signature node into the main document:
Node docImportedNode = doc.importNode(sigNode, true);
// Then add the signature node to the main document's root:
docRootNode.appendChild(docImportedNode);
// Show the output (as a String in this case, for the demo):
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(writer));
System.out.println(writer.toString());
The result is this (details omitted):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<data>foo</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
...
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>
<KeyValue>
<DSAKeyValue>
...
</DSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</root>
Hope that helps.
Small point about the "internally detached" terminology in the question (courtesy of Wikipedia):
An XML signature used to sign a resource outside its containing XML document is called a detached signature; if it is used to sign some part of its containing document, it is called an enveloped signature.
I assume this example is the latter.