diff --git a/__tests__/src/lib/getServices.test.js b/__tests__/src/lib/getServices.test.js new file mode 100644 index 0000000000..9afd7c0b92 --- /dev/null +++ b/__tests__/src/lib/getServices.test.js @@ -0,0 +1,88 @@ +import { v4 as uuid } from 'uuid'; +import { + anyAuthServices, getLogoutService, getProbeService, getTokenService, +} from '../../../src/lib/getServices'; + +/** + */ +function resourceFixtureWithService(props) { + return { + id: uuid(), + services: [ + { ...props }, + ], + type: 'Dataset', + }; +} + +/** + */ +function actualLogoutServiceId(resource) { + const service = getLogoutService(resource); + return service + && service.id; +} + +/** + */ +function actualTokenServiceId(resource) { + const service = getTokenService(resource); + return service + && service.id; +} + +/** + */ +function actualProbeServiceId(resource) { + const service = getProbeService(resource); + return service + && service.id; +} + +describe('anyAuthServices', () => { + it('returns a filtered list', () => { + const serviceId = uuid(); + const auth0 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/0/anyService' }); + expect(anyAuthServices(auth0).length).toEqual(1); + const auth1 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/1/anyService' }); + expect(anyAuthServices(auth1).length).toEqual(1); + const auth2 = resourceFixtureWithService({ id: serviceId, type: 'AuthAnyService2' }); + expect(anyAuthServices(auth2).length).toEqual(1); + const notAuthProfile = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/not-auth/1/anyService' }); + expect(anyAuthServices(notAuthProfile).length).toEqual(0); + const notAuthType = resourceFixtureWithService({ id: serviceId, type: 'NotAuthAnyService2' }); + expect(anyAuthServices(notAuthType).length).toEqual(0); + }); +}); + +describe('getLogoutService', () => { + it('returns a Service', () => { + const serviceId = uuid(); + const auth0 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/0/logout' }); + expect(actualLogoutServiceId(auth0)).toEqual(serviceId); + const auth1 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/1/logout' }); + expect(actualLogoutServiceId(auth1)).toEqual(serviceId); + const auth2 = resourceFixtureWithService({ id: serviceId, type: 'AuthLogoutService2' }); + expect(actualLogoutServiceId(auth2)).toEqual(serviceId); + }); +}); + +describe('getProbeService', () => { + it('returns a Service', () => { + const serviceId = uuid(); + const auth2 = resourceFixtureWithService({ id: serviceId, type: 'AuthProbeService2' }); + expect(actualProbeServiceId(auth2)).toEqual(serviceId); + }); +}); + +describe('getTokenService', () => { + it('returns a Service', () => { + const serviceId = uuid(); + const auth0 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/0/token' }); + expect(actualTokenServiceId(auth0)).toEqual(serviceId); + const auth1 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/1/token' }); + expect(actualTokenServiceId(auth1)).toEqual(serviceId); + const auth2 = resourceFixtureWithService({ id: serviceId, type: 'AuthAccessTokenService2' }); + expect(actualTokenServiceId(auth2)).toEqual(serviceId); + }); +}); diff --git a/src/containers/IIIFAuthentication.js b/src/containers/IIIFAuthentication.js index 7d51087168..bfeb27461f 100644 --- a/src/containers/IIIFAuthentication.js +++ b/src/containers/IIIFAuthentication.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux'; import { compose } from 'redux'; import { withTranslation } from 'react-i18next'; -import { Utils } from 'manifesto.js'; import { withPlugins } from '../extend/withPlugins'; +import { getLogoutService, getTokenService } from '../lib/getServices'; import * as actions from '../state/actions'; import { getAuth, @@ -23,14 +23,8 @@ const mapStateToProps = (state, { windowId }) => { // TODO: get the most actionable auth service... const service = services[0]; - const accessTokenService = service && ( - Utils.getService(service, 'http://iiif.io/api/auth/1/token') - || Utils.getService(service, 'http://iiif.io/api/auth/0/token') - ); - const logoutService = service && ( - Utils.getService(service, 'http://iiif.io/api/auth/1/logout') - || Utils.getService(service, 'http://iiif.io/api/auth/0/logout') - ); + const accessTokenService = getTokenService(service); + const logoutService = getLogoutService(service); const authStatuses = getAuth(state); const authStatus = service && authStatuses[service.id]; diff --git a/src/lib/getServices.js b/src/lib/getServices.js new file mode 100644 index 0000000000..ad37f64865 --- /dev/null +++ b/src/lib/getServices.js @@ -0,0 +1,41 @@ +import { Utils } from 'manifesto.js'; +import { filterByTypes } from './typeFilters'; + +/** + */ +export function anyAuthServices(resource) { + return resource + && Utils.getServices(resource).filter(s => (s.getProfile() + && s.getProfile().match(/http:\/\/iiif.io\/api\/auth\//)) + || (s.getProperty('type') + && s.getProperty('type').match(/^Auth.*2$/))); +} + +/** + */ +export function getProbeService(resource) { + return resource + && filterByTypes(Utils.getServices(resource), 'AuthProbeService2')[0]; +} + +/** + */ +export function getTokenService(resource) { + return resource + && ( + Utils.getService(resource, 'http://iiif.io/api/auth/1/token') + || Utils.getService(resource, 'http://iiif.io/api/auth/0/token') + || filterByTypes(Utils.getServices(resource), 'AuthAccessTokenService2')[0] + ); +} + +/** + */ +export function getLogoutService(resource) { + return resource + && ( + Utils.getService(resource, 'http://iiif.io/api/auth/1/logout') + || Utils.getService(resource, 'http://iiif.io/api/auth/0/logout') + || filterByTypes(Utils.getServices(resource), 'AuthLogoutService2')[0] + ); +} diff --git a/src/state/sagas/auth.js b/src/state/sagas/auth.js index 732a482368..7cd2eafd37 100644 --- a/src/state/sagas/auth.js +++ b/src/state/sagas/auth.js @@ -5,6 +5,7 @@ import { Utils } from 'manifesto.js'; import flatten from 'lodash/flatten'; import ActionTypes from '../actions/action-types'; import MiradorCanvas from '../../lib/MiradorCanvas'; +import { getTokenService } from '../../lib/getServices'; import { addAuthenticationRequest, resolveAuthenticationRequest, @@ -52,8 +53,7 @@ export function* refetchInfoResponses({ serviceId }) { const haveThisTokenService = infoResponse => { const services = Utils.getServices(infoResponse); return services.some(e => { - const infoTokenService = Utils.getService(e, 'http://iiif.io/api/auth/1/token') - || Utils.getService(e, 'http://iiif.io/api/auth/0/token'); + const infoTokenService = getTokenService(e); return infoTokenService && infoTokenService.id === serviceId; }); }; @@ -90,8 +90,7 @@ export function* doAuthWorkflow({ infoJson, windowId }) { // start the auth yield put(addAuthenticationRequest(windowId, authService.id, authService.getProfile())); } else if (profileConfig.external) { - const tokenService = Utils.getService(authService, 'http://iiif.io/api/auth/1/token') - || Utils.getService(authService, 'http://iiif.io/api/auth/0/token'); + const tokenService = getTokenService(authService); if (!tokenService) return; // resolve the auth @@ -107,8 +106,7 @@ export function* rerequestOnAccessTokenFailure({ infoJson, windowId, tokenServic // 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') - || Utils.getService(service, 'http://iiif.io/api/auth/0/token'); + const tokenService = getTokenService(service); return tokenService && tokenService.id === tokenServiceId; }); diff --git a/src/state/sagas/iiif.js b/src/state/sagas/iiif.js index 3a613ee934..d7a1f7115d 100644 --- a/src/state/sagas/iiif.js +++ b/src/state/sagas/iiif.js @@ -10,6 +10,7 @@ import { receiveSearch, receiveSearchFailure, receiveAnnotation, receiveAnnotationFailure, } from '../actions'; +import { getTokenService } from '../../lib/getServices'; import { getManifests, getRequestsConfig, @@ -128,8 +129,7 @@ function* getAccessTokenService(resource) { for (let i = 0; i < services.length; i += 1) { const authService = services[i]; - const accessTokenService = Utils.getService(authService, 'http://iiif.io/api/auth/1/token') - || Utils.getService(authService, 'http://iiif.io/api/auth/0/token'); + const accessTokenService = getTokenService(authService); const token = accessTokenService && accessTokens[accessTokenService.id]; if (token && token.json) return token; }