Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: node_js
node_js:
- 0.6

before_script:
- npm install

script: npm test
20 changes: 20 additions & 0 deletions lib/enveloped-signature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var xpath = require('./xpath');

exports.EnvelopedSignature = EnvelopedSignature;

function EnvelopedSignature() {
}

EnvelopedSignature.prototype.process = function (node) {
var signature = xpath.SelectNodes(node.ownerDocument, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];

var xml = "" + node;
var sigXml = "" + signature;

var cleaned = xml.replace(sigXml, '');
return cleaned;
};

EnvelopedSignature.prototype.getAlgorithmName = function () {
return "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
};
50 changes: 30 additions & 20 deletions lib/signed-xml.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var select = require('./xpath.js').SelectNodes
, Dom = require('xmldom').DOMParser
, utils = require('./utils')
, ExclusiveCanonicalization = require('./exclusive-canonicalization').ExclusiveCanonicalization
, EnvelopedSignature = require('./enveloped-signature').EnvelopedSignature
, crypto = require('crypto')
, fs = require('fs')

Expand Down Expand Up @@ -100,7 +101,8 @@ function SignedXml(idMode) {
}

SignedXml.CanonicalizationAlgorithms = {
'http://www.w3.org/2001/10/xml-exc-c14n#': ExclusiveCanonicalization
'http://www.w3.org/2001/10/xml-exc-c14n#': ExclusiveCanonicalization,
'http://www.w3.org/2000/09/xmldsig#enveloped-signature': EnvelopedSignature
}

