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
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,29 @@ var signedAssertion = saml.create(options);

Everything except the cert and key is optional.

### Encryption

SAML assertions can optionally be encrypted, by providing a certificate and public key, as follows:

```js
var saml = require('saml').Saml20; // or Saml11

var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
nameIdentifier: 'foo',
encryptionPublicKey: fs.readFileSync(__dirname + '/encryption-key.pub'),
encryptionCert: fs.readFileSync(__dirname + '/encryption-cert.pem'),
encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', // Defaults to http://www.w3.org/2009/xmlenc11#aes256-gcm if not specified
disallowEncryptionWithInsecureAlgorithm: true,
warnOnInsecureEncryptionAlgorithm: true
}
```

See [node-xml-encryption](https://github.com/auth0/node-xml-encryption) for documentation on the allowed algorithms. If using algorithms treated as insecure by [node-xml-encryption](https://github.com/auth0/node-xml-encryption), you must provide disallowEncryptionWithInsecureAlgorithm option set to false.
A warning will be piped to `stderr` using console.warn() by default when the insecure algorithms are used and above mentioned flag is false. This can be disabled via the `warnOnInsecureEncryptionAlgorithm` flag.


## Issue Reporting

If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
Expand Down
4 changes: 4 additions & 0 deletions lib/saml11.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ function extractSaml11Options(opts) {
* @param [options.encryptionPublicKey] {Buffer}
* @param [options.encryptionAlgorithm] {string}
* @param [options.keyEncryptionAlgorithm] {string}
* @param [options.disallowEncryptionWithInsecureAlgorithm] {boolean}
* @param [options.warnOnInsecureEncryptionAlgorithm] {boolean}
*
* @param {Function} [callback] required if encrypting
* @return {String|*}
Expand Down Expand Up @@ -89,6 +91,8 @@ exports.create = function(options, callback) {
* @param [options.encryptionPublicKey] {Buffer}
* @param [options.encryptionAlgorithm] {string}
* @param [options.keyEncryptionAlgorithm] {string}
* @param [options.disallowEncryptionWithInsecureAlgorithm] {boolean}
* @param [options.warnOnInsecureEncryptionAlgorithm] {boolean}
*
* @param {Function} [callback] required if encrypting
* @return {String|*}
Expand Down
4 changes: 4 additions & 0 deletions lib/saml20.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ function extractSaml20Options(opts) {
* @param [options.encryptionPublicKey] {Buffer}
* @param [options.encryptionAlgorithm] {string}
* @param [options.keyEncryptionAlgorithm] {string}
* @param [options.disallowEncryptionWithInsecureAlgorithm] {boolean}
* @param [options.warnOnInsecureEncryptionAlgorithm] {boolean}
*
* @param {Function} [callback] required if encrypting
* @return {*}
Expand Down Expand Up @@ -134,6 +136,8 @@ exports.create = function createSignedAssertion(options, callback) {
* @param [options.encryptionPublicKey] {Buffer}
* @param [options.encryptionAlgorithm] {string}
* @param [options.keyEncryptionAlgorithm] {string}
* @param [options.disallowEncryptionWithInsecureAlgorithm] {boolean}
* @param [options.warnOnInsecureEncryptionAlgorithm] {boolean}
*
* @param {Function} [callback] required if encrypting
* @return {*}
Expand Down
4 changes: 3 additions & 1 deletion lib/xml/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ exports.fromEncryptXmlOptions = function (options) {
const encryptOptions = {
rsa_pub: options.encryptionPublicKey,
pem: options.encryptionCert,
encryptionAlgorithm: options.encryptionAlgorithm || 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
encryptionAlgorithm: options.encryptionAlgorithm || 'http://www.w3.org/2009/xmlenc11#aes256-gcm',
keyEncryptionAlgorithm: options.keyEncryptionAlgorithm || 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p',
disallowEncryptionWithInsecureAlgorithm: options?.disallowEncryptionWithInsecureAlgorithm !== false,
warnInsecureAlgorithm: options?.warnOnInsecureEncryptionAlgorithm !== false,
};

// expose the encryptOptions as these are needed when adding the SubjectConfirmation
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"husky": "^9.1.7",
"mocha": "^8.2.0",
"semantic-release": "^25.0.2",
"should": "~1.2.1"
"should": "~1.2.1",
"sinon": "^9.0.2"
},
"files": [
"lib"
Expand All @@ -31,7 +32,7 @@
"moment": "^2.29.4",
"valid-url": "~1.0.9",
"xml-crypto": "^2.1.3",
"xml-encryption": "^2.0.0",
"xml-encryption": "^4.0.0",
"xml-name-validator": "~2.0.1",
"xpath": "0.0.5"
},
Expand Down
63 changes: 63 additions & 0 deletions test/saml11.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var xmlenc = require('xml-encryption');

var utils = require('./utils');
var saml11 = require('../lib/saml11');
var sinon = require('sinon');

describe('saml 1.1', function () {

Expand Down Expand Up @@ -356,6 +357,14 @@ describe('saml 1.1', function () {
});

describe('encryption', function () {
let consoleSpy = null;
beforeEach(function() {
consoleSpy = sinon.spy(console, 'warn');
});

afterEach(function() {
consoleSpy.restore();
});

it('should create a saml 1.1 encrypted assertion', function (done) {
var options = {
Expand Down Expand Up @@ -483,6 +492,60 @@ describe('saml 1.1', function () {
});
});
});

it('should use aes256-gcm as the default encryption algorithm', function (done) {
var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
encryptionPublicKey: fs.readFileSync(__dirname + '/test-auth0_rsa.pub'),
encryptionCert: fs.readFileSync(__dirname + '/test-auth0.pem'),
};

saml11[createAssertion](options, function (err, encrypted) {
if (err) return done(err);
var doc = new xmldom.DOMParser().parseFromString(encrypted);
var encryptionMethod = doc.getElementsByTagName('xenc:EncryptionMethod')[0];
assert.equal('http://www.w3.org/2009/xmlenc11#aes256-gcm', encryptionMethod.getAttribute('Algorithm'));
done();
})
});

it('should allow aes256-cbc when disallowEncryptionWithInsecureAlgorithm is false', function (done) {
var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
encryptionPublicKey: fs.readFileSync(__dirname + '/test-auth0_rsa.pub'),
encryptionCert: fs.readFileSync(__dirname + '/test-auth0.pem'),
encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
disallowEncryptionWithInsecureAlgorithm: false,
warnOnInsecureEncryptionAlgorithm: true,
};

saml11[createAssertion](options, function (err, encrypted) {
if (err) return done(err);
var doc = new xmldom.DOMParser().parseFromString(encrypted);
var encryptionMethod = doc.getElementsByTagName('xenc:EncryptionMethod')[0];
assert.equal('http://www.w3.org/2001/04/xmlenc#aes256-cbc', encryptionMethod.getAttribute('Algorithm'));
assert.equal(consoleSpy.called, true);
done();
});
});

it('should not allow aes256-cbc when disallowEncryptionWithInsecureAlgorithm is true', function (done) {
var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
encryptionPublicKey: fs.readFileSync(__dirname + '/test-auth0_rsa.pub'),
encryptionCert: fs.readFileSync(__dirname + '/test-auth0.pem'),
encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
disallowEncryptionWithInsecureAlgorithm: true
};

saml11[createAssertion](options, function (err, encrypted) {
assert.ok(err);
done();
});
});
});
});
}
Expand Down
64 changes: 64 additions & 0 deletions test/saml20.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var moment = require('moment');
var should = require('should');
var xmldom = require('@xmldom/xmldom');
var xmlenc = require('xml-encryption');
var sinon = require('sinon');

