Skip to content
Snippets Groups Projects
Commit 155d7b1d authored by Chris Beer's avatar Chris Beer
Browse files

Eagerly retry or reset auth states if a token is rejected

parent 5b115527
Branches
Tags
No related merge requests found
...@@ -8,6 +8,8 @@ import { ...@@ -8,6 +8,8 @@ import {
refetchInfoResponses, refetchInfoResponses,
refetchInfoResponsesOnLogout, refetchInfoResponsesOnLogout,
doAuthWorkflow, doAuthWorkflow,
rerequestOnAccessTokenFailure,
invalidateInvalidAuth,
} from '../../../src/state/sagas/auth'; } from '../../../src/state/sagas/auth';
import { import {
fetchInfoResponse, fetchInfoResponse,
...@@ -283,4 +285,107 @@ describe('IIIF Authentication sagas', () => { ...@@ -283,4 +285,107 @@ describe('IIIF Authentication sagas', () => {
.run(); .run();
}); });
}); });
describe('rerequestOnAccessTokenFailure', () => {
it('does nothing if no access token was used', () => {
const infoJson = {};
const windowId = 'window';
const tokenServiceId = undefined;
return expectSaga(rerequestOnAccessTokenFailure, { infoJson, tokenServiceId, windowId })
.provide([
[select(getAccessTokens), {}],
])
.not.put.like({ type: ActionTypes.REQUEST_ACCESS_TOKEN })
.run();
});
it('does nothing if the access token has never worked', () => {
const infoJson = {
service: [{
'@context': 'http://iiif.io/api/auth/1/context.json',
'@id': 'https://authentication.example.com/kiosk',
profile: 'http://iiif.io/api/auth/1/kiosk',
service: [
{
'@id': 'https://authentication.example.com/token',
profile: 'http://iiif.io/api/auth/1/token',
},
],
}],
};
const windowId = 'window';
const tokenServiceId = 'https://authentication.example.com/token';
return expectSaga(rerequestOnAccessTokenFailure, { infoJson, tokenServiceId, windowId })
.provide([
[select(getAccessTokens), { [tokenServiceId]: { success: false } }],
])
.not.put.like({ type: ActionTypes.REQUEST_ACCESS_TOKEN })
.run();
});
it('re-requests the access token if it might be reneweable', () => {
const infoJson = {
service: [{
'@context': 'http://iiif.io/api/auth/1/context.json',
'@id': 'https://authentication.example.com/kiosk',
profile: 'http://iiif.io/api/auth/1/kiosk',
service: [
{
'@id': 'https://authentication.example.com/token',
profile: 'http://iiif.io/api/auth/1/token',
},
],
}],
};
const windowId = 'window';
const tokenServiceId = 'https://authentication.example.com/token';
return expectSaga(rerequestOnAccessTokenFailure, { infoJson, tokenServiceId, windowId })
.provide([
[select(getAccessTokens), { [tokenServiceId]: { success: true } }],
])
.put({
authId: 'https://authentication.example.com/kiosk',
serviceId: 'https://authentication.example.com/token',
type: ActionTypes.REQUEST_ACCESS_TOKEN,
})
.run();
});
});
describe('invalidateInvalidAuth', () => {
it('resets the auth service if the auth cookie might have expired', () => {
const authId = 'authId';
const serviceId = 'serviceId';
return expectSaga(invalidateInvalidAuth, { serviceId })
.provide([
[select(getAccessTokens), { [serviceId]: { authId, id: serviceId, success: true } }],
[select(getAuth), { [authId]: { id: authId } }],
])
.put({
id: authId,
tokenServiceId: serviceId,
type: ActionTypes.RESET_AUTHENTICATION_STATE,
})
.run();
});
it('marks the auth service as failed if the auth token was not successfully used', () => {
const authId = 'authId';
const serviceId = 'serviceId';
return expectSaga(invalidateInvalidAuth, { serviceId })
.provide([
[select(getAccessTokens), { [serviceId]: { authId, id: serviceId } }],
[select(getAuth), { [authId]: { id: authId } }],
])
.put({
id: authId,
ok: false,
tokenServiceId: serviceId,
type: ActionTypes.RESOLVE_AUTHENTICATION_REQUEST,
})
.run();
});
});
}); });
...@@ -98,9 +98,60 @@ export function* doAuthWorkflow({ infoJson, windowId }) { ...@@ -98,9 +98,60 @@ export function* doAuthWorkflow({ infoJson, windowId }) {
yield put(requestAccessToken(tokenService.id, authService.id)); yield put(requestAccessToken(tokenService.id, authService.id));
} }
} }
/** */
export function* rerequestOnAccessTokenFailure({ infoJson, windowId, tokenServiceId }) {
if (!tokenServiceId) return;
// make sure we have an auth service to try
const authService = Utils.getServices(infoJson).find(service => {
const tokenService = Utils.getService(service, 'http://iiif.io/api/auth/1/token');
return tokenService && tokenService.id === tokenServiceId;
});
if (!authService) return;
// make sure the token ever worked (and might have expired or needs to be re-upped)
const accessTokenServices = yield select(getAccessTokens);
const service = accessTokenServices[tokenServiceId];
if (!(service && service.success)) return;
yield put(requestAccessToken(tokenServiceId, authService.id));
}
/** */
export function* invalidateInvalidAuth({ serviceId }) {
const accessTokenServices = yield select(getAccessTokens);
const authServices = yield select(getAuth);
const accessTokenService = accessTokenServices[serviceId];
if (!accessTokenService) return;
const authService = authServices[accessTokenService.authId];
if (!authService) return;
if (accessTokenService.success) {
// if the token ever worked, reset things so we try to get a new cookie
yield put(resetAuthenticationState({
authServiceId: authService.id,
tokenServiceId: accessTokenService.id,
}));
} else {
// if the token never worked, mark the auth service as bad so we could
// try to pick a different service
yield put(resolveAuthenticationRequest(
authService.id,
accessTokenService.id,
{ ok: false },
));
}
}
/** */ /** */
export default function* authSaga() { export default function* authSaga() {
yield all([ yield all([
takeEvery(ActionTypes.RECEIVE_DEGRADED_INFO_RESPONSE, rerequestOnAccessTokenFailure),
takeEvery(ActionTypes.RECEIVE_ACCESS_TOKEN_FAILURE, invalidateInvalidAuth),
takeEvery(ActionTypes.RECEIVE_DEGRADED_INFO_RESPONSE, doAuthWorkflow), takeEvery(ActionTypes.RECEIVE_DEGRADED_INFO_RESPONSE, doAuthWorkflow),
takeEvery(ActionTypes.RECEIVE_ACCESS_TOKEN, refetchInfoResponses), takeEvery(ActionTypes.RECEIVE_ACCESS_TOKEN, refetchInfoResponses),
takeEvery(ActionTypes.RESET_AUTHENTICATION_STATE, refetchInfoResponsesOnLogout), takeEvery(ActionTypes.RESET_AUTHENTICATION_STATE, refetchInfoResponsesOnLogout),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment