UNPKG

neo4j-client-sso

Version:

Single sign-on client (frontend) library for Neo4j products

165 lines (164 loc) 7.93 kB
/* * Copyright (c) "Neo4j" * Neo4j Sweden AB [http://neo4j.com] * * This file is part of Neo4j. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import jwtDecode from 'jwt-decode'; import pick from 'lodash.pick'; import { isObject } from './utils'; import { AUTH_STORAGE_REFRESH_DATA, AUTH_STORAGE_URL_SEARCH_PARAMS, REDIRECT_URI, SSO_REDIRECT } from './constants'; import { addSearchParamsInBrowserHistory, authLog, authDebug } from './helpers'; import { defaultTokenTypeAuthentication, defaultTokenTypePrincipal, mandatoryKeysForSSOProviderParams, mandatoryKeysForSSOProviders } from './settings'; export const getInitialisationParameters = () => { const urlSearchParams = window.location.search; const urlHashParamsAsSearchParams = '?' + window.location.hash.substring(1); const initParams = {}; new URLSearchParams(urlSearchParams).forEach((value, key) => { initParams[key] = value; }); new URLSearchParams(urlHashParamsAsSearchParams).forEach((value, key) => { initParams[key] = value; }); return initParams; }; export const getValidSSOProviders = (discoveredSSOProviders) => { if (!discoveredSSOProviders) { return []; } if (!Array.isArray(discoveredSSOProviders)) { authLog(`Discovered SSO providers should be a list, got ${discoveredSSOProviders}`, 'warn'); } if (discoveredSSOProviders.length === 0) { authLog('List of discovered SSO providers was empty'); return []; } const validSSOProviders = discoveredSSOProviders.filter(provider => { const missingKeys = mandatoryKeysForSSOProviders.filter(key => !provider.hasOwnProperty(key)); if (missingKeys.length !== 0) { authLog(`Dropping invalid discovered sso provider with id: "${provider.id}", missing key(s) ${missingKeys.join(', ')} `); return false; } const missingParamKeys = mandatoryKeysForSSOProviderParams.filter(key => !provider.params.hasOwnProperty(key)); if (missingParamKeys.length !== 0) { authLog(`Dropping invalid discovered SSO provider with id: "${provider.id}", missing params key(s) ${missingParamKeys.join(', ')}`); return false; } return true; }); authLog('Checked SSO providers'); return validSSOProviders.map(ssoProvider => (Object.assign({ // visibility was introduced in 5.14.0 and defaults to true visible: true }, ssoProvider))); }; export const getCredentialsFromAuthResult = (result, selectedSSOProvider) => { var _a, _b, _c; authLog(`Attempting to assemble credentials for idp_id: ${selectedSSOProvider.id}`); if (!selectedSSOProvider) { throw new Error('No SSO provider passed'); } if (!result) { throw new Error('Missing result in auth result handler'); } const tokenTypePrincipal = ((_a = selectedSSOProvider.config) === null || _a === void 0 ? void 0 : _a['token_type_principal']) || defaultTokenTypePrincipal; authLog(`Credentials, using token type "${tokenTypePrincipal}" to retrieve principal`); let parsedJWT; try { parsedJWT = jwtDecode(result[tokenTypePrincipal]); } catch (err) { } if (!parsedJWT) { throw new Error(`Could not parse JWT of type "${tokenTypePrincipal}" for idp_id "${selectedSSOProvider.id}", aborting`); } authDebug('Credentials, parsed JWT', parsedJWT); const principal = (_b = selectedSSOProvider.config) === null || _b === void 0 ? void 0 : _b.principal; if (principal) { authLog(`Credentials, provided principal in config: ${principal}`); } else { authLog(`Credentials, no principal provided in config, falling back to 'email' then 'sub'`); } const credsPrincipal = parsedJWT[principal] || parsedJWT.email || parsedJWT.sub; authLog(`Credentials assembly with username: ${credsPrincipal}`); const configuredTokenType = (_c = selectedSSOProvider.config) === null || _c === void 0 ? void 0 : _c['token_type_authentication']; const tokenTypeAuthentication = configuredTokenType || defaultTokenTypeAuthentication; if (!configuredTokenType) { authLog(`token_type_authentication not configured, using default token type "${defaultTokenTypeAuthentication}".`); } authLog(`Credentials assembled with token type "${tokenTypeAuthentication}" as password. If connection still does not succeed, make sure 'neo4j.conf' is set up correctly`); return { username: credsPrincipal, password: result[tokenTypeAuthentication] }; }; export const temporarilyStoreUrlSearchParams = () => { const currentBrowserURLParams = getInitialisationParameters(); authLog(`Temporarily storing the url search params. data: "${JSON.stringify(currentBrowserURLParams)}"`); window.sessionStorage.setItem(AUTH_STORAGE_URL_SEARCH_PARAMS, JSON.stringify(currentBrowserURLParams)); }; export const storeRefreshTokenData = (refreshToken, selectedSSOProviderId) => { authLog('Storing refresh data'); window.sessionStorage.setItem(AUTH_STORAGE_REFRESH_DATA, JSON.stringify({ refreshToken, selectedSSOProviderId })); }; export const retrieveRefreshTokenData = () => { const emptyResponse = { refreshToken: null, selectedSSOProviderId: null }; try { const data = window.sessionStorage.getItem(AUTH_STORAGE_REFRESH_DATA); if (!data) return emptyResponse; return JSON.parse(data); } catch (err) { authLog(`Parsing of refresh token data failed, err: ${err}`); return emptyResponse; } }; export const clearRefreshTokenData = () => window.sessionStorage.removeItem(AUTH_STORAGE_REFRESH_DATA); export const getSSOServerIdIfShouldRedirect = () => { const { searchParams } = new URL(window.location.href); return searchParams.get(SSO_REDIRECT); }; export const wasRedirectedBackFromSSOServer = () => { const { auth_flow_step: authFlowStep } = getInitialisationParameters(); return (authFlowStep || '').toLowerCase() === REDIRECT_URI; }; export const restoreSearchAndHashParams = (toRetrieveParams = [], isClearStore = true) => { authLog(`Retrieving temporarily stored url search params, params to retrieve: "${toRetrieveParams}"`); try { const storedParams = JSON.parse(window.sessionStorage.getItem(AUTH_STORAGE_URL_SEARCH_PARAMS)); if (isClearStore) { authLog('Clearing temporarily stored url search params.'); window.sessionStorage.removeItem(AUTH_STORAGE_URL_SEARCH_PARAMS); } if (!isObject(storedParams)) { throw new Error(`Stored search params were ${storedParams}, expected an object.`); } let parameters = storedParams; if (toRetrieveParams === null || toRetrieveParams === void 0 ? void 0 : toRetrieveParams.length) { parameters = pick(storedParams, toRetrieveParams); } const crntHashParams = window.location.hash || undefined; addSearchParamsInBrowserHistory(parameters); const newUrl = `${window.location.href}${crntHashParams || ''}`; window.history.replaceState({}, '', newUrl); return parameters; } catch (err) { authLog(`Error when parsing temporarily stored url search params, err: ${err}. Clearing.`); window.sessionStorage.removeItem(AUTH_STORAGE_URL_SEARCH_PARAMS); return null; } };