Skip to content

Commit 4d72940

Browse files
RoelandLoneRifle
authored andcommitted
Accept existing xml prefixes to avoid adding to signature (#171)
1 parent f609f08 commit 4d72940

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ To sign xml documents:
204204
- `prefix` - adds this value as a prefix for the generated signature tags
205205
- `attrs` - a hash of attributes and values `attrName: value` to add to the signature root node
206206
- `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`
207+
- `existingPrefixes` - A hash of prefixes and namespaces `prefix: namespace` that shouldn't be in the signature because they already exist in the xml
207208
- `getSignedXml()` - returns the original xml document with the signature in it, **must be called only after `computeSignature`**
208209
- `getSignatureXml()` - returns just the signature part, **must be called only after `computeSignature`**
209210
- `getOriginalXmlWithIds()` - returns the original xml with Id attributes added on relevant elements (required for validation), **must be called only after `computeSignature`**

lib/signed-xml.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ SignedXml.prototype.addReference = function(xpath, transforms, digestAlgorithm,
661661
* - `prefix` {String} Adds a prefix for the generated signature tags
662662
* - `attrs` {Object} A hash of attributes and values `attrName: value` to add to the signature root node
663663
* - `location` {{ reference: String, action: String }}
664+
* - `existingPrefixes` {Object} A hash of prefixes and namespaces `prefix: namespace` already in the xml
664665
* An object with a `reference` key which should
665666
* contain a XPath expression, an `action` key which
666667
* should contain one of the following values:
@@ -682,6 +683,7 @@ SignedXml.prototype.computeSignature = function(xml, opts) {
682683
prefix = opts.prefix;
683684
attrs = opts.attrs || {};
684685
location = opts.location || {};
686+
existingPrefixes = opts.existingPrefixes || {};
685687
// defaults to the root node
686688
location.reference = location.reference || "/*";
687689
// defaults to append action
@@ -719,7 +721,16 @@ SignedXml.prototype.computeSignature = function(xml, opts) {
719721

720722
this.originalXmlWithIds = doc.toString()
721723

722-
var signatureDoc = new Dom().parseFromString(this.signatureXml)
724+
var existingPrefixesString = ""
725+
Object.keys(existingPrefixes).forEach(function(key) {
726+
existingPrefixesString += "xmlns:" + key + '="' + existingPrefixes[key] + '" '
727+
});
728+
729+
// A trick to remove the namespaces that already exist in the xml
730+
// This only works if the prefix and namespace match with those in te xml
731+
var dummySignatureWrapper = "<Dummy " + existingPrefixesString + ">" + this.signatureXml + "</Dummy>"
732+
var xml = new Dom().parseFromString(dummySignatureWrapper)
733+
var signatureDoc = xml.documentElement.firstChild;
723734

724735
var referenceNode = xpath.select(location.reference, doc);
725736

@@ -730,13 +741,13 @@ SignedXml.prototype.computeSignature = function(xml, opts) {
730741
referenceNode = referenceNode[0];
731742

732743
if (location.action === "append") {
733-
referenceNode.appendChild(signatureDoc.documentElement);
744+
referenceNode.appendChild(signatureDoc);
734745
} else if (location.action === "prepend") {
735-
referenceNode.insertBefore(signatureDoc.documentElement, referenceNode.firstChild);
746+
referenceNode.insertBefore(signatureDoc, referenceNode.firstChild);
736747
} else if (location.action === "before") {
737-
referenceNode.parentNode.insertBefore(signatureDoc.documentElement, referenceNode);
748+
referenceNode.parentNode.insertBefore(signatureDoc, referenceNode);
738749
} else if (location.action === "after") {
739-
referenceNode.parentNode.insertBefore(signatureDoc.documentElement, referenceNode.nextSibling);
750+
referenceNode.parentNode.insertBefore(signatureDoc, referenceNode.nextSibling);
740751
}
741752

742753
this.signedXml = doc.toString()

test/signature-unit-tests.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,49 @@ module.exports = {
539539
test.ok(!(err instanceof TypeError));
540540
}
541541
test.done();
542+
},
543+
544+
"signer adds existing prefixes": function(test) {
545+
function AssertionKeyInfo(assertionId) {
546+
this.getKeyInfo = function(key, prefix) {
547+
return '<wsse:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" wsu:Id="0" ' +
548+
'xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"> ' +
549+
'<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">'+assertionId+'</wsse:KeyIdentifier>'
550+
'</wsse:SecurityTokenReference>';
551+
};
552+
}
553+
554+
var xml =
555+
'<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> ' +
556+
'<SOAP-ENV:Header> ' +
557+
'<wsse:Security ' +
558+
'xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" ' +
559+
'xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> ' +
560+
'<Assertion></Assertion> '+
561+
'</wsse:Security> '+
562+
'</SOAP-ENV:Header> '+
563+
'</SOAP-ENV:Envelope>'
564+
565+
var sig = new SignedXml();
566+
sig.keyInfoProvider = new AssertionKeyInfo(
567+
"_81d5fba5c807be9e9cf60c58566349b1"
568+
);
569+
sig.signingKey = fs.readFileSync("./test/static/client.pem");
570+
sig.computeSignature(xml, {
571+
prefix: "ds",
572+
location: {
573+
reference: "//Assertion",
574+
action: "after"
575+
},
576+
existingPrefixes: {
577+
wsse: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
578+
wsu: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
579+
}
580+
});
581+
result = sig.getSignedXml();
582+
test.equal((result.match(/xmlns:wsu=/g) || []).length, 1)
583+
test.equal((result.match(/xmlns:wsse=/g) || []).length, 1)
584+
test.done();
542585
}
543586

544587
}

0 commit comments

Comments
 (0)