Skip to content

Commit fb1bda0

Browse files
author
big kahuna burger
authored
Singleline private keys (#423)
* feat: single line private keys allowed * docs: document single line private keys option * docs: document hashing algs selection with opinionated comments
1 parent a224a31 commit fb1bda0

File tree

4 files changed

+93
-7
lines changed

4 files changed

+93
-7
lines changed

README.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,47 @@ The `generateServiceProviderMetadata` method is also available on the `MultiSaml
208208
209209
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.
210210
211-
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
212-
should start with `-----BEGIN PRIVATE KEY-----` on its own line and end with `-----END PRIVATE KEY-----` on its own line.
211+
Authentication requests sent by Passport-SAML can be signed using RSA signature with SHA1, SHA256 or SHA512 hashing algorithms.
213212
214-
For example:
213+
To select hashing algorithm, use:
214+
215+
```js
216+
...
217+
signatureAlgorithm: 'sha1' // (default, but not recommended anymore these days)
218+
signatureAlgorithm: 'sha256', // (preffered - your IDP should support it, otherwise think about upgrading it)
219+
signatureAlgorithm: 'sha512' // (most secure - check if your IDP supports it)
220+
...
221+
```
222+
223+
To sign them you need to provide a private key in the PEM format via the `privateCert` configuration key.
224+
225+
Formats supported for `privateCert` field are,
226+
227+
1. Well formatted PEM:
228+
229+
```
230+
-----BEGIN PRIVATE KEY-----
231+
<private key contents here delimited at 64 characters per row>
232+
-----END PRIVATE KEY-----
233+
234+
```
235+
```
236+
-----BEGIN RSA PRIVATE KEY-----
237+
<private key contents here delimited at 64 characters per row>
238+
-----END RSA PRIVATE KEY-----
239+
240+
```
241+
(both versions work)
242+
See example from tests of the first version of [well formatted private key](test/static/acme_tools_com.key).
243+
244+
2. Alternativelly a single line private key without start/end lines where all rows are joined into single line:
245+
246+
See example from tests of [singleline private key](test/static/singleline_acme_tools_com.key).
247+
248+
Add it to strategy options like this:
215249
216250
```javascript
217-
privateCert: fs.readFileSync('./cert.pem', 'utf-8')
251+
privateCert: fs.readFileSync('./privateCert.pem', 'utf-8')
218252
```
219253
220254

lib/passport-saml/saml.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ SAML.prototype.signRequest = function (samlMessage) {
139139
samlMessageToSign.SigAlg = samlMessage.SigAlg;
140140
}
141141
signer.update(querystring.stringify(samlMessageToSign));
142-
samlMessage.Signature = signer.sign(this.options.privateCert, 'base64');
142+
samlMessage.Signature = signer.sign(this.keyToPEM(this.options.privateCert), 'base64');
143143
};
144144

145145
SAML.prototype.generateAuthorizeRequest = function (req, isPassive, isHttpPostBinding, callback) {
@@ -1290,4 +1290,19 @@ SAML.prototype.generateServiceProviderMetadata = function( decryptionCert, signi
12901290
return xmlbuilder.create(metadata).end({ pretty: true, indent: ' ', newline: '\n' });
12911291
};
12921292

1293+
SAML.prototype.keyToPEM = function (key) {
1294+
if (!key || typeof key !== 'string') return key;
1295+
1296+
const lines = key.split('\n');
1297+
if (lines.length !== 1) return key;
1298+
1299+
const wrappedKey = [
1300+
'-----BEGIN PRIVATE KEY-----',
1301+
...key.match(/.{1,64}/g),
1302+
'-----END PRIVATE KEY-----',
1303+
''
1304+
].join('\n');
1305+
return wrappedKey;
1306+
};
1307+
12931308
exports.SAML = SAML;

test/samlTests.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
'use strict';
2+
var fs = require('fs');
3+
var url = require('url');
4+
var should = require('should');
25

36
var SAML = require('../lib/passport-saml/saml.js').SAML;
4-
var should = require('should');
5-
var url = require('url');
67

78
describe('SAML.js', function () {
89
describe('get Urls', function () {
@@ -232,5 +233,40 @@ describe('SAML.js', function () {
232233
});
233234
});
234235
});
236+
237+
describe('keyToPEM', function () {
238+
var [regular, singleline] = [
239+
'acme_tools_com.key',
240+
'singleline_acme_tools_com.key'
241+
].map(keyFromFile);
242+
243+
it('formats singleline keys properly', function (done) {
244+
var result = saml.keyToPEM(singleline);
245+
result.should.equal(regular);
246+
done();
247+
});
248+
249+
it('passes all other multiline keys', function (done) {
250+
var result = saml.keyToPEM(regular);
251+
result.should.equal(regular);
252+
done();
253+
});
254+
255+
it('does nothing to falsy', function (done) {
256+
var result = saml.keyToPEM(null);
257+
should.equal(result, null);
258+
done();
259+
});
260+
261+
it('does nothing to non strings', function (done) {
262+
var result = saml.keyToPEM(1);
263+
should.equal(result, 1);
264+
done();
265+
});
266+
});
235267
});
236268
});
269+
270+
function keyFromFile (file) {
271+
return fs.readFileSync(`./test/static/${file}`).toString();
272+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJP47MTKaFpkU1/Hj4cXFlsE/d6C9xSA+8ZrvBYJXu/K4Jq4sGrA7UVCrNpEPGQSKGQeqZTPrcPbm/ZCLEvFfKpoVDxPEMUrBgBO1IvvHkbYbDDnofQvVcaBh01bVqQ/H3Q/5RKZWfVZv//sDBT5NX67iMiApnJNogVZ0WXAGGWng4EQcLJjCeAWAzJWgIGxKbBviJ/syLlPvjon1kxCkL62z6R/OV7Ln03Pnmlrl9EvC7irEVS/ahF1cB/Zku7EHsM9BtEfzb97Blnw3gFQaJDIDA6weCnSxv0kny4Qz+qHJLV1dfGOj6TGwjkdeHGng/lH1UAO46q5osijym0itAgMBAAECggEAOEGbotp/9BxfJAPwU5pwK0gea4oSOTAK/YKd4UNSrWcWQ3aaM25Hk/yDIwbvXQg5yVDhqol6lrJ4I6fTSgBl+L75lMcE22xhX75VF4GK51AT0ONvFlqcsfhV8rNfyazgY8qjLGth4iVKq+tCOXCVLOVlSWnQ0Mwnjak+TZYQfSQb9a6KZWwkTkoMf38q52iSkc3zbqUG0xYoGfpUNhdULrna8C6m6yGh+odG9kennHKBePf38M1sa3cCyriAm0TrKUG+OIAIJPV+PN2q14Vn/o9YW6uxj4GD/abBJZzFgt6aEGhJxSjwogEBT8U9SjhwBGwetL2A7T6NOoQkyWyKHQKBgQDGj4PMYtxUV9Cd50C5ekh2NQBLEsGd6DGrkJe2OrLuqDOmpxOdtGnAI7s0oiBNB2gYuTd8T+zL+FdN9vKJc9OJ9dZ0zgHKVoajff8ZB6QDkvGXGKZNbYjnsbuJYAuMg7fE0HZ7DZnBmArbRO1RtfbRf31Pfj2bpuaEWLPr3BbDewKBgQDC3g9XKKsaS+Eg3phgRYBfLL7j33vM5nGe1GrogVu3gNvirLoQLq60lSCzaWIwq0d9m+7nM9xgY9BeA6rxFWms0wWAxBW5Dj+UrRNjAa5KFav1IPVNBkzkoUfXc+WskgZBneDJt87Xif0NdnwvZPufvTzYLtgp7uf1tACOB0v39wKBgQCkvhglMPULiZyOFnuOKFYMtWbb4uD/ydHEPgCR8lvZRXctUzwkQbbn8v106vsPzhBhSvMtUgbvKMoO5tBOmOovcegQG4hCv82Pwo8vzjYXvQhzS8FXRoUrbzxg+245lGOZiTh0WlFy3VpMmQCqJeZ15Wgr11r4VN63ef01uPKuFwKBgDFTXlS0oaL1ZBYa4j00Ootc2zD5J/A0wLvwjuMto1au0nntOOfRuT1SpkVjvowNPvpnlzCE6xqnCV5S1VlTDz3E6Jawi8Mc/TEYIlkkWsa795wD7LPDjYEt5e5+krt89wJzASxuT3g1oI1g2YxxplPH5ffe2665n5ONLbrF1A//AoGAUKM5N826wiZqmYCa+eC1TVz12iprlIdW0wOoBL5hcDRDd7u0ninTSiv9mAE5RYJVHEF3PchmQFTs9i3OJXGXYDWU73kHhzgYnEC+vDxDq/6Q8BOhicRyBZ7faQ3oNnGTUzIioiBoQtmJ9axJZVNs3tfYUpxvwr43am35OSeC3aI=

0 commit comments

Comments
 (0)