Skip to content

Commit

Permalink
hacked together
Browse files Browse the repository at this point in the history
  • Loading branch information
OskarDamkjaer committed Jul 20, 2021
1 parent 3318941 commit 1f4c490
Show file tree
Hide file tree
Showing 12 changed files with 836 additions and 15 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,12 @@
"isomorphic-fetch": "^2.2.1",
"jsonic": "^0.3.0",
"jszip": "^3.2.2",
"jwt-decode": "^3.1.2",
"lodash-es": "^4.17.15",
"memoize-one": "^5.2.1",
"monaco-editor": "0.23.0",
"neo4j-driver": "^4.3.1",
"querystring": "^0.2.1",
"react": "^16.9.0",
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",
Expand Down
12 changes: 12 additions & 0 deletions src/browser/modules/Stream/Auth/ConnectForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import { NATIVE, NO_AUTH } from 'services/bolt/boltHelpers'
import { toKeyString } from 'services/utils'
import { stripScheme, getScheme } from 'services/boltscheme.utils'
import { AuthenticationMethod } from 'shared/modules/connections/connectionsDuck'
import { authRequestForSSO } from 'shared/modules/auth/index.js'
import { getSSOProvidersFromStorage } from 'shared/modules/auth/common.js'

const readableauthenticationMethods: Record<AuthenticationMethod, string> = {
[NATIVE]: 'Username / Password',
Expand Down Expand Up @@ -64,6 +66,8 @@ export default function ConnectForm(props: ConnectFormProps): JSX.Element {
props.allowedSchemes ? `${getScheme(props.host)}://` : ''
)

const ssoProviders = getSSOProvidersFromStorage()

useEffect(() => {
if (props.allowedSchemes) {
return setScheme(`${getScheme(props.host)}://`)
Expand Down Expand Up @@ -118,6 +122,14 @@ export default function ConnectForm(props: ConnectFormProps): JSX.Element {

return (
<StyledConnectionForm onSubmit={onConnectClick}>
{ssoProviders.map((provider: any) => (
<button
key={provider.id}
onClick={() => authRequestForSSO(provider.id)}
>
hej {provider.name}
</button>
))}
<StyledConnectionFormEntry>
<StyledConnectionLabel htmlFor="url-input" title={hoverText}>
Connect URL
Expand Down
233 changes: 233 additions & 0 deletions src/shared/modules/auth/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import jwtDecode from 'jwt-decode'
import { isObject, pick } from 'lodash'
import {
AUTH_STORAGE_SSO_PROVIDERS,
AUTH_STORAGE_URL_SEARCH_PARAMS
} from './constants'
import { addSearchParamsInBrowserHistory, authLog } from './helpers'
import {
mandatoryKeysForSSOProviderParams,
mandatoryKeysForSSOProviders,
searchParamsToSaveForAfterAuthRedirect
} from './settings'
import { parse as parseQueryString } from 'querystring'

export const getInitialisationParameters = (
urlSearchParams = window.location.search,
urlHashParams = window.location.hash
) => {
let initParams = {}
try {
initParams = {
...parseQueryString(urlSearchParams.replace(/^\?/, '')),
...parseQueryString(urlHashParams.replace(/^#/, ''))
}
Object.keys(initParams).forEach(key => {
if (initParams[key].trim().length === 0) {
initParams[key] = null
}
})
} catch (exc) {
console.warn('Exception occured while parsing Browser URL parameters', exc)
}
return initParams
}

export const checkAndMergeSSOProviders = (
discoveredSSOProviders,
isLocalhostOrigin
) => {
if (!discoveredSSOProviders || !discoveredSSOProviders.length) {
authLog('Invalid discovered SSO providers')
return
}

let currentSSOProviders =
JSON.parse(window.sessionStorage.getItem(AUTH_STORAGE_SSO_PROVIDERS)) || []
if (!Array.isArray(currentSSOProviders)) {
authLog(
'Found SSO providers in storage are defect, consider clearing the SSO provider state and reload',
'warn'
)
currentSSOProviders = []
}

discoveredSSOProviders.forEach(provider => {
if (!provider) return
if (
!mandatoryKeysForSSOProviders.every(key => provider.hasOwnProperty(key))
) {
authLog(
`Dropping invalid discovered SSO provider with id: "${provider.id}", missing key`
)
return
}
if (
!mandatoryKeysForSSOProviderParams.every(key =>
provider?.params?.hasOwnProperty(key)
)
) {
authLog(
`Dropping invalid discovered SSO provider with id: "${provider.id}", missing params key`
)
return
}
if (
currentSSOProviders.find(crntProvider => crntProvider.id === provider.id)
) {
if (isLocalhostOrigin) {
const idx = currentSSOProviders.findIndex(
crntProvider => crntProvider.id === provider.id
)
currentSSOProviders.splice(idx, 1)
authLog(`Updating SSO provider with id: "${provider.id}"`)
} else {
authLog(
`Not accepting discovered SSO provider with id: "${provider.id}", id exists already`
)
return
}
}
currentSSOProviders.push(provider)
})

window.sessionStorage.setItem(
AUTH_STORAGE_SSO_PROVIDERS,
JSON.stringify(currentSSOProviders)
)
authLog('Checked and merged SSO providers')
}

export const getSSOProvidersFromStorage = () => {
const ssoProviders = JSON.parse(
window.sessionStorage.getItem(AUTH_STORAGE_SSO_PROVIDERS)
)
if (!ssoProviders || !ssoProviders.length) {
authLog('No SSO providers in (local) storage found')
return []
}
return ssoProviders
}

export const getSSOProviderByIdpId = idpId => {
const ssoProviders = getSSOProvidersFromStorage()

const selectedSSOProvider = ssoProviders.find(
provider => provider.id === idpId
)
if (!selectedSSOProvider) {
authLog(`No matching SSO provider to passed in argument: ${idpId}`, 'warn')
return null
}
return selectedSSOProvider
}

export const getCredentialsFromAuthResult = (result, idpId) => {
const _parseJWTAndSetCredentials = toParseToken => {
const parsedJWT = jwtDecode(toParseToken)

// TODO: remove this
console.log('Parsed JWT: ', parsedJWT)

if (!parsedJWT) {
authLog(`Could not parse JWT for idp_id: ${idpId}, aborting`, 'warn')
return { username: '', password: '' }
}

const email = parsedJWT[principal] || parsedJWT.email || parsedJWT.sub
authLog(`Credentials assembly, username: ${email}`)

return { username: email, password: result.access_token }
}

let credentials = {}
authLog(`Attempting to assemble credentials for idp_id: ${idpId}`)

if (!result || !idpId) {
authLog('No result or idp_id passed in', 'warn')
return credentials
}

const selectedSSOProvider = getSSOProviderByIdpId(idpId)
if (!selectedSSOProvider) return

const principal = selectedSSOProvider.config?.principal || ''
authLog(`Credentials, principal: ${principal}`)

switch (idpId) {
case 'google-oidc':
if (!result.id_token) {
authLog('No id_token in google-oidc result!', 'warn')
authLog(
`We do not support auth_flow: "${selectedSSOProvider.auth_flow}" for idp_id: "${idpId}" at the moment`,
'warn'
)
// INFO: Another HTTP call would be needed to get an id_token.
credentials = { username: '', password: '' }
break
}
credentials = _parseJWTAndSetCredentials(result.id_token)
break
default:
credentials = _parseJWTAndSetCredentials(result.access_token)
break
}
return credentials
}

export const temporarlyStoreUrlSearchParams = () => {
const currentBrowserURLParams = getInitialisationParameters()
const toSaveSearchParams = pick(
currentBrowserURLParams,
searchParamsToSaveForAfterAuthRedirect
)

authLog(
`Temporarly storing the url search params. data: "${JSON.stringify(
toSaveSearchParams
)}"`
)
window.sessionStorage.setItem(
AUTH_STORAGE_URL_SEARCH_PARAMS,
JSON.stringify(toSaveSearchParams)
)
}

export const addStoredUrlSearchParamsToBrowserHistory = (
toRetrieveParams,
isClearStore = false
) => {
if (!toRetrieveParams || !toRetrieveParams.length) {
authLog(
'Invalid arguments provided for retrieving temporarly stored url search params, aborting'
)
return
}

authLog(
`Retrieving temporarly stored url search params, params: "${toRetrieveParams}"`
)
try {
const storedParams = JSON.parse(
window.sessionStorage.getItem(AUTH_STORAGE_URL_SEARCH_PARAMS)
)

if (isClearStore) {
window.sessionStorage.setItem(AUTH_STORAGE_URL_SEARCH_PARAMS, '')
}

if (isObject(storedParams)) {
const retrievedParams = pick(storedParams, toRetrieveParams)
addSearchParamsInBrowserHistory(retrievedParams)
return retrievedParams
} else {
authLog('Invalid temporarly stored url search params')
return null
}
} catch (err) {
authLog(
`Error when parsing temporarly stored url search params, err: ${err}`
)
return null
}
}
13 changes: 13 additions & 0 deletions src/shared/modules/auth/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const REDIRECT_URI = 'redirect_uri'
export const SSO_REDIRECT = 'sso_redirect'
export const BEARER = 'bearer'
export const PKCE = 'pkce'
export const IMPLICIT = 'implicit'

export const AUTH_LOGGING_PREFIX = 'OIDC/OAuth#'

const AUTH_STORAGE_PREFIX = '/auth#'
export const AUTH_STORAGE_SSO_PROVIDERS = `${AUTH_STORAGE_PREFIX}sso_providers`
export const AUTH_STORAGE_STATE = `${AUTH_STORAGE_PREFIX}state`
export const AUTH_STORAGE_CODE_VERIFIER = `${AUTH_STORAGE_PREFIX}code_verifier`
export const AUTH_STORAGE_URL_SEARCH_PARAMS = `${AUTH_STORAGE_PREFIX}url_search_params`
Loading

0 comments on commit 1f4c490

Please sign in to comment.