diff --git a/README.md b/README.md
index e4aafa72..f806e017 100644
--- a/README.md
+++ b/README.md
@@ -204,6 +204,7 @@ To sign xml documents:
- `prefix` - adds this value as a prefix for the generated signature tags
- `attrs` - a hash of attributes and values `attrName: value` to add to the signature root node
- `location` - customize the location of the signature, pass an object with a `reference` key which should contain a XPath expression to a reference node, an `action` key which should contain one of the following values: `append`, `prepend`, `before`, `after`
+ - `existingPrefixes` - A hash of prefixes and namespaces `prefix: namespace` that shouldn't be in the signature because they already exist in the xml
- `getSignedXml()` - returns the original xml document with the signature in it, **must be called only after `computeSignature`**
- `getSignatureXml()` - returns just the signature part, **must be called only after `computeSignature`**
- `getOriginalXmlWithIds()` - returns the original xml with Id attributes added on relevant elements (required for validation), **must be called only after `computeSignature`**
diff --git a/lib/signed-xml.js b/lib/signed-xml.js
index 08d828bb..bd14cfc6 100644
--- a/lib/signed-xml.js
+++ b/lib/signed-xml.js
@@ -661,6 +661,7 @@ SignedXml.prototype.addReference = function(xpath, transforms, digestAlgorithm,
* - `prefix` {String} Adds a prefix for the generated signature tags
* - `attrs` {Object} A hash of attributes and values `attrName: value` to add to the signature root node
* - `location` {{ reference: String, action: String }}
+ * - `existingPrefixes` {Object} A hash of prefixes and namespaces `prefix: namespace` already in the xml
* An object with a `reference` key which should
* contain a XPath expression, an `action` key which
* should contain one of the following values:
@@ -682,6 +683,7 @@ SignedXml.prototype.computeSignature = function(xml, opts) {
prefix = opts.prefix;
attrs = opts.attrs || {};
location = opts.location || {};
+ existingPrefixes = opts.existingPrefixes || {};
// defaults to the root node
location.reference = location.reference || "/*";
// defaults to append action
@@ -719,7 +721,16 @@ SignedXml.prototype.computeSignature = function(xml, opts) {
this.originalXmlWithIds = doc.toString()
- var signatureDoc = new Dom().parseFromString(this.signatureXml)
+ var existingPrefixesString = ""
+ Object.keys(existingPrefixes).forEach(function(key) {
+ existingPrefixesString += "xmlns:" + key + '="' + existingPrefixes[key] + '" '
+ });
+
+ // A trick to remove the namespaces that already exist in the xml
+ // This only works if the prefix and namespace match with those in te xml
+ var dummySignatureWrapper = "" + this.signatureXml + ""
+ var xml = new Dom().parseFromString(dummySignatureWrapper)
+ var signatureDoc = xml.documentElement.firstChild;
var referenceNode = xpath.select(location.reference, doc);
@@ -730,13 +741,13 @@ SignedXml.prototype.computeSignature = function(xml, opts) {
referenceNode = referenceNode[0];
if (location.action === "append") {
- referenceNode.appendChild(signatureDoc.documentElement);
+ referenceNode.appendChild(signatureDoc);
} else if (location.action === "prepend") {
- referenceNode.insertBefore(signatureDoc.documentElement, referenceNode.firstChild);
+ referenceNode.insertBefore(signatureDoc, referenceNode.firstChild);
} else if (location.action === "before") {
- referenceNode.parentNode.insertBefore(signatureDoc.documentElement, referenceNode);
+ referenceNode.parentNode.insertBefore(signatureDoc, referenceNode);
} else if (location.action === "after") {
- referenceNode.parentNode.insertBefore(signatureDoc.documentElement, referenceNode.nextSibling);
+ referenceNode.parentNode.insertBefore(signatureDoc, referenceNode.nextSibling);
}
this.signedXml = doc.toString()
diff --git a/test/signature-unit-tests.js b/test/signature-unit-tests.js
index dff41c29..0a7dc343 100644
--- a/test/signature-unit-tests.js
+++ b/test/signature-unit-tests.js
@@ -539,6 +539,49 @@ module.exports = {
test.ok(!(err instanceof TypeError));
}
test.done();
+ },
+
+ "signer adds existing prefixes": function(test) {
+ function AssertionKeyInfo(assertionId) {
+ this.getKeyInfo = function(key, prefix) {
+ return ' ' +
+ ''+assertionId+''
+ '';
+ };
+ }
+
+ var xml =
+ ' ' +
+ ' ' +
+ ' ' +
+ ' '+
+ ' '+
+ ' '+
+ ''
+
+ var sig = new SignedXml();
+ sig.keyInfoProvider = new AssertionKeyInfo(
+ "_81d5fba5c807be9e9cf60c58566349b1"
+ );
+ sig.signingKey = fs.readFileSync("./test/static/client.pem");
+ sig.computeSignature(xml, {
+ prefix: "ds",
+ location: {
+ reference: "//Assertion",
+ action: "after"
+ },
+ existingPrefixes: {
+ wsse: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
+ wsu: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+ }
+ });
+ result = sig.getSignedXml();
+ test.equal((result.match(/xmlns:wsu=/g) || []).length, 1)
+ test.equal((result.match(/xmlns:wsse=/g) || []).length, 1)
+ test.done();
}
}