Skip to content

Commit 7045d8a

Browse files
committed
Support InResponseTo validations in MultiSaml
Either use cache provided by user, or a default memory cache to store InResponse parameters. This cache is not yet partitioned per provider, which means a malicious provider could do replay attacks by using anothers unconsummed `InResponse` values node-saml#334
1 parent e2154f2 commit 7045d8a

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ passport.use(new MultiSamlStrategy(
7272
})
7373
);
7474
```
75+
The options passed when the `MultiSamlStrategy` is initialized are also passed as default values to each provider.
76+
e.g. If you provide an `issuer` on `MultiSamlStrategy`, this will be also a default value for every provider.
77+
You can override these defaults by passing a new value through the `getSamlOptions` function.
78+
79+
Using multiple providers supports `validateInResponseTo`, but all the `InResponse` values are stored on the same Cache. This means, if you're using the default `InMemoryCache`, that all providers have access to it and a provider might get its response validated against another's request. [Issue Report](!https://github.com/bergie/passport-saml/issues/334). To amend this you should provide a different cache provider per SAML provider, through the `getSamlOptions` function.
7580

7681
#### The profile object:
7782

multiSamlStrategy.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,50 @@
11
var util = require('util');
22
var saml = require('./lib/passport-saml/saml');
3+
var InMemoryCacheProvider = require('./lib/passport-saml/inmemory-cache-provider').CacheProvider;
34
var SamlStrategy = require('./lib/passport-saml/strategy');
45

56
function MultiSamlStrategy (options, verify) {
67
if (!options || typeof options.getSamlOptions != 'function') {
78
throw new Error('Please provide a getSamlOptions function');
89
}
910

11+
if(!options.requestIdExpirationPeriodMs){
12+
options.requestIdExpirationPeriodMs = 28800000; // 8 hours
13+
}
14+
15+
if(!options.cacheProvider){
16+
options.cacheProvider = new InMemoryCacheProvider(
17+
{keyExpirationPeriodMs: options.requestIdExpirationPeriodMs });
18+
}
19+
1020
SamlStrategy.call(this, options, verify);
11-
this._getSamlOptions = options.getSamlOptions;
21+
this._options = options;
1222
}
1323

1424
util.inherits(MultiSamlStrategy, SamlStrategy);
1525

1626
MultiSamlStrategy.prototype.authenticate = function (req, options) {
1727
var self = this;
1828

19-
this._getSamlOptions(req, function (err, samlOptions) {
29+
this._options.getSamlOptions(req, function (err, samlOptions) {
2030
if (err) {
2131
return self.error(err);
2232
}
2333

24-
self._saml = new saml.SAML(samlOptions);
34+
self._saml = new saml.SAML(Object.assign({}, self._options, samlOptions));
2535
self.constructor.super_.prototype.authenticate.call(self, req, options);
2636
});
2737
};
2838

2939
MultiSamlStrategy.prototype.logout = function (req, options) {
3040
var self = this;
3141

32-
this._getSamlOptions(req, function (err, samlOptions) {
42+
this._options.getSamlOptions(req, function (err, samlOptions) {
3343
if (err) {
3444
return self.error(err);
3545
}
3646

37-
self._saml = new saml.SAML(samlOptions);
47+
self._saml = new saml.SAML(Object.assign({}, self._options, samlOptions));
3848
self.constructor.super_.prototype.logout.call(self, req, options);
3949
});
4050
};

test/multiSamlStrategy.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ describe('strategy#authenticate', function() {
3737
done();
3838
};
3939

40-
var strategy = new MultiSamlStrategy({ getSamlOptions: getSamlOptions }, verify);
40+
var strategy = new MultiSamlStrategy({
41+
getSamlOptions: getSamlOptions
42+
}, verify);
4143
strategy.authenticate();
4244
});
4345

@@ -57,7 +59,7 @@ describe('strategy#authenticate', function() {
5759
strategy.authenticate();
5860
});
5961

60-
it('uses geted options to setup internal saml provider', function(done) {
62+
it('uses given options to setup internal saml provider', function(done) {
6163
var samlOptions = {
6264
issuer: 'http://foo.issuer',
6365
callbackUrl: 'http://foo.callback',
@@ -73,12 +75,15 @@ describe('strategy#authenticate', function() {
7375

7476
function getSamlOptions (req, fn) {
7577
fn(null, samlOptions);
76-
strategy._saml.options.should.containEql(samlOptions);
78+
strategy._saml.options.should.containEql(Object.assign({},
79+
cacheProvider: 'mock cache provider',
80+
samlOptions
81+
));
7782
done();
7883
}
7984

8085
var strategy = new MultiSamlStrategy(
81-
{ getSamlOptions: getSamlOptions },
86+
{ getSamlOptions: getSamlOptions, cacheProvider: 'mock cache provider'},
8287
verify
8388
);
8489
strategy.authenticate();
@@ -122,7 +127,7 @@ describe('strategy#logout', function() {
122127
strategy.logout();
123128
});
124129

125-
it('uses geted options to setup internal saml provider', function(done) {
130+
it('uses given options to setup internal saml provider', function(done) {
126131
var samlOptions = {
127132
issuer: 'http://foo.issuer',
128133
callbackUrl: 'http://foo.callback',

0 commit comments

Comments
 (0)