Comparing version 0.9.3 to 0.10.0
@@ -6,3 +6,5 @@ | ||
xmlenc = require('xml-encryption'), | ||
moment = require('moment'); | ||
moment = require('moment'), | ||
xmlNameValidator = require('xml-name-validator'), | ||
is_uri = require('valid-url').is_uri; | ||
@@ -26,2 +28,33 @@ var fs = require('fs'); | ||
function getAttributeType(value){ | ||
switch(typeof value) { | ||
case "string": | ||
return 'xs:string'; | ||
case "boolean": | ||
return 'xs:boolean'; | ||
case "number": | ||
// Maybe we should fine-grain this type and check whether it is an integer, float, double xsi:types | ||
return 'xs:double'; | ||
default: | ||
return 'xs:anyType'; | ||
} | ||
} | ||
function getNameFormat(name){ | ||
if (is_uri(name)){ | ||
return 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'; | ||
} | ||
// Check that the name is a valid xs:Name -> https://www.w3.org/TR/xmlschema-2/#Name | ||
// xmlNameValidate.name takes a string and will return an object of the form { success, error }, | ||
// where success is a boolean | ||
// if it is false, then error is a string containing some hint as to where the match went wrong. | ||
if (xmlNameValidator.name(name).success){ | ||
return 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic'; | ||
} | ||
// Default value | ||
return 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified'; | ||
} | ||
exports.create = function(options, callback) { | ||
@@ -37,2 +70,6 @@ if (!options.key) | ||
options.includeAttributeNameFormat = (typeof options.includeAttributeNameFormat !== 'undefined') ? options.includeAttributeNameFormat : true; | ||
options.typedAttributes = (typeof options.typedAttributes !== 'undefined') ? options.typedAttributes : true; | ||
var cert = utils.pemToCert(options.cert); | ||
@@ -103,11 +140,20 @@ | ||
attributeElement.setAttribute('Name', prop); | ||
if (options.includeAttributeNameFormat){ | ||
attributeElement.setAttribute('NameFormat', getNameFormat(prop)); | ||
} | ||
var values = options.attributes[prop] instanceof Array ? options.attributes[prop] : [options.attributes[prop]]; | ||
values.forEach(function (value) { | ||
var valueElement = doc.createElementNS(NAMESPACE, 'saml:AttributeValue'); | ||
valueElement.setAttribute('xsi:type', 'xs:anyType'); | ||
valueElement.textContent = value; | ||
attributeElement.appendChild(valueElement); | ||
// Check by type, becase we want to include false values | ||
if (typeof value !== 'undefined') { | ||
// Ignore undefined values in Array | ||
var valueElement = doc.createElementNS(NAMESPACE, 'saml:AttributeValue'); | ||
valueElement.setAttribute('xsi:type', options.typedAttributes ? getAttributeType(value) : 'xs:anyType'); | ||
valueElement.textContent = value; | ||
attributeElement.appendChild(valueElement); | ||
} | ||
}); | ||
if (values && values.length > 0) { | ||
if (values && values.filter(function(i){ return typeof i !== 'undefined'; }).length > 0) { | ||
// saml:Attribute must have at least one saml:AttributeValue | ||
@@ -114,0 +160,0 @@ statement.appendChild(attributeElement); |
{ | ||
"name": "saml", | ||
"version": "0.9.3", | ||
"version": "0.10.0", | ||
"devDependencies": { | ||
@@ -19,4 +19,6 @@ "mocha": "*", | ||
"moment": "~2.14.1", | ||
"valid-url": "~1.0.9", | ||
"xml-crypto": "0.8.4", | ||
"xml-encryption": "~0.7.4", | ||
"xml-name-validator": "~2.0.1", | ||
"xmldom": "=0.1.15", | ||
@@ -23,0 +25,0 @@ "xpath": "0.0.5" |
@@ -87,2 +87,209 @@ var assert = require('assert'), | ||
it('should set attributes with the correct attribute type', function () { | ||
var options = { | ||
cert: fs.readFileSync(__dirname + '/test-auth0.pem'), | ||
key: fs.readFileSync(__dirname + '/test-auth0.key'), | ||
attributes: { | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'foo@bar.com', | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Foo Bar', | ||
'http://example.org/claims/testemptyarray': [], // should dont include empty arrays | ||
'http://example.org/claims/testaccent': 'fóo', // should supports accents | ||
'http://attributes/boolean': true, | ||
'http://attributes/booleanNegative': false, | ||
'http://attributes/number': 123, | ||
'http://undefinedattribute/ws/com.com': undefined | ||
} | ||
}; | ||
var signedAssertion = saml.create(options); | ||
var isValid = utils.isValidSignature(signedAssertion, options.cert); | ||
assert.equal(true, isValid); | ||
var attributes = utils.getAttributes(signedAssertion); | ||
assert.equal(6, attributes.length); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', attributes[0].getAttribute('Name')); | ||
assert.equal('foo@bar.com', attributes[0].textContent); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name', attributes[1].getAttribute('Name')); | ||
assert.equal('Foo Bar', attributes[1].textContent); | ||
assert.equal('http://example.org/claims/testaccent', attributes[2].getAttribute('Name')); | ||
assert.equal('xs:string', attributes[2].firstChild.getAttribute('xsi:type')); | ||
assert.equal('fóo', attributes[2].textContent); | ||
assert.equal('http://attributes/boolean', attributes[3].getAttribute('Name')); | ||
assert.equal('xs:boolean', attributes[3].firstChild.getAttribute('xsi:type')); | ||
assert.equal('true', attributes[3].textContent); | ||
assert.equal('http://attributes/booleanNegative', attributes[4].getAttribute('Name')); | ||
assert.equal('xs:boolean', attributes[4].firstChild.getAttribute('xsi:type')); | ||
assert.equal('false', attributes[4].textContent); | ||
assert.equal('http://attributes/number', attributes[5].getAttribute('Name')); | ||
assert.equal('xs:double', attributes[5].firstChild.getAttribute('xsi:type')); | ||
assert.equal('123', attributes[5].textContent); | ||
}); | ||
it('should set attributes with the correct attribute type and NameFormat', function () { | ||
var options = { | ||
cert: fs.readFileSync(__dirname + '/test-auth0.pem'), | ||
key: fs.readFileSync(__dirname + '/test-auth0.key'), | ||
attributes: { | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'foo@bar.com', | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Foo Bar', | ||
'http://example.org/claims/testemptyarray': [], // should dont include empty arrays | ||
'testaccent': 'fóo', // should supports accents | ||
'urn:test:1:2:3': true, | ||
'123~oo': 123, | ||
'http://undefinedattribute/ws/com.com': undefined | ||
} | ||
}; | ||
var signedAssertion = saml.create(options); | ||
var isValid = utils.isValidSignature(signedAssertion, options.cert); | ||
assert.equal(true, isValid); | ||
var attributes = utils.getAttributes(signedAssertion); | ||
assert.equal(5, attributes.length); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', attributes[0].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', attributes[0].getAttribute('NameFormat')); | ||
assert.equal('foo@bar.com', attributes[0].textContent); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name', attributes[1].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', attributes[1].getAttribute('NameFormat')); | ||
assert.equal('Foo Bar', attributes[1].textContent); | ||
assert.equal('testaccent', attributes[2].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:basic', attributes[2].getAttribute('NameFormat')); | ||
assert.equal('xs:string', attributes[2].firstChild.getAttribute('xsi:type')); | ||
assert.equal('fóo', attributes[2].textContent); | ||
assert.equal('urn:test:1:2:3', attributes[3].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', attributes[3].getAttribute('NameFormat')); | ||
assert.equal('xs:boolean', attributes[3].firstChild.getAttribute('xsi:type')); | ||
assert.equal('true', attributes[3].textContent); | ||
assert.equal('123~oo', attributes[4].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified', attributes[4].getAttribute('NameFormat')); | ||
assert.equal('xs:double', attributes[4].firstChild.getAttribute('xsi:type')); | ||
assert.equal('123', attributes[4].textContent); | ||
}); | ||
it('should set attributes to anytpe when typedAttributes is false', function () { | ||
var options = { | ||
cert: fs.readFileSync(__dirname + '/test-auth0.pem'), | ||
key: fs.readFileSync(__dirname + '/test-auth0.key'), | ||
typedAttributes: false, | ||
attributes: { | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'foo@bar.com', | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Foo Bar', | ||
'http://example.org/claims/testemptyarray': [], // should dont include empty arrays | ||
'http://example.org/claims/testaccent': 'fóo', // should supports accents | ||
'http://attributes/boolean': true, | ||
'http://attributes/number': 123, | ||
'http://undefinedattribute/ws/com.com': undefined | ||
} | ||
}; | ||
var signedAssertion = saml.create(options); | ||
var isValid = utils.isValidSignature(signedAssertion, options.cert); | ||
assert.equal(true, isValid); | ||
var attributes = utils.getAttributes(signedAssertion); | ||
assert.equal(5, attributes.length); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', attributes[0].getAttribute('Name')); | ||
assert.equal('foo@bar.com', attributes[0].textContent); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name', attributes[1].getAttribute('Name')); | ||
assert.equal('Foo Bar', attributes[1].textContent); | ||
assert.equal('http://example.org/claims/testaccent', attributes[2].getAttribute('Name')); | ||
assert.equal('xs:anyType', attributes[2].firstChild.getAttribute('xsi:type')); | ||
assert.equal('fóo', attributes[2].textContent); | ||
assert.equal('http://attributes/boolean', attributes[3].getAttribute('Name')); | ||
assert.equal('xs:anyType', attributes[3].firstChild.getAttribute('xsi:type')); | ||
assert.equal('true', attributes[3].textContent); | ||
assert.equal('http://attributes/number', attributes[4].getAttribute('Name')); | ||
assert.equal('xs:anyType', attributes[4].firstChild.getAttribute('xsi:type')); | ||
assert.equal('123', attributes[4].textContent); | ||
}); | ||
it('should not set NameFormat in attributes when includeAttributeNameFormat is false', function () { | ||
var options = { | ||
cert: fs.readFileSync(__dirname + '/test-auth0.pem'), | ||
key: fs.readFileSync(__dirname + '/test-auth0.key'), | ||
typedAttributes: false, | ||
includeAttributeNameFormat: false, | ||
attributes: { | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'foo@bar.com', | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Foo Bar', | ||
'http://example.org/claims/testemptyarray': [], // should dont include empty arrays | ||
'testaccent': 'fóo', // should supports accents | ||
'urn:test:1:2:3': true, | ||
'123~oo': 123, | ||
'http://undefinedattribute/ws/com.com': undefined | ||
} | ||
}; | ||
var signedAssertion = saml.create(options); | ||
var isValid = utils.isValidSignature(signedAssertion, options.cert); | ||
assert.equal(true, isValid); | ||
var attributes = utils.getAttributes(signedAssertion); | ||
assert.equal(5, attributes.length); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', attributes[0].getAttribute('Name')); | ||
assert.equal('', attributes[0].getAttribute('NameFormat')); | ||
assert.equal('foo@bar.com', attributes[0].textContent); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name', attributes[1].getAttribute('Name')); | ||
assert.equal('', attributes[1].getAttribute('NameFormat')); | ||
assert.equal('Foo Bar', attributes[1].textContent); | ||
assert.equal('testaccent', attributes[2].getAttribute('Name')); | ||
assert.equal('', attributes[2].getAttribute('NameFormat')); | ||
assert.equal('fóo', attributes[2].textContent); | ||
assert.equal('urn:test:1:2:3', attributes[3].getAttribute('Name')); | ||
assert.equal('', attributes[3].getAttribute('NameFormat')); | ||
assert.equal('true', attributes[3].textContent); | ||
assert.equal('123~oo', attributes[4].getAttribute('Name')); | ||
assert.equal('', attributes[4].getAttribute('NameFormat')); | ||
assert.equal('123', attributes[4].textContent); | ||
}); | ||
it('should ignore undefined attributes in array', function () { | ||
var options = { | ||
cert: fs.readFileSync(__dirname + '/test-auth0.pem'), | ||
key: fs.readFileSync(__dirname + '/test-auth0.key'), | ||
attributes: { | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'foo@bar.com', | ||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Foo Bar', | ||
'http://example.org/claims/testemptyarray': [], // should dont include empty arrays | ||
'arrayAttribute': [ 'foo', undefined, 'bar'], | ||
'urn:test:1:2:3': true, | ||
'123~oo': 123, | ||
'http://undefinedattribute/ws/com.com': undefined | ||
} | ||
}; | ||
var signedAssertion = saml.create(options); | ||
var isValid = utils.isValidSignature(signedAssertion, options.cert); | ||
assert.equal(true, isValid); | ||
var attributes = utils.getAttributes(signedAssertion); | ||
assert.equal(5, attributes.length); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', attributes[0].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', attributes[0].getAttribute('NameFormat')); | ||
assert.equal('foo@bar.com', attributes[0].textContent); | ||
assert.equal('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name', attributes[1].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', attributes[1].getAttribute('NameFormat')); | ||
assert.equal('Foo Bar', attributes[1].textContent); | ||
assert.equal('arrayAttribute', attributes[2].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:basic', attributes[2].getAttribute('NameFormat')); | ||
assert.equal('xs:string', attributes[2].firstChild.getAttribute('xsi:type')); | ||
assert.equal(2, attributes[2].childNodes.length); | ||
assert.equal('foo', attributes[2].childNodes[0].textContent); | ||
// undefined should not be here | ||
assert.equal('bar', attributes[2].childNodes[1].textContent); | ||
assert.equal('urn:test:1:2:3', attributes[3].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', attributes[3].getAttribute('NameFormat')); | ||
assert.equal('xs:boolean', attributes[3].firstChild.getAttribute('xsi:type')); | ||
assert.equal('true', attributes[3].textContent); | ||
assert.equal('123~oo', attributes[4].getAttribute('Name')); | ||
assert.equal('urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified', attributes[4].getAttribute('NameFormat')); | ||
assert.equal('xs:double', attributes[4].firstChild.getAttribute('xsi:type')); | ||
assert.equal('123', attributes[4].textContent); | ||
}); | ||
it('whole thing with specific authnContextClassRef', function () { | ||
@@ -89,0 +296,0 @@ var options = { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
68785
19
1202
0
8
+ Addedvalid-url@~1.0.9
+ Addedxml-name-validator@~2.0.1
+ Addedvalid-url@1.0.9(transitive)
+ Addedxml-name-validator@2.0.1(transitive)