Preserve current session when invalidating tokens
Fix User model to preserve the current session (provided via "options.accessToken") when invalidating access tokens after a change of email or password property.
This commit is contained in:
parent
f8b013dab8
commit
afd6dd7073
|
@ -647,7 +647,12 @@ module.exports = function(User) {
|
|||
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)
|
||||
return process.nextTick(cb);
|
||||
|
||||
|
@ -656,7 +661,14 @@ module.exports = function(User) {
|
|||
return process.nextTick(cb);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -873,7 +885,7 @@ module.exports = function(User) {
|
|||
}).map(function(u) {
|
||||
return u.id;
|
||||
});
|
||||
ctx.Model._invalidateAccessTokensOfUsers(userIdsToExpire, next);
|
||||
ctx.Model._invalidateAccessTokensOfUsers(userIdsToExpire, ctx.options, next);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -100,6 +100,54 @@ describe('users - integration', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('invalidates current session when options are not injected', function(done) {
|
||||
// "injectOptionsFromRemoteContext" is disabled by default,
|
||||
// therefore the code invalidating sessions cannot tell what
|
||||
// is the current session, and thus invalidates all sessions
|
||||
var url = '/api/users/' + userId;
|
||||
var self = this;
|
||||
this.request.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(401, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve current session when invalidating tokens', function(done) {
|
||||
var UserWithContext = app.registry.createModel({
|
||||
name: 'UserWithContext',
|
||||
plural: 'ctx-users',
|
||||
base: 'User',
|
||||
injectOptionsFromRemoteContext: true
|
||||
});
|
||||
app.model(UserWithContext, {dataSource: 'db'});
|
||||
|
||||
var self = this;
|
||||
var CREDENTIALS = {email: 'ctx@example.com', password: 'pass'};
|
||||
UserWithContext.create(CREDENTIALS, function(err, user) {
|
||||
if (err) return done(err);
|
||||
|
||||
UserWithContext.login(CREDENTIALS, function(err, token) {
|
||||
if (err) return done(err);
|
||||
|
||||
var url = '/api/ctx-users/' + user.id;
|
||||
self.request.patch(url)
|
||||
.send({email: 'new@example.com'})
|
||||
.set('Authorization', token.id)
|
||||
.expect(200, function(err) {
|
||||
if (err) return done(err);
|
||||
self.get(url)
|
||||
.set('Authorization', token.id)
|
||||
.expect(200, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sub-user', function() {
|
||||
|
|
|
@ -2252,6 +2252,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) {
|
||||
var user1, user2, user1Token;
|
||||
async.series([
|
||||
|
|
Loading…
Reference in New Issue