var saml = require('../lib/saml20');

Expand Down Expand Up @@ -581,6 +582,14 @@ describe('saml 2.0', function () {
});

describe('encryption', function () {
let consoleSpy = null;
beforeEach(function() {
consoleSpy = sinon.spy(console, 'warn');
});

afterEach(function() {
consoleSpy.restore();
});

it('should create a saml 2.0 signed and encrypted assertion', function (done) {
var options = {
Expand Down Expand Up @@ -682,6 +691,61 @@ describe('saml 2.0', function () {
});
});
});

it('should use aes256-gcm as the default encryption algorithm', function (done) {
var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
encryptionPublicKey: fs.readFileSync(__dirname + '/test-auth0_rsa.pub'),
encryptionCert: fs.readFileSync(__dirname + '/test-auth0.pem'),
};

saml[createAssertion](options, function (err, encrypted) {
if (err) return done(err);
var encryptedData = utils.getEncryptedData(encrypted);
var encryptionMethod = encryptedData.getElementsByTagName('xenc:EncryptionMethod')[0];
assert.equal('http://www.w3.org/2009/xmlenc11#aes256-gcm', encryptionMethod.getAttribute('Algorithm'));
done();
})
});

it('should allow aes256-cbc when disallowEncryptionWithInsecureAlgorithm is false', function (done) {
var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
encryptionPublicKey: fs.readFileSync(__dirname + '/test-auth0_rsa.pub'),
encryptionCert: fs.readFileSync(__dirname + '/test-auth0.pem'),
encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
disallowEncryptionWithInsecureAlgorithm: false,
warnOnInsecureEncryptionAlgorithm: true,
};

saml[createAssertion](options, function (err, encrypted) {
if (err) return done(err);
var encryptedData = utils.getEncryptedData(encrypted);
var encryptionMethod = encryptedData.getElementsByTagName('xenc:EncryptionMethod')[0];
assert.equal('http://www.w3.org/2001/04/xmlenc#aes256-cbc', encryptionMethod.getAttribute('Algorithm'));
assert.equal(consoleSpy.called, true);
done();
});
});

it('should not allow aes256-cbc when disallowEncryptionWithInsecureAlgorithm is true', function (done) {
var options = {
cert: fs.readFileSync(__dirname + '/test-auth0.pem'),
key: fs.readFileSync(__dirname + '/test-auth0.key'),
encryptionPublicKey: fs.readFileSync(__dirname + '/test-auth0_rsa.pub'),
encryptionCert: fs.readFileSync(__dirname + '/test-auth0.pem'),
encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
disallowEncryptionWithInsecureAlgorithm: true
};

saml[createAssertion](options, function (err, encrypted) {
assert.ok(err);
done();
});
});

});
});
}
Expand Down