From 60d8df49d6d89ea91a9c3a2a63e68be888f30fb5 Mon Sep 17 00:00:00 2001 From: Ryan Berger Date: Fri, 14 Jun 2024 10:32:01 -0400 Subject: [PATCH 1/5] Ensure okapi is being read from store after pulling from tenantOptions in AuthLogin --- src/components/AuthnLogin/AuthnLogin.js | 3 ++- src/components/Root/FFetch.js | 3 ++- src/components/Root/token-util.js | 6 ++---- src/components/SSOLanding/useSSOSession.js | 5 +++-- src/discoverServices.js | 8 ++++---- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/components/AuthnLogin/AuthnLogin.js b/src/components/AuthnLogin/AuthnLogin.js index 4ae5a020d..0b005de14 100644 --- a/src/components/AuthnLogin/AuthnLogin.js +++ b/src/components/AuthnLogin/AuthnLogin.js @@ -39,8 +39,9 @@ const AuthnLogin = ({ stripes }) => { if (okapi.authnUrl) { // If only 1 tenant is defined in config, skip the tenant selection screen. if (tenants.length === 1) { + const loginTenant = tenants[0]; const redirectUri = `${window.location.protocol}//${window.location.host}/oidc-landing`; - const authnUri = `${okapi.authnUrl}/realms/${okapi.tenant}/protocol/openid-connect/auth?client_id=${okapi.clientId}&response_type=code&redirect_uri=${redirectUri}&scope=openid`; + const authnUri = `${okapi.authnUrl}/realms/${loginTenant.name}/protocol/openid-connect/auth?client_id=${loginTenant.clientId}&response_type=code&redirect_uri=${redirectUri}&scope=openid`; return ; } diff --git a/src/components/Root/FFetch.js b/src/components/Root/FFetch.js index 21c5b4c73..b451b0cba 100644 --- a/src/components/Root/FFetch.js +++ b/src/components/Root/FFetch.js @@ -112,7 +112,8 @@ export class FFetch { rotationP.then((rotationInterval) => { this.logger.log('rtr', `rotation fired from rotateCallback; next callback in ${ms(rotationInterval)}`); this.store.dispatch(setRtrTimeout(setTimeout(() => { - rtr(this.nativeFetch, this.logger, this.rotateCallback); + const { okapi } = this.store.getState(); + rtr(this.nativeFetch, this.logger, this.rotateCallback, okapi); }, rotationInterval))); }); }; diff --git a/src/components/Root/token-util.js b/src/components/Root/token-util.js index c1a147024..cf4b49a91 100644 --- a/src/components/Root/token-util.js +++ b/src/components/Root/token-util.js @@ -1,6 +1,3 @@ -import { isEmpty } from 'lodash'; -import { okapi } from 'stripes-config'; - import { getTokenExpiry, setTokenExpiry } from '../../loginServices'; import { RTRError, UnexpectedResourceError } from './Errors'; import { @@ -192,9 +189,10 @@ export const isRotating = () => { * @param {function} fetchfx native fetch function * @param {@folio/stripes/logger} logger * @param {function} callback + * @param {object} store * @returns void */ -export const rtr = (fetchfx, logger, callback) => { +export const rtr = (fetchfx, logger, callback, okapi) => { logger.log('rtr', '** RTR ...'); // rotation is already in progress, maybe in this window, diff --git a/src/components/SSOLanding/useSSOSession.js b/src/components/SSOLanding/useSSOSession.js index 8242f111f..ce9383154 100644 --- a/src/components/SSOLanding/useSSOSession.js +++ b/src/components/SSOLanding/useSSOSession.js @@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom'; import { useCookies } from 'react-cookie'; import queryString from 'query-string'; -import { config, okapi } from 'stripes-config'; +import { config } from 'stripes-config'; import { defaultErrors } from '../../constants'; import { setAuthError } from '../../okapiActions'; @@ -24,11 +24,12 @@ const getToken = (cookies, params) => { }; const getTenant = (params, token) => { + const store = useStore(); const tenant = config.useSecureTokens ? params?.tenantId : parseJWT(token)?.tenant; - return tenant || okapi.tenant; + return tenant || store.getState()?.okapi?.tenant; }; const useSSOSession = () => { diff --git a/src/discoverServices.js b/src/discoverServices.js index 98e6a4c43..6ea2a63b9 100644 --- a/src/discoverServices.js +++ b/src/discoverServices.js @@ -96,7 +96,7 @@ function parseApplicationDescriptor(store, descriptor) { const APP_MAX_COUNT = 500; function fetchApplicationDetails(store) { - const okapi = store.getState().okapi; + const { okapi } = store.getState(); return fetch(`${okapi.url}/entitlements/${okapi.tenant}/applications?limit=${APP_MAX_COUNT}`, { credentials: 'include', @@ -146,7 +146,7 @@ function fetchApplicationDetails(store) { */ function fetchGatewayVersion(store) { - const okapi = store.getState().okapi; + const { okapi } = store.getState(); return fetch(`${okapi.url}/version`, { credentials: 'include', @@ -167,7 +167,7 @@ function fetchGatewayVersion(store) { } function fetchOkapiVersion(store) { - const okapi = store.getState().okapi; + const { okapi } = store.getState(); return fetch(`${okapi.url}/_/version`, { credentials: 'include', @@ -188,7 +188,7 @@ function fetchOkapiVersion(store) { } function fetchModules(store) { - const okapi = store.getState().okapi; + const { okapi } = store.getState(); return fetch(`${okapi.url}/_/proxy/tenants/${okapi.tenant}/modules?full=true`, { credentials: 'include', From 2c2e7a28030944a7ec6133bc6af17e6ecf9b4dc0 Mon Sep 17 00:00:00 2001 From: Ryan Berger Date: Fri, 14 Jun 2024 13:25:09 -0400 Subject: [PATCH 2/5] Fix import --- src/components/Root/token-util.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Root/token-util.js b/src/components/Root/token-util.js index cf4b49a91..c77f990cb 100644 --- a/src/components/Root/token-util.js +++ b/src/components/Root/token-util.js @@ -1,3 +1,5 @@ +import { isEmpty } from 'lodash'; + import { getTokenExpiry, setTokenExpiry } from '../../loginServices'; import { RTRError, UnexpectedResourceError } from './Errors'; import { From 0e79df53df5b263aae4c0ec21c00a74cd02a1dfd Mon Sep 17 00:00:00 2001 From: Ryan Berger Date: Fri, 14 Jun 2024 13:52:01 -0400 Subject: [PATCH 3/5] Fix unit tests and lint --- src/components/Root/FFetch.js | 4 ++-- src/components/Root/token-util.test.js | 15 ++++++++++----- src/components/SSOLanding/useSSOSession.js | 7 +++---- src/components/SSOLanding/useSSOSession.test.js | 9 ++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/components/Root/FFetch.js b/src/components/Root/FFetch.js index b451b0cba..49adfc152 100644 --- a/src/components/Root/FFetch.js +++ b/src/components/Root/FFetch.js @@ -112,8 +112,8 @@ export class FFetch { rotationP.then((rotationInterval) => { this.logger.log('rtr', `rotation fired from rotateCallback; next callback in ${ms(rotationInterval)}`); this.store.dispatch(setRtrTimeout(setTimeout(() => { - const { okapi } = this.store.getState(); - rtr(this.nativeFetch, this.logger, this.rotateCallback, okapi); + const okapiStore = this.store.getState().okapi; + rtr(this.nativeFetch, this.logger, this.rotateCallback, okapiStore); }, rotationInterval))); }); }; diff --git a/src/components/Root/token-util.test.js b/src/components/Root/token-util.test.js index 4463ec97a..0ed8cc7fc 100644 --- a/src/components/Root/token-util.test.js +++ b/src/components/Root/token-util.test.js @@ -13,6 +13,11 @@ import { } from './token-util'; import { RTR_SUCCESS_EVENT } from './constants'; +const okapi = { + tenant: 'diku', + url: 'http://test' +}; + describe('isFolioApiRequest', () => { it('accepts requests whose origin matches okapi\'s', () => { const oUrl = 'https://millicent-sounds-kinda-like-malificent.edu'; @@ -126,7 +131,7 @@ describe('rtr', () => { let ex = null; // const callback = () => { console.log('HOLA!!!')}; // jest.fn(); try { - await rtr(fetchfx, logger, callback); + await rtr(fetchfx, logger, callback, okapi); expect(callback).toHaveBeenCalled(); } catch (e) { ex = e; @@ -168,7 +173,7 @@ describe('rtr', () => { let ex = null; try { - await rtr(nativeFetch, logger, jest.fn()); + await rtr(nativeFetch, logger, jest.fn(), okapi); } catch (e) { ex = e; } @@ -202,7 +207,7 @@ describe('rtr', () => { let ex = null; try { - await rtr(nativeFetch, logger, jest.fn()); + await rtr(nativeFetch, logger, jest.fn(), okapi); } catch (e) { ex = e; } @@ -232,7 +237,7 @@ describe('rtr', () => { let ex = null; try { - await rtr(nativeFetch, logger, jest.fn()); + await rtr(nativeFetch, logger, jest.fn(), okapi); } catch (e) { ex = e; } @@ -262,7 +267,7 @@ describe('rtr', () => { let ex = null; try { - await rtr(nativeFetch, logger, jest.fn()); + await rtr(nativeFetch, logger, jest.fn(), okapi); } catch (e) { ex = e; } diff --git a/src/components/SSOLanding/useSSOSession.js b/src/components/SSOLanding/useSSOSession.js index ce9383154..8e71b01c4 100644 --- a/src/components/SSOLanding/useSSOSession.js +++ b/src/components/SSOLanding/useSSOSession.js @@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom'; import { useCookies } from 'react-cookie'; import queryString from 'query-string'; -import { config } from 'stripes-config'; +import { config, okapi } from 'stripes-config'; import { defaultErrors } from '../../constants'; import { setAuthError } from '../../okapiActions'; @@ -23,8 +23,7 @@ const getToken = (cookies, params) => { return cookies?.ssoToken || params?.ssoToken; }; -const getTenant = (params, token) => { - const store = useStore(); +const getTenant = (params, token, store) => { const tenant = config.useSecureTokens ? params?.tenantId : parseJWT(token)?.tenant; @@ -43,7 +42,7 @@ const useSSOSession = () => { const params = getParams(location); const token = getToken(cookies, params); - const tenant = getTenant(params, token); + const tenant = getTenant(params, token, store); useEffect(() => { requestUserWithPerms(okapi.url, store, tenant, token) diff --git a/src/components/SSOLanding/useSSOSession.test.js b/src/components/SSOLanding/useSSOSession.test.js index 2a0e4cd0c..5216279af 100644 --- a/src/components/SSOLanding/useSSOSession.test.js +++ b/src/components/SSOLanding/useSSOSession.test.js @@ -51,7 +51,14 @@ describe('SSOLanding', () => { useLocation.mockReturnValue({ search: '' }); useCookies.mockReturnValue([]); - useStore.mockReturnValue({ getState: jest.fn() }); + useStore.mockReturnValue({ + getState: jest.fn().mockReturnValue({ + okapi: { + url: 'okapiUrl', + tenant: 'okapiTenant' + } + }) + }); requestUserWithPerms.mockReturnValue(Promise.resolve()); }); From 04c786e36760cba05d06d3f726906014e216f4fc Mon Sep 17 00:00:00 2001 From: Ryan Berger Date: Fri, 14 Jun 2024 14:07:35 -0400 Subject: [PATCH 4/5] Lint fix --- src/components/SSOLanding/useSSOSession.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SSOLanding/useSSOSession.test.js b/src/components/SSOLanding/useSSOSession.test.js index 5216279af..06eac936e 100644 --- a/src/components/SSOLanding/useSSOSession.test.js +++ b/src/components/SSOLanding/useSSOSession.test.js @@ -56,7 +56,7 @@ describe('SSOLanding', () => { okapi: { url: 'okapiUrl', tenant: 'okapiTenant' - } + } }) }); From a0a58674e27097243e530869c44393a76bd35a79 Mon Sep 17 00:00:00 2001 From: Ryan Berger Date: Tue, 18 Jun 2024 17:12:40 -0400 Subject: [PATCH 5/5] Rename for clarity --- src/components/Root/FFetch.js | 12 ++++++------ src/components/Root/token-util.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/Root/FFetch.js b/src/components/Root/FFetch.js index 49adfc152..90eade94e 100644 --- a/src/components/Root/FFetch.js +++ b/src/components/Root/FFetch.js @@ -42,7 +42,7 @@ */ import ms from 'ms'; -import { okapi } from 'stripes-config'; +import { okapi as okapiConfig } from 'stripes-config'; import { setRtrTimeout } from '../../okapiActions'; @@ -112,8 +112,8 @@ export class FFetch { rotationP.then((rotationInterval) => { this.logger.log('rtr', `rotation fired from rotateCallback; next callback in ${ms(rotationInterval)}`); this.store.dispatch(setRtrTimeout(setTimeout(() => { - const okapiStore = this.store.getState().okapi; - rtr(this.nativeFetch, this.logger, this.rotateCallback, okapiStore); + const { okapi } = this.store.getState(); + rtr(this.nativeFetch, this.logger, this.rotateCallback, okapi); }, rotationInterval))); }); }; @@ -174,12 +174,12 @@ export class FFetch { */ ffetch = async (resource, options = {}) => { // FOLIO API requests are subject to RTR - if (isFolioApiRequest(resource, okapi.url)) { + if (isFolioApiRequest(resource, okapiConfig.url)) { this.logger.log('rtrv', 'will fetch', resource); // on authentication, grab the response to kick of the rotation cycle, // then return the response - if (isAuthenticationRequest(resource, okapi.url)) { + if (isAuthenticationRequest(resource, okapiConfig.url)) { this.logger.log('rtr', 'authn request'); return this.nativeFetch.apply(global, [resource, options && { ...options, ...OKAPI_FETCH_OPTIONS }]) .then(res => { @@ -208,7 +208,7 @@ export class FFetch { // tries to logout, the logout request will fail. And that's fine, just // fine. We will let them fail, capturing the response and swallowing it // to avoid getting stuck in an error loop. - if (isLogoutRequest(resource, okapi.url)) { + if (isLogoutRequest(resource, okapiConfig.url)) { this.logger.log('rtr', 'logout request'); return this.nativeFetch.apply(global, [resource, options && { ...options, ...OKAPI_FETCH_OPTIONS }]) diff --git a/src/components/Root/token-util.js b/src/components/Root/token-util.js index c77f990cb..32ede2604 100644 --- a/src/components/Root/token-util.js +++ b/src/components/Root/token-util.js @@ -191,7 +191,7 @@ export const isRotating = () => { * @param {function} fetchfx native fetch function * @param {@folio/stripes/logger} logger * @param {function} callback - * @param {object} store + * @param {object} okapi * @returns void */ export const rtr = (fetchfx, logger, callback, okapi) => {