SignedXml.HashAlgorithms = {
Expand All @@ -116,26 +118,28 @@ SignedXml.prototype.checkSignature = function(xml) {
this.signedXml = xml

if (!this.keyInfoProvider) {
throw "cannot validate signature since no key info resolver was provided"
throw new Error("cannot validate signature since no key info resolver was provided")
}

this.signingKey = this.keyInfoProvider.getKey(this.keyInfo)
if (!this.signingKey) throw "key info provider could not resolve key info " + this.keyInfo
if (!this.signingKey) throw new Error("key info provider could not resolve key info " + this.keyInfo)

var doc = new Dom().parseFromString(xml)

if (!this.validateReferences(doc))
return false
if (!this.validateReferences(doc)) {
return false;
}

if (!this.validateSignatureValue(doc))
return false
if (!this.validateSignatureValue(doc)) {
return false;
}

return true
}

SignedXml.prototype.validateSignatureValue = function(doc) {
var signedInfo = utils.findChilds(this.signatureXmlDoc.documentElement, "SignedInfo")
if (signedInfo.length==0) throw "could not find SignedInfo element in the message"
if (signedInfo.length==0) throw new Error("could not find SignedInfo element in the message")
var signedInfoCanon = this.getCanonXml([this.canonicalizationAlgorithm], signedInfo[0])
var signer = this.findSignatureAlgorithm(this.signatureAlgorithm)
var res = signer.verifySignature(signedInfoCanon, this.signingKey, this.signatureValue)
Expand All @@ -147,19 +151,19 @@ SignedXml.prototype.validateSignatureValue = function(doc) {
SignedXml.prototype.findSignatureAlgorithm = function(name) {
var algo = SignedXml.SignatureAlgorithms[name]
if (algo) return new algo()
else throw "signature algorithm '" + name + "' is not supported"
else throw new Error("signature algorithm '" + name + "' is not supported");
}

SignedXml.prototype.findCanonicalizationAlgorithm = function(name) {
var algo = SignedXml.CanonicalizationAlgorithms[name]
if (algo) return new algo()
else throw "canonicalization algorithm '" + name + "' is not supported"
else throw new Error("canonicalization algorithm '" + name + "' is not supported");
}

SignedXml.prototype.findHashAlgorithm = function(name) {
var algo = SignedXml.HashAlgorithms[name]
if (algo) return new algo()
else throw "hash algorithm '" + name + "' is not supported"
else throw new Error("hash algorithm '" + name + "' is not supported");
}


Expand All @@ -170,9 +174,12 @@ SignedXml.prototype.validateReferences = function(doc) {
var uri = ref.uri[0]=="#" ? ref.uri.substring(1) : ref.uri
var elem = select(doc, "//*[@*[local-name(.)='Id']='" + uri + "']")
if (elem.length==0) {
this.validationErrors.push("invalid signature: the signature refernces an element with uri "+
elem = select(doc, "//*[@*[local-name(.)='ID']='" + uri + "']")
if (elem.length==0) {
this.validationErrors.push("invalid signature: the signature refernces an element with uri "+
ref.uri + " but could not find such element in the xml")
return false
return false
}
}

var canonXml = this.getCanonXml(ref.transforms, elem[0])
Expand All @@ -196,15 +203,15 @@ SignedXml.prototype.loadSignature = function(signatureXml) {
this.signatureXmlDoc = doc

var nodes = select(doc, "//*[local-name(.)='CanonicalizationMethod']/@Algorithm")
if (nodes.length==0) throw "could not find CanonicalizationMethod/@Algorithm element"
if (nodes.length==0) throw new Error("could not find CanonicalizationMethod/@Algorithm element")
this.canonicalizationAlgorithm = nodes[0].value

this.signatureAlgorithm =
utils.findFirst(doc, "//*[local-name(.)='SignatureMethod']/@Algorithm").value

this.references = []
var references = select(doc, "//*[local-name(.)='SignedInfo']/*[local-name(.)='Reference' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")
if (references.length == 0) throw "could not find any Reference elements"
if (references.length == 0) throw new Error("could not find any Reference elements")

for (var i in references) {
this.loadReference(references[i])
Expand All @@ -222,18 +229,18 @@ SignedXml.prototype.loadSignature = function(signatureXml) {
*/
SignedXml.prototype.loadReference = function(ref) {
var nodes = utils.findChilds(ref, "DigestMethod")
if (nodes.length==0) throw "could not find DigestMethod in reference " + ref.toString()
if (nodes.length==0) throw new Error("could not find DigestMethod in reference " + ref.toString())
var digestAlgoNode = nodes[0]

var attr = utils.findAttr(digestAlgoNode, "Algorithm")
if (!attr) throw "could not find Algorithm attribute in node " + digestAlgoNode.toString()
if (!attr) throw new Error("could not find Algorithm attribute in node " + digestAlgoNode.toString())
var digestAlgo = attr.value

nodes = utils.findChilds(ref, "DigestValue")
if (nodes.length==0) throw "could not find DigestValue node in reference " + ref.toString()
if (nodes.length==0) throw new Error("could not find DigestValue node in reference " + ref.toString())
if (nodes[0].childNodes.length==0 || !nodes[0].firstChild.data)
{
throw "could not find the value of DigestValue in " + nodes[0].toString()
throw new Error("could not find the value of DigestValue in " + nodes[0].toString())
}
var digestValue = nodes[0].firstChild.data

Expand Down Expand Up @@ -358,8 +365,11 @@ SignedXml.prototype.ensureHasId = function(node) {
}
else {
attr = utils.findAttr(node, "Id", null)
if (!attr) {
attr = utils.findAttr(node, "ID", null)
}
}

if (attr) return attr.value

//add the attribute
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,8 @@
"keywords": ["xml", "digital signature", "xml encryption", "x.509 certificate"],
"licenses": [{
"type" : "MIT License",
"url" : "http://www.opensource.org/licenses/mit-license.php" }]
}
"url" : "http://www.opensource.org/licenses/mit-license.php" }],
"scripts": {
"test": "./node_modules/nodeunit/bin/nodeunit test"
}
}
15 changes: 15 additions & 0 deletions test/saml-response-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var crypto = require('../index');
var xmldom = require('xmldom');
var fs = require('fs');

exports['test validating SAML response'] = function (test) {
var xml = fs.readFileSync('./test/static/valid_saml.xml', 'utf-8');
var doc = new xmldom.DOMParser().parseFromString(xml);
var signature = crypto.xpath.SelectNodes(doc, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
var sig = new crypto.SignedXml();
sig.keyInfoProvider = new crypto.FileKeyInfo("./test/static/feide_public.pem");
sig.loadSignature(signature.toString());
var result = sig.checkSignature(xml);
test.equal(result, true);
test.done();
};
6 changes: 5 additions & 1 deletion test/signature-integration-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ module.exports = {
}

function verifySignature(test, xml, xpath) {
if (process.platform !== 'win32') {
test.done();
return;
}
var sig = new SignedXml()
sig.signingKey = fs.readFileSync("./test/static/client.pem")
sig.keyInfoCaluse = null
Expand Down Expand Up @@ -57,4 +61,4 @@ function verifySignature(test, xml, xpath) {
test.done()
});

}
}
16 changes: 16 additions & 0 deletions test/static/feide_public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC
Tk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UE
CxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0B
CQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoX
DTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhl
aW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBv
cGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdA
dW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlx
AZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4Hln
O4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZ
jcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQ
Yj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1j
wKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3K
jjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==
-----END CERTIFICATE-----
9 changes: 9 additions & 0 deletions test/static/valid_saml.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx94e4a319-b6f7-4a40-25d1-01fcb642e4c5" Version="2.0" IssueInstant="2012-07-03T11:32:20Z" Destination="http://localhost:3000/login/callback" InResponseTo="_d766d16611ac0d14121b"><saml:Issuer>https://openidp.feide.no</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfx94e4a319-b6f7-4a40-25d1-01fcb642e4c5"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>fc21hh1bKZpaMNjx9HfOfVelfWw=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>dkONrkxW+LSuDvnNMG/mWYFa47d2WGyapLhXSTYqrlT9Td+tT7ciojNJ55WTaPaCMt7IrGtIxxskPAZIjdIn5pRyDxHr0joWxzZ7oZHCOI1CnQV5HjOq+rzzmEN2LctCZ6S4hbL7SQ1qJ3vp2BCXAygy4tmJOURQdnk0KLwwRS8=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx66496e6c-3c29-230d-6d47-b245434b872d" Version="2.0" IssueInstant="2012-07-03T11:32:20Z"><saml:Issuer>https://openidp.feide.no</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfx66496e6c-3c29-230d-6d47-b245434b872d"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>RnNjoyUguwze5w2R+cboyTHlkQk=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>aw5711jKP7xragunjRRCAD4mT4xKHc37iohBpQDbdSomD3ksOSB96UZQp0MtaC3xlVSkMtYw85Om96T2q2xrxLLYVA50eFJEMMF7SCVPStWTVjBlaCuOPEQxIaHyJs9Sy3MCEfbBh4Pqn9IJBd1kzwdlCrWWjAmksbFFg5wHQJA=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID SPNameQualifier="passport-saml" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_6c5dcaa3053321ff4d63785fbc3f67c59a129cde82</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2012-07-03T11:37:20Z" Recipient="http://localhost:3000/login/callback" InResponseTo="_d766d16611ac0d14121b"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2012-07-03T11:31:50Z" NotOnOrAfter="2012-07-03T11:37:20Z"><saml:AudienceRestriction><saml:Audience>passport-saml</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2012-07-03T11:32:20Z" SessionNotOnOrAfter="2012-07-03T19:32:20Z" SessionIndex="_c8e6823fe38ddbce125f9be6e5118b8c352d04bcae"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">bergie</saml:AttributeValue></saml:Attribute><saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri</saml:AttributeValue></saml:Attribute><saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonPrincipalName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonTargetedID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">8216c78fe244502efa13f62e6615c94acb7bdf3e</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">bergie</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">8216c78fe244502efa13f62e6615c94acb7bdf3e</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
6 changes: 5 additions & 1 deletion test/xml-assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ var select = require('../lib/xpath.js').SelectNodes


function nodeExists(test, doc, xpath) {
if (!doc && !xpath) {
test.done();
return;
}
var node = select(doc, xpath)
test.ok(node.length==1, "xpath " + xpath + " not found")
}

exports.nodeExists = nodeExists
exports.nodeExists = nodeExists