Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert privateCert to PEM for signing #390

Merged
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
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,21 @@ The `generateServiceProviderMetadata` method is also available on the `MultiSaml
Passport-SAML uses the HTTP Redirect Binding for its `AuthnRequest`s (unless overridden with the `authnRequestBinding` parameter), and expects to receive the messages back via the HTTP POST binding.

Authentication requests sent by Passport-SAML can be signed using RSA-SHA1. To sign them you need to provide a private key in the PEM format via the `privateCert` configuration key. The certificate
should start with `-----BEGIN PRIVATE KEY-----` on its own line and end with `-----END PRIVATE KEY-----` on its own line.
can start with `-----BEGIN PRIVATE KEY-----` on its own line and end with `-----END PRIVATE KEY-----` on its own line, or have these lines stripped out.

For example:

```javascript
privateCert: fs.readFileSync('./cert.pem', 'utf-8')
```

Alternately:


```javascript
privateCert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W=='
```


It is a good idea to validate the signatures of the incoming SAML Responses. For this, you can provide the Identity Provider's public PEM-encoded X.509 signing certificate using the `cert` confguration key. The "BEGIN CERTIFICATE" and "END CERTIFICATE" lines should be stripped out and the certificate should be provided on a single line.

Expand Down
13 changes: 12 additions & 1 deletion lib/passport-saml/saml.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ SAML.prototype.signRequest = function (samlMessage) {
samlMessageToSign.SigAlg = samlMessage.SigAlg;
}
signer.update(querystring.stringify(samlMessageToSign));
samlMessage.Signature = signer.sign(this.options.privateCert, 'base64');
samlMessage.Signature = signer.sign(this.keyToPEM(this.options.privateCert), 'base64');
};

SAML.prototype.generateAuthorizeRequest = function (req, isPassive, callback) {
Expand Down Expand Up @@ -508,6 +508,17 @@ SAML.prototype.certToPEM = function (cert) {
return cert;
};

SAML.prototype.keyToPEM = function (key) {
key = key.match(/.{1,64}/g).join('\n');

if (key.indexOf('-BEGIN PRIVATE KEY-') === -1)
key = "-----BEGIN PRIVATE KEY-----\n" + key;
if (key.indexOf('-END PRIVATE KEY-') === -1)
key = key + "\n-----END PRIVATE KEY-----\n";

return key;
};

SAML.prototype.certsToCheck = function () {
var self = this;
if (!self.options.cert) {
Expand Down
34 changes: 33 additions & 1 deletion test/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,38 @@ describe( 'passport-saml /', function() {
});
});

it( 'acme_tools request signed with sha256 when cert not in PEM format', function( done ) {
var privateCert = fs.readFileSync(__dirname + '/static/acme_tools_com.key', 'utf-8')
.replace('-----BEGIN PRIVATE KEY-----', '')
.replace('-----END PRIVATE KEY-----', '')
.replace(/\n/g, '')
var samlConfig = {
entryPoint: 'https://adfs.acme_tools.com/adfs/ls/',
issuer: 'acme_tools_com',
callbackUrl: 'https://relyingparty/adfs/postResponse',
privateCert: privateCert,
authnContext: 'http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/password',
identifierFormat: null,
signatureAlgorithm: 'sha256',
additionalParams: {
customQueryStringParam: 'CustomQueryStringParamValue'
}
};
var samlObj = new SAML( samlConfig );
samlObj.generateUniqueID = function () { return '12345678901234567890' };
samlObj.getAuthorizeUrl({}, {}, function(err, url) {
try {
var qry = require('querystring').parse(require('url').parse(url).query);
qry.SigAlg.should.match('http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
qry.Signature.should.match('hel9NaoLU0brY/VhrQsY+lTtuAbTsT/ul6nZ/eVlSMXQRaKn5LTbKadzxmPghX7s4xoHwdah+yZHK/0u4StYSj4b5MKcqbsJapVr2R7H90z8YfGfR2C/G0Gng721YV9Da6VBzKg8Was91zQotgsMpZ9pGX1kPKi6cgFwPwM4NEFugn8AYgXEriNvO5+Q23K/MdBT2bgwRTj2FQCWTuQcgwbyWHXoquHztZ0lbh8UhY5BfQRv7c6D9XPkQEMMQFQeME4PIEg3JnynwFZk5wwhkphMd5nXxau+zt7Nfp4fRm0G8WYnxV1etBnWimwSglZVaSHFYeQBRsC2wvKSiVS8JA==');
qry.customQueryStringParam.should.match('CustomQueryStringParamValue');
done();
} catch (err2) {
done(err2);
}
});
});

it( 'acme_tools request not signed if missing entry point', function( done ) {
var samlConfig = {
entryPoint: '',
Expand Down Expand Up @@ -2147,7 +2179,7 @@ describe( 'passport-saml /', function() {
samlObj.requestToUrl(request, null, 'authorize', {}, function(err) {
try {
should.exist(err);
err.message.should.containEql('no start line');
err.message.should.containEql('bad end line');
done();
} catch (err2) {
done(err2);
Expand Down