diff --git a/src/application/ApplicationThunks.ts b/src/application/ApplicationThunks.ts index 6af4b6339..67f48b726 100644 --- a/src/application/ApplicationThunks.ts +++ b/src/application/ApplicationThunks.ts @@ -291,7 +291,6 @@ export const handleSharedDashboardsThunk = () => (dispatch: any) => { if (skipConfirmation === true) { dispatch(onConfirmLoadSharedDashboardThunk()); } - window.history.pushState({}, document.title, window.location.pathname); } else { dispatch(setConnectionModalOpen(false)); @@ -358,7 +357,6 @@ export const onConfirmLoadSharedDashboardThunk = () => (dispatch: any, getState: } if (shareDetails.standalone == true) { dispatch(setStandaloneMode(true)); - localStorage.setItem('standaloneShared', 'true'); // EDGE CASE: redirect SSO removes the shareDetails when redirecting } dispatch(resetShareDetails()); } catch (e) { @@ -410,29 +408,33 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: try { // Parse the URL parameters to see if there's any deep linking of parameters. + const state = getState(); const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); + if (state.application.waitForSSO) { + const paramsBeforeSSO = JSON.parse(sessionStorage.getItem('SSO_PARAMS_BEFORE_REDIRECT') || '{}'); + Object.entries(paramsBeforeSSO).forEach(([key, value]) => { + urlParams.set(key, value); + }); + } const paramsToSetAfterConnecting = {}; Array.from(urlParams.entries()).forEach(([key, value]) => { if (key.startsWith('neodash_')) { paramsToSetAfterConnecting[key] = value; } }); - + sessionStorage.getItem('SSO_PARAMS_BEFORE_REDIRECT'); const page = urlParams.get('page'); if (page !== '' && page !== null) { if (!isNaN(page)) { dispatch(setPageNumberThunk(parseInt(page))); } } - const state = getState(); dispatch(setSSOEnabled(config.ssoEnabled, state.application.cachedSSODiscoveryUrl)); dispatch(setSSOProviders(config.ssoProviders)); // Check if we are in standalone mode - // const standaloneShared = localStorage.getItem('standaloneShared') == 'true'; // EDGE case: from url param it could happen that we lose the value due to SSO redirect - const { standalone } = config; - // || standaloneShared; + const standalone = config.standalone || urlParams.get('standalone') == 'Yes'; // if a dashboard database was previously set, remember to use it. const dashboardDatabase = state.application.standaloneDashboardDatabase; @@ -455,7 +457,6 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: config.standaloneDatabaseList ) ); - localStorage.removeItem('standaloneShared'); dispatch(setLoggingMode(config.loggingMode)); dispatch(setLoggingDatabase(config.loggingDatabase)); @@ -530,14 +531,18 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: } if (standalone) { - if (config.standaloneDashboardURL !== undefined && config.standaloneDashboardURL.length > 0) { + if (urlParams.get('id')) { + dispatch(setDashboardToLoadAfterConnecting(urlParams.get('id'))); + } else if (config.standaloneDashboardURL !== undefined && config.standaloneDashboardURL.length > 0) { dispatch(setDashboardToLoadAfterConnecting(config.standaloneDashboardURL)); } else { dispatch(setDashboardToLoadAfterConnecting(`name:${config.standaloneDashboardName}`)); } dispatch(setParametersToLoadAfterConnecting(paramsToSetAfterConnecting)); } + sessionStorage.removeItem('SSO_PARAMS_BEFORE_REDIRECT'); }); + dispatch(setWaitForSSO(false)); if (!success) { alert('Unable to connect using SSO. See the browser console for more details.'); @@ -550,6 +555,12 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: } else { return; } + } else if (state.application.ssoEnabled && !state.application.waitForSSO && urlParams) { + let paramsToStore = {}; + urlParams.forEach((value, key) => { + paramsToStore[key] = value; + }); + sessionStorage.setItem('SSO_PARAMS_BEFORE_REDIRECT', JSON.stringify(paramsToStore)); } if (standalone) { diff --git a/src/component/sso/SSOLoginButton.tsx b/src/component/sso/SSOLoginButton.tsx index b22b47163..fab194260 100644 --- a/src/component/sso/SSOLoginButton.tsx +++ b/src/component/sso/SSOLoginButton.tsx @@ -6,7 +6,7 @@ import { Button, IconButton } from '@neo4j-ndl/react'; export const SSOLoginButton = ({ discoveryAPIUrl, hostname, port, onSSOAttempt, onClick, providers }) => { const [savedSSOProviders, setSSOProviders] = useState([]); - const [discoveryUrlValidated, setDiscoveryUrlValidated] = useState(undefined); + const [discoveryUrlValidated, setDiscoveryUrlValidated] = useState(undefined); const filterByProvidersList = (discoveredProviders, validProviders) => { return validProviders == null || validProviders.length == 0 @@ -15,19 +15,26 @@ export const SSOLoginButton = ({ discoveryAPIUrl, hostname, port, onSSOAttempt, }; const attemptManualSSOProviderRetrieval = () => { // Do an extra check to see if the hostname provides some SSO provider configuration. - getDiscoveryDataInfo(`https://${hostname}:${port}`) + const protocol = isLocalhost(hostname) ? 'http' : 'https'; + const discoveryUrl = `${protocol}://${hostname}:${port}`; + getDiscoveryDataInfo(discoveryUrl) .then((mergedSSOProviders) => { setSSOProviders(filterByProvidersList(mergedSSOProviders, providers)); if (mergedSSOProviders.length == 0) { setDiscoveryUrlValidated(undefined); } else { - setDiscoveryUrlValidated(`https://${hostname}:${port}`); + setDiscoveryUrlValidated(discoveryUrl); } }) // eslint-disable-next-line no-console .catch((err) => console.error('Error in getDiscoveryDataInfo of Login component', err)); }; + function isLocalhost(hostname) { + const localhostNames = ['localhost', '127.0.0.1', '::1']; + return localhostNames.includes(hostname); + } + useEffect(() => { // First, try to get the SSO discovery URL from the config.json configuration file and see if it contains anything. getDiscoveryDataInfo(discoveryAPIUrl)