Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix token refresh error #1072

Merged
merged 6 commits into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion public/res/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"need-help-signing-in": "Need help signing in?",
"need-help-signing-in-link": "https://www.isis.stfc.ac.uk/Pages/Troubleshoot-Login.aspx",
"dont-have-an-account-sign-up-now": "Don't have an account? <2>Sign up now</2>",
"dont-have-an-account-sign-up-now-link": "https://users.facilities.rl.ac.uk/auth/CreateAccount.aspx"
"dont-have-an-account-sign-up-now-link": "https://users.facilities.rl.ac.uk/auth/CreateAccount.aspx",
"auto-login-error-msg": "Unable to create anonymous session - please reload the page. If the error persists please contact support"
},
"home-page": {
"title_line1": "<0>Data discovery</0> and <2>access</2>",
Expand Down
69 changes: 62 additions & 7 deletions src/state/middleware/scigateway.middleware.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
LoadHighContrastModePreferenceType,
SignOutType,
AuthFailureType,
NotificationType,
} from '../scigateway.types';
import { toastr } from 'react-redux-toastr';
import { AddHelpTourStepsType } from '../scigateway.types';
Expand Down Expand Up @@ -176,6 +177,43 @@ describe('scigateway middleware', () => {
expect(store.getActions()[1]).toEqual(autoLoginAuthorised());
});

it('sends an error notification if autoLogin fails', async () => {
log.error = jest.fn();

autoLogin = jest.fn(() => Promise.reject());
store = mockStore({
...getState(),
scigateway: {
...getState().scigateway,
authorisation: {
...getState().scigateway.authorisation,
provider: {
...getState().scigateway.authorisation.provider,
autoLogin,
},
},
},
});

autoLoginMiddleware(store)(store.dispatch)({ type: SignOutType });

expect(autoLogin).toHaveBeenCalled();

await flushPromises();

expect(store.getActions().length).toEqual(1);

expect(log.error).toHaveBeenCalled();
const mockLog = (log.error as jest.Mock).mock;
expect(mockLog.calls[0][0]).toEqual('Auto Login via middleware failed');

expect(events.length).toEqual(1);
expect(events[0].detail).toEqual({
type: NotificationType,
payload: { severity: 'error', message: 'auto-login-error-msg' },
});
});

it('does nothing when random action sent', () => {
autoLoginMiddleware(store)(store.dispatch)({ type: 'test' });

Expand Down Expand Up @@ -445,16 +483,33 @@ describe('scigateway middleware', () => {
expect(refreshSpy).toHaveBeenCalled();
});

it('should listen for events and fire invalidateToken action on invalidateToken message', async () => {
it('should listen for events and fires invalidateToken action & notification event on invalidateToken message & failed refresh', async () => {
listenToPlugins(store.dispatch, getState);

handler(new CustomEvent('test', { detail: { type: InvalidateTokenType } }));
const notificationPayload = { severity: 'error', message: 'Token error' };

handler(
new CustomEvent('test', {
detail: {
type: InvalidateTokenType,
payload: notificationPayload,
},
})
);

await flushPromises();

expect(document.addEventListener).toHaveBeenCalled();
expect(store.getActions().length).toEqual(1);
expect(store.getActions()[0]).toEqual({ type: InvalidateTokenType });
expect(store.getActions()[0]).toEqual({
type: InvalidateTokenType,
payload: notificationPayload,
});
expect(events.length).toEqual(1);
expect(events[0].detail).toEqual({
type: NotificationType,
payload: notificationPayload,
});
});

it('should listen for events and fire registerroute action and addHelpTourStep action when helpText present', () => {
Expand Down Expand Up @@ -592,7 +647,7 @@ describe('scigateway middleware', () => {
listenToPlugins(store.dispatch, getState);

const notificationAction = {
type: 'scigateway:api:notification',
type: NotificationType,
payload: {
message: 'test notification',
},
Expand All @@ -609,7 +664,7 @@ describe('scigateway middleware', () => {
listenToPlugins(store.dispatch, getState);

const notificationAction = {
type: 'scigateway:api:notification',
type: NotificationType,
payload: {
message: 'test notification',
severity: 'success',
Expand All @@ -628,7 +683,7 @@ describe('scigateway middleware', () => {
listenToPlugins(store.dispatch, getState);

const notificationAction = {
type: 'scigateway:api:notification',
type: NotificationType,
payload: {
message: 'test notification',
severity: 'error',
Expand All @@ -648,7 +703,7 @@ describe('scigateway middleware', () => {
listenToPlugins(store.dispatch, getState);

const notificationAction = {
type: 'scigateway:api:notification',
type: NotificationType,
payload: {
message: 'test notification',
severity: 'warning',
Expand Down
42 changes: 37 additions & 5 deletions src/state/middleware/scigateway.middleware.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { buildTheme } from '../../theming';
import { push } from 'connected-react-router';
import { ThunkDispatch } from 'redux-thunk';
import * as singleSpa from 'single-spa';
import { getAppStrings, getString } from '../strings';

const trackPage = (page: string): void => {
ReactGA.set({
Expand Down Expand Up @@ -181,7 +182,20 @@ export const listenToPlugins = (
case InvalidateTokenType:
getState()
.scigateway.authorisation.provider.refresh()
.catch(() => dispatch(pluginMessage.detail));
.catch(() => {
dispatch(pluginMessage.detail);
// if there's an error message in the token invalidation event then broadcast it
if (pluginMessage.detail.payload) {
document.dispatchEvent(
new CustomEvent(microFrontendMessageId, {
detail: {
type: NotificationType,
payload: pluginMessage.detail.payload,
},
})
);
}
});
break;
default:
// log and ignore
Expand Down Expand Up @@ -261,7 +275,9 @@ export const autoLoginMiddleware: Middleware<
({ dispatch, getState }) =>
(next) =>
async (action) => {
const autoLogin = getState().scigateway.authorisation.provider.autoLogin;
const state = getState();
const autoLogin = state.scigateway.authorisation.provider.autoLogin;
const res = getAppStrings(state, 'login');
if (
autoLogin &&
// these are the three actions that can cause a user sign out
Expand All @@ -270,9 +286,25 @@ export const autoLoginMiddleware: Middleware<
action.type === InvalidateTokenType)
) {
next(action);
return await autoLogin().then(() => {
dispatch(autoLoginAuthorised());
});
return await autoLogin()
.then(() => {
dispatch(autoLoginAuthorised());
})
.catch(() => {
log.error('Auto Login via middleware failed');
// we can't recover from here - tell user they'll need to refresh the page or login again
document.dispatchEvent(
new CustomEvent(microFrontendMessageId, {
detail: {
type: NotificationType,
payload: {
severity: 'error',
message: getString(res, 'auto-login-error-msg'),
sam-glendenning marked this conversation as resolved.
Show resolved Hide resolved
},
},
})
);
});
}

return next(action);
Expand Down