diff --git a/common/models/access-token.js b/common/models/access-token.js index 5d6be2bc..a3af78c9 100644 --- a/common/models/access-token.js +++ b/common/models/access-token.js @@ -147,11 +147,19 @@ module.exports = function(AccessToken) { assert(this.ttl, 'token.ttl must exist'); assert(this.ttl >= -1, 'token.ttl must be >= -1'); + var AccessToken = this.constructor; + var userRelation = AccessToken.relations.user; // may not be set up + var User = userRelation && userRelation.modelTo; + var now = Date.now(); var created = this.created.getTime(); var elapsedSeconds = (now - created) / 1000; var secondsToLive = this.ttl; - var isValid = elapsedSeconds < secondsToLive; + var eternalTokensAllowed = !!(User && User.settings.allowEternalTokens); + var isEternalToken = secondsToLive === -1; + var isValid = isEternalToken ? + eternalTokensAllowed : + elapsedSeconds < secondsToLive; if (isValid) { cb(null, isValid); diff --git a/test/access-token.test.js b/test/access-token.test.js index 5883d41b..50d8d91d 100644 --- a/test/access-token.test.js +++ b/test/access-token.test.js @@ -357,11 +357,38 @@ describe('AccessToken', function() { assert(Object.prototype.toString.call(this.token.created), '[object Date]'); }); - it('should be validateable', function(done) { - this.token.validate(function(err, isValid) { - assert(isValid); + describe('.validate()', function() { + it('accepts valid tokens', function(done) { + this.token.validate(function(err, isValid) { + assert(isValid); + done(); + }); + }); - done(); + it('rejects eternal TTL by default', function(done) { + this.token.ttl = -1; + this.token.validate(function(err, isValid) { + if (err) return done(err); + expect(isValid, 'isValid').to.equal(false); + done(); + }); + }); + + it('allows eternal tokens when enabled by User.allowEternalTokens', + function(done) { + var Token = givenLocalTokenModel(); + + // Overwrite User settings - enable eternal tokens + Token.app.models.User.settings.allowEternalTokens = true; + + Token.create({ userId: '123', ttl: -1 }, function(err, token) { + if (err) return done(err); + token.validate(function(err, isValid) { + if (err) return done(err); + expect(isValid, 'isValid').to.equal(true); + done(); + }); + }); }); }); @@ -626,3 +653,16 @@ function createTestApp(testToken, settings, done) { return app; } + +function givenLocalTokenModel() { + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + app.dataSource('db', { connector: 'memory' }); + + var User = app.registry.getModel('User'); + app.model(User, { dataSource: 'db' }); + + var Token = app.registry.getModel('AccessToken'); + app.model(Token, { dataSource: 'db' }); + + return Token; +}