Skip to content

Commit

Permalink
look for typed services providing Auth2 token/logout (#3789)
Browse files Browse the repository at this point in the history
- DRY search routines into functions defined in getServices
- all routines should look for Auth2 types and Auth1 profiles
- include search for uncoducmented Auth1 implementation of explicit probe service
  • Loading branch information
barmintor committed Oct 3, 2023
1 parent dd09ce7 commit 2221286
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 17 deletions.
90 changes: 90 additions & 0 deletions __tests__/src/lib/getServices.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
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 auth1 = resourceFixtureWithService({ id: serviceId, profile: 'http://iiif.io/api/auth/1/probe' });
expect(actualProbeServiceId(auth1)).toEqual(serviceId);
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);
});
});
12 changes: 3 additions & 9 deletions src/containers/IIIFAuthentication.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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];
Expand Down
44 changes: 44 additions & 0 deletions src/lib/getServices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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
&& (
Utils.getService(resource, 'http://iiif.io/api/auth/1/probe')
|| 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]
);
}
10 changes: 4 additions & 6 deletions src/state/sagas/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
});
};
Expand Down Expand Up @@ -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
Expand All @@ -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;
});
Expand Down
4 changes: 2 additions & 2 deletions src/state/sagas/iiif.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
receiveSearch, receiveSearchFailure,
receiveAnnotation, receiveAnnotationFailure,
} from '../actions';
import { getTokenService } from '../../lib/getServices';
import {
getManifests,
getRequestsConfig,
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 2221286

Please sign in to comment.