Merge pull request #3098 from strongloop/preserve-current-access-token
Preserve current session when invalidating access tokens
This commit is contained in:
commit
4ffe5fe17f
|
@ -657,7 +657,12 @@ module.exports = function(User) {
|
||||||
throw err;
|
throw err;
|
||||||
};
|
};
|
||||||
|
|
||||||
User._invalidateAccessTokensOfUsers = function(userIds, cb) {
|
User._invalidateAccessTokensOfUsers = function(userIds, options, cb) {
|
||||||
|
if (typeof options === 'function' && cb === undefined) {
|
||||||
|
cb = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
if (!Array.isArray(userIds) || !userIds.length)
|
if (!Array.isArray(userIds) || !userIds.length)
|
||||||
return process.nextTick(cb);
|
return process.nextTick(cb);
|
||||||
|
|
||||||
|
@ -666,7 +671,14 @@ module.exports = function(User) {
|
||||||
return process.nextTick(cb);
|
return process.nextTick(cb);
|
||||||
|
|
||||||
var AccessToken = accessTokenRelation.modelTo;
|
var AccessToken = accessTokenRelation.modelTo;
|
||||||
AccessToken.deleteAll({userId: {inq: userIds}}, cb);
|
|
||||||
|
var query = {userId: {inq: userIds}};
|
||||||
|
var tokenPK = AccessToken.definition.idName() || 'id';
|
||||||
|
if (options.accessToken && tokenPK in options.accessToken) {
|
||||||
|
query[tokenPK] = {neq: options.accessToken[tokenPK]};
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessToken.deleteAll(query, options, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -893,7 +905,7 @@ module.exports = function(User) {
|
||||||
}).map(function(u) {
|
}).map(function(u) {
|
||||||
return u.id;
|
return u.id;
|
||||||
});
|
});
|
||||||
ctx.Model._invalidateAccessTokensOfUsers(userIdsToExpire, next);
|
ctx.Model._invalidateAccessTokensOfUsers(userIdsToExpire, ctx.options, next);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ _beforeEach.withApp = function(app) {
|
||||||
this.get = _request.get;
|
this.get = _request.get;
|
||||||
this.put = _request.put;
|
this.put = _request.put;
|
||||||
this.del = _request.del;
|
this.del = _request.del;
|
||||||
|
this.patch = _request.patch;
|
||||||
|
|
||||||
if (app.booting) {
|
if (app.booting) {
|
||||||
return app.once('booted', done);
|
return app.once('booted', done);
|
||||||
|
|
|
@ -92,6 +92,20 @@ describe('users - integration', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should preserve current session when invalidating tokens', function(done) {
|
||||||
|
var url = '/api/users/' + userId;
|
||||||
|
var self = this;
|
||||||
|
this.patch(url)
|
||||||
|
.send({email: 'new@example.com'})
|
||||||
|
.set('Authorization', accessToken)
|
||||||
|
.expect(200, function(err) {
|
||||||
|
if (err) return done(err);
|
||||||
|
self.get(url)
|
||||||
|
.set('Authorization', accessToken)
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sub-user', function() {
|
describe('sub-user', function() {
|
||||||
|
|
|
@ -2000,7 +2000,7 @@ describe('User', function() {
|
||||||
User.login(currentEmailCredentials, function(err, accessToken1) {
|
User.login(currentEmailCredentials, function(err, accessToken1) {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
assert(accessToken1.userId);
|
assert(accessToken1.userId);
|
||||||
originalUserToken1 = accessToken1.id;
|
originalUserToken1 = accessToken1;
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -2008,7 +2008,7 @@ describe('User', function() {
|
||||||
User.login(currentEmailCredentials, function(err, accessToken2) {
|
User.login(currentEmailCredentials, function(err, accessToken2) {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
assert(accessToken2.userId);
|
assert(accessToken2.userId);
|
||||||
originalUserToken2 = accessToken2.id;
|
originalUserToken2 = accessToken2;
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -2068,7 +2068,7 @@ describe('User', function() {
|
||||||
it('keeps sessions AS IS if firstName is added using `updateAttributes`', function(done) {
|
it('keeps sessions AS IS if firstName is added using `updateAttributes`', function(done) {
|
||||||
user.updateAttributes({'firstName': 'Janny'}, function(err, userInstance) {
|
user.updateAttributes({'firstName': 'Janny'}, function(err, userInstance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
assertUntouchedTokens(done);
|
assertPreservedTokens(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2079,7 +2079,7 @@ describe('User', function() {
|
||||||
email: currentEmailCredentials.email,
|
email: currentEmailCredentials.email,
|
||||||
}, function(err, userInstance) {
|
}, function(err, userInstance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
assertUntouchedTokens(done);
|
assertPreservedTokens(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2263,6 +2263,19 @@ describe('User', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('preserves current session', function(done) {
|
||||||
|
var options = {accessToken: originalUserToken1};
|
||||||
|
user.updateAttribute('email', 'new@example.com', options, function(err) {
|
||||||
|
if (err) return done(err);
|
||||||
|
AccessToken.find({where: {userId: user.id}}, function(err, tokens) {
|
||||||
|
if (err) return done(err);
|
||||||
|
var tokenIds = tokens.map(function(t) { return t.id; });
|
||||||
|
expect(tokenIds).to.eql([originalUserToken1.id]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('preserves other user sessions if their password is untouched', function(done) {
|
it('preserves other user sessions if their password is untouched', function(done) {
|
||||||
var user1, user2, user1Token;
|
var user1, user2, user1Token;
|
||||||
async.series([
|
async.series([
|
||||||
|
@ -2314,9 +2327,11 @@ describe('User', function() {
|
||||||
function assertPreservedTokens(done) {
|
function assertPreservedTokens(done) {
|
||||||
AccessToken.find({where: {userId: user.id}}, function(err, tokens) {
|
AccessToken.find({where: {userId: user.id}}, function(err, tokens) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
expect(tokens.length).to.equal(2);
|
var actualIds = tokens.map(function(t) { return t.id; });
|
||||||
expect([tokens[0].id, tokens[1].id]).to.have.members([originalUserToken1,
|
actualIds.sort();
|
||||||
originalUserToken2]);
|
var expectedIds = [originalUserToken1.id, originalUserToken2.id];
|
||||||
|
expectedIds.sort();
|
||||||
|
expect(actualIds).to.eql(expectedIds);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -2328,14 +2343,6 @@ describe('User', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertUntouchedTokens(done) {
|
|
||||||
AccessToken.find({where: {userId: user.id}}, function(err, tokens) {
|
|
||||||
if (err) return done(err);
|
|
||||||
expect(tokens.length).to.equal(2);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Verification after updating email', function() {
|
describe('Verification after updating email', function() {
|
||||||
|
|
Loading…
Reference in New Issue