diff --git a/lib/passport-wsfed-saml2/saml.js b/lib/passport-wsfed-saml2/saml.js index 8c5b8ed..1f736c9 100644 --- a/lib/passport-wsfed-saml2/saml.js +++ b/lib/passport-wsfed-saml2/saml.js @@ -24,6 +24,8 @@ var SAML = function (options) { this.options.checkExpiration = (typeof this.options.checkExpiration !== 'undefined') ? this.options.checkExpiration : true; // Note! It would be best to set this to true. But it's defaulting to false so as not to break login for expired certs. this.options.checkCertExpiration = (typeof this.options.checkCertExpiration !== 'undefined') ? this.options.checkCertExpiration : false; + //clockskew in minutes + this.options.clockSkew = (typeof this.options.clockSkew === 'number' && this.options.clockSkew >= 0) ? this.options.clockSkew : 3; this.options.checkAudience = (typeof this.options.checkAudience !== 'undefined') ? this.options.checkAudience : true; this.options.checkRecipient = (typeof this.options.checkRecipient !== 'undefined') ? this.options.checkRecipient : true; this.options.checkNameQualifier = (typeof this.options.checkNameQualifier !== 'undefined') ? this.options.checkNameQualifier : true; @@ -133,15 +135,15 @@ SAML.prototype.validateCertExpiration = function (validatedSamlAssertion) { }; SAML.prototype.validateExpiration = function (samlAssertion, version) { - + var self = this; var conditions = xpath.select(".//*[local-name(.)='Conditions']", samlAssertion); if (!conditions || conditions.length === 0) return true; var notBefore = new Date(conditions[0].getAttribute('NotBefore')); - notBefore = notBefore.setMinutes(notBefore.getMinutes() - 5); // 5 minutes clock skew + notBefore = notBefore.setMinutes(notBefore.getMinutes() - self.options.clockSkew); var notOnOrAfter = new Date(conditions[0].getAttribute('NotOnOrAfter')); - notOnOrAfter = notOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 5); // 5 minutes clock skew + notOnOrAfter = notOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + self.options.clockSkew); var now = new Date(); if (now < notBefore || now > notOnOrAfter) diff --git a/test/saml20.tests.js b/test/saml20.tests.js index b9c6bcb..350e6ae 100644 --- a/test/saml20.tests.js +++ b/test/saml20.tests.js @@ -122,9 +122,9 @@ describe('saml 2.0 assertion', function () { }); - it('should validate assertion expiration', function (done) { + it('should validate expiration with default clockSkew', function (done) { - options.lifetimeInSeconds = -10000; + options.lifetimeInSeconds = -240; var signedAssertion = saml20.create(options); var publicKey = fs.readFileSync(__dirname + '/test-auth0.cer').toString(); @@ -139,6 +139,21 @@ describe('saml 2.0 assertion', function () { }); + it('should validate expiration with overriden clockSkew', function (done) { + + options.lifetimeInSeconds = -240; + + var signedAssertion = saml20.create(options); + var publicKey = fs.readFileSync(__dirname + '/test-auth0.cer').toString(); + const samlPassport = new SamlPassport({cert: publicKey, realm: 'urn:myapp', checkRecipient: false, clockSkew: 5}); + var profile = samlPassport.validateSamlAssertion(signedAssertion, function(err, profile) { + should.not.exists(err); + should.exists(profile); + + done(); + }); + + }); it('should should allow expired cert if option not passed', function (done) { @@ -197,8 +212,6 @@ describe('saml 2.0 assertion', function () { }); - - it('should validate recipent', function (done) { options.lifetimeInSeconds = 600; options.recipient = 'foo'; @@ -286,6 +299,4 @@ describe('saml 2.0 assertion', function () { }); }); - - });