Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
[PLT-7396] Add the ability to revoke user sessions in System Console …
Browse files Browse the repository at this point in the history
…> Users #7493 (#267)

* revoe all sessions for a user, redux action and request

* add tests, add logic to reducer so it knows when sessions have been cleared for the current user (so tests can work), remove unnecessary post body param

* test revokeAllSessions to verify it works when there are multiple sessions for the given user
  • Loading branch information
rickbatka authored and hmhealey committed Aug 28, 2020
1 parent 5611544 commit e07a535
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/mattermost-redux/src/action_types/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export default keyMirror({
REVOKE_SESSION_SUCCESS: null,
REVOKE_SESSION_FAILURE: null,

REVOKE_ALL_USER_SESSIONS_REQUEST: null,
REVOKE_ALL_USER_SESSIONS_SUCCESS: null,
REVOKE_ALL_USER_SESSIONS_FAILURE: null,

AUDITS_REQUEST: null,
AUDITS_SUCCESS: null,
AUDITS_FAILURE: null,
Expand Down
28 changes: 28 additions & 0 deletions packages/mattermost-redux/src/actions/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
} from './preferences';

import {getConfig} from 'selectors/entities/general';
import {getCurrentUserId} from 'selectors/entities/users';

export function checkMfa(loginId) {
return async (dispatch, getState) => {
Expand Down Expand Up @@ -675,6 +676,32 @@ export function revokeSession(userId, sessionId) {
};
}

export function revokeAllSessionsForUser(userId) {
return async (dispatch, getState) => {
dispatch({type: UserTypes.REVOKE_ALL_USER_SESSIONS_REQUEST}, getState);

try {
await Client4.revokeAllSessionsForUser(userId);
} catch (error) {
forceLogoutIfNecessary(error, dispatch);
dispatch(batchActions([
{type: UserTypes.REVOKE_ALL_USER_SESSIONS_FAILURE, error},
logError(error)(dispatch)
]), getState);
return {error};
}
const data = {isCurrentUser: userId === getCurrentUserId(getState())};
dispatch(batchActions([
{
type: UserTypes.REVOKE_ALL_USER_SESSIONS_SUCCESS,
data
}
]), getState);

return {data: true};
};
}

export function loadProfilesForDirect() {
return async (dispatch, getState) => {
const state = getState();
Expand Down Expand Up @@ -1362,6 +1389,7 @@ export default {
getSessions,
loadProfilesForDirect,
revokeSession,
revokeAllSessionsForUser,
getUserAudits,
searchProfiles,
startPeriodicStatusUpdates,
Expand Down
7 changes: 7 additions & 0 deletions packages/mattermost-redux/src/client/client4.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,13 @@ export default class Client4 {
);
};

revokeAllSessionsForUser = async (userId) => {
return this.doFetch(
`${this.getUserRoute(userId)}/sessions/revoke/all`,
{method: 'post'}
);
};

getUserAudits = async (userId, page = 0, perPage = PER_PAGE_DEFAULT) => {
return this.doFetch(
`${this.getUserRoute(userId)}/audits${buildQueryString({page, per_page: perPage})}`,
Expand Down
7 changes: 7 additions & 0 deletions packages/mattermost-redux/src/reducers/entities/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ function mySessions(state = [], action) {

return state;
}

case UserTypes.REVOKE_ALL_USER_SESSIONS_SUCCESS:
if (action.data.isCurrentUser === true) {
return [];
}
return state;

case UserTypes.LOGOUT_SUCCESS:
return [];

Expand Down
11 changes: 11 additions & 0 deletions packages/mattermost-redux/src/reducers/requests/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@ function revokeSession(state = initialRequestState(), action) {
);
}

function revokeAllSessionsForUser(state = initialRequestState(), action) {
return handleRequest(
UserTypes.REVOKE_ALL_USER_SESSIONS_REQUEST,
UserTypes.REVOKE_ALL_USER_SESSIONS_SUCCESS,
UserTypes.REVOKE_ALL_USER_SESSIONS_FAILURE,
state,
action
);
}

function getAudits(state = initialRequestState(), action) {
return handleRequest(
UserTypes.AUDITS_REQUEST,
Expand Down Expand Up @@ -363,6 +373,7 @@ export default combineReducers({
setStatus,
getSessions,
revokeSession,
revokeAllSessionsForUser,
getAudits,
autocompleteUsers,
searchProfiles,
Expand Down
40 changes: 40 additions & 0 deletions packages/mattermost-redux/test/actions/users.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,46 @@ describe('Actions.Users', () => {
}
});

it('revokeAllSessionsForCurrentUser', async () => {
const user = TestHelper.basicUser;
await TestHelper.basicClient4.logout();
let sessions = store.getState().entities.users.mySessions;

assert.strictEqual(sessions.length, 0);

await Actions.loginById(user.id, 'password1')(store.dispatch, store.getState);
await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1');

await Actions.getSessions(user.id)(store.dispatch, store.getState);

const sessionsRequest = store.getState().requests.users.getSessions;

if (sessionsRequest.status === RequestStatus.FAILURE) {
throw new Error(JSON.stringify(sessionsRequest.error));
}

sessions = store.getState().entities.users.mySessions;
assert.ok(sessions.length > 1);

await Actions.revokeAllSessionsForUser(user.id)(store.dispatch, store.getState);

const revokeRequest = store.getState().requests.users.revokeAllSessionsForUser;
if (revokeRequest.status === RequestStatus.FAILURE) {
throw new Error(JSON.stringify(revokeRequest.error));
}

await Actions.getProfiles(0)(store.dispatch, store.getState);

const logoutRequest = store.getState().requests.users.logout;
if (logoutRequest.status === RequestStatus.FAILURE) {
throw new Error(JSON.stringify(logoutRequest.error));
}

sessions = store.getState().entities.users.mySessions;

assert.strictEqual(sessions.length, 0);
});

it('getUserAudits', async () => {
await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1');
await Actions.getUserAudits(TestHelper.basicUser.id)(store.dispatch, store.getState);
Expand Down

0 comments on commit e07a535

Please sign in to comment.