[NEW] REST endpoint to log user out from other clients #19246

pull/19642/head
Oliver Jägle 5 years ago committed by GitHub
parent c7ed37840b
commit 3135db0e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      app/api/server/v1/users.js
  2. 88
      tests/end-to-end/api/01-users.js

@ -779,6 +779,16 @@ API.v1.addRoute('users.requestDataDownload', { authRequired: true }, {
},
});
API.v1.addRoute('users.logoutOtherClients', { authRequired: true }, {
post() {
try {
Meteor.runAsUser(this.userId, () => API.v1.success(Meteor.call('logoutOtherClients')));
} catch (error) {
return API.v1.failure(error);
}
},
});
API.v1.addRoute('users.autocomplete', { authRequired: true }, {
get() {
const { selector } = this.queryParams;

@ -20,6 +20,47 @@ import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { createUser, login, deleteUser, getUserStatus } from '../../data/users.helper.js';
import { createRoom } from '../../data/rooms.helper';
function createTestUser() {
return new Promise((resolve) => {
const username = `user.test.${ Date.now() }`;
const email = `${ username }@rocket.chat`;
request.post(api('users.create'))
.set(credentials)
.send({ email, name: username, username, password })
.end((err, res) => resolve(res.body.user));
});
}
function loginTestUser(user) {
return new Promise((resolve, reject) => {
request.post(api('login'))
.send({
user: user.username,
password,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
const userCredentials = {};
userCredentials['X-Auth-Token'] = res.body.data.authToken;
userCredentials['X-User-Id'] = res.body.data.userId;
resolve(userCredentials);
})
.end((err) => (err ? reject(err) : resolve()));
});
}
function deleteTestUser(user) {
return new Promise((resolve) => {
request.post(api('users.delete'))
.set(credentials)
.send({
userId: user._id,
})
.end(resolve);
});
}
describe('[Users]', function() {
this.retries(0);
@ -2288,6 +2329,53 @@ describe('[Users]', function() {
});
});
describe('[/users.logoutOtherClients]', function() {
let user;
let userCredentials;
let newCredentials;
this.timeout(20000);
before(async () => {
user = await createTestUser();
userCredentials = await loginTestUser(user);
newCredentials = await loginTestUser(user);
});
after(async () => {
await deleteTestUser(user);
user = undefined;
});
it('should invalidate all active sesions', (done) => {
/* We want to validate that the login with the "old" credentials fails
However, the removal of the tokens is done asynchronously.
Thus, we check that within the next seconds, at least one try to
access an authentication requiring route fails */
let counter = 0;
async function checkAuthenticationFails() {
const result = await request.get(api('me'))
.set(userCredentials);
return result.statusCode === 401;
}
async function tryAuthentication() {
if (await checkAuthenticationFails()) {
done();
} else if (++counter < 20) {
setTimeout(tryAuthentication, 1000);
} else {
done('Session did not invalidate in time');
}
}
request.post(api('users.logoutOtherClients'))
.set(newCredentials)
.expect(200)
.then(tryAuthentication);
});
});
describe('[/users.autocomplete]', () => {
it('should return an empty list when the user does not have the necessary permission', (done) => {
updatePermission('view-outside-room', []).then(() => {

Loading…
Cancel
Save