Skip to content

Commit

Permalink
Merge pull request #11 from dancinnamon-okta/update_wellknown_call
Browse files Browse the repository at this point in the history
Update wellknown call
  • Loading branch information
TomLoomis-Evernorth authored May 3, 2024
2 parents a9a58e3 + 996f03f commit 0c83591
Showing 1 changed file with 58 additions and 105 deletions.
163 changes: 58 additions & 105 deletions lib/authorize.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,66 +28,68 @@ module.exports.authorizeHandler = async (requestQuerystring, requestHeaders, dat
if(idpUri && scopes && scopes.split(" ").includes("udap") && dataHolderOrIdpMode == 'dataholder') {
console.log("Tiered-OAuth request found.")
const oauthPlatformManagementClient = oauthPlatform.getAPIClient(process.env.OAUTH_ORG, process.env.OAUTH_CLIENT_ID, process.env.OAUTH_PRIVATE_KEY_FILE)
const idpValidationResult = await validateIDPUri(idpUri)

var finalIDPId = null
if(idpValidationResult.valid === 'true') {
console.log("URI is valid and belongs to our trust community.")
try {
const oauthIDPId = await oauthPlatform.getIdpIdByUri(idpUri, oauthPlatformManagementClient)
var newIDPInfo = null
//If OAuth Platform doesn't know this IDP yet, we need to register.
if(!oauthIDPId) {
console.log("No IDP found in OAuth Platform- registering.")
console.log("Getting additional OIDC metadata.")
const oidcMetadata = await readOIDCConfiguration(idpUri)

const oauthIDPInfo = await registerOAuthIDP(idpUri, idpValidationResult.validatedMetadataBody, oidcMetadata, oauthPlatform, oauthPlatformManagementClient)
newIDPInfo = oauthIDPInfo.newIdpMapping
finalIDPId = oauthIDPInfo.idpId
}
else {
finalIDPId = oauthIDPId
}

const authorizeProxyDetails = oauthPlatform.getAuthorizeProxyDetails(requestHeaders, requestQuerystring, finalIDPId)

console.debug("Final /authorize parameters: ")
console.debug(authorizeProxyDetails)

var oauthResult = await axios.request({
'url': backendAuthorizeUrl + "?" + authorizeProxyDetails.updatedQuerystring,
'method': 'GET',
'headers': authorizeProxyDetails.updatedHeaders,
'maxRedirects': 0,
'validateStatus': function (status) {
return true //We want to report on exactly what the OAuth Platform reports back, good or bad.
}
})
return {
statusCode: oauthResult.status,
headers: oauthResult.headers,
body: oauthResult.data,
newIdpMapping: newIDPInfo
const client = new udapClient(process.env.SERVER_KEY, process.env.SERVER_KEY_PWD, process.env.COMMUNITY_CERT, null, idpUri, process.env.ORGANIZATION_ID, process.env.ORGANIZATION_NAME, process.env.PURPOSE_OF_USE)

try {
await client.getAndValidateUdapMetadata(`${idpUri}/.well-known/udap`)
}
catch(error) {
return {
statusCode: 400,
body: {
'error': 'invalid_idp',
'error_description': error.message
}
}
catch(error) {
console.error(error)
return {
statusCode: 400,
body: {
'error': 'unable_to_register',
'error_description': 'Unable to register ourselves with the upstream IDP.'
}
}
var finalIDPId = null

console.log("URI is valid and belongs to our trust community.")
try {
const oauthIDPId = await oauthPlatform.getIdpIdByUri(idpUri, oauthPlatformManagementClient)
var newIDPInfo = null
//If OAuth Platform doesn't know this IDP yet, we need to register.
if(!oauthIDPId) {
console.log("No IDP found in OAuth Platform- registering.")
console.log("Getting additional OIDC metadata.")
const oidcMetadata = await readOIDCConfiguration(idpUri)

const oauthIDPInfo = await registerOAuthIDP(idpUri, client, oidcMetadata, oauthPlatform, oauthPlatformManagementClient)
newIDPInfo = oauthIDPInfo.newIdpMapping
finalIDPId = oauthIDPInfo.idpId
}
else {
finalIDPId = oauthIDPId
}

const authorizeProxyDetails = oauthPlatform.getAuthorizeProxyDetails(requestHeaders, requestQuerystring, finalIDPId)

console.debug("Final /authorize parameters: ")
console.debug(authorizeProxyDetails)

var oauthResult = await axios.request({
'url': backendAuthorizeUrl + "?" + authorizeProxyDetails.updatedQuerystring,
'method': 'GET',
'headers': authorizeProxyDetails.updatedHeaders,
'maxRedirects': 0,
'validateStatus': function (status) {
return true //We want to report on exactly what the OAuth Platform reports back, good or bad.
}
})
return {
statusCode: oauthResult.status,
headers: oauthResult.headers,
body: oauthResult.data,
newIdpMapping: newIDPInfo
}
}
else {
catch(error) {
console.error(error)
return {
statusCode: 400,
body: {
'error': 'invalid_idp',
'error_description': idpValidationResult.message
'error': 'unable_to_register',
'error_description': 'Unable to register ourselves with the upstream IDP.'
}
}
}
Expand Down Expand Up @@ -115,54 +117,6 @@ module.exports.authorizeHandler = async (requestQuerystring, requestHeaders, dat
}
}

//Takes the URI from the request, and looks up in OAuth Platform what the IDP ID would be.
async function validateIDPUri(idpUri) {
//Steps:
//1- attempt to get the /.well-known/udap from the idpUri
//2- validate the metadata coming back.
//3- return true/false if the metadata is valid.
try {
const trustAnchorObject = udapCommon.parseTrustAnchorPEM(process.env.COMMUNITY_CERT)

const metadataUrl = idpUri + '/.well-known/udap'
console.log('Getting metadata for idp at: ' + metadataUrl)
const metadataResponse = await axios.request({
'url': metadataUrl,
'method': 'GET',
'headers': {'Content-Type': 'application/fhir+json'}
})
console.log("Metadata response from IDP:")
console.log(metadataResponse.data)

if(!metadataResponse.data.signed_metadata) {
//TODO: Throw an error here so we can surface this better.
return {
'valid': 'false',
'code': 'missing_signed_metadata',
'message': 'The UDAP metadata file did not contain signed metadata.'
}
}

const metadataValidationDetail = await udapCommon.verifyUdapJwtCommon(metadataResponse.data.signed_metadata, trustAnchorObject)

console.log('UDAP IDP validated. Detail:')
console.log(metadataValidationDetail)
return {
'valid': 'true',
'code': 'Success',
'message': 'Metadata validated.',
'validatedMetadataBody': metadataValidationDetail.verifiedJwt.body
}
}
catch(e) {
return {
'valid': 'false',
'code': 'invalid_metadata',
'message': e.message
}
}
}

async function readOIDCConfiguration(idpBaseUrl) {
const oidcWellKnownEndpoint = idpBaseUrl + '/.well-known/openid-configuration'
console.log("Looking for OIDC metadata at: " + oidcWellKnownEndpoint)
Expand All @@ -180,7 +134,7 @@ async function readOIDCConfiguration(idpBaseUrl) {
return idpResponse.data
}

async function registerOAuthIDP(idpUri, validatedIDPMetadata, oidcMetadata, oauthPlatform, oauthPlatformManagementClient) {
async function registerOAuthIDP(idpUri, udapClient, oidcMetadata, oauthPlatform, oauthPlatformManagementClient) {
//TODO: Need to make these config variables.
const authzCodeRegistrationObject = {
client_name: "Tiered OAuth Test Data Holder",
Expand All @@ -194,8 +148,7 @@ async function registerOAuthIDP(idpUri, validatedIDPMetadata, oidcMetadata, oaut
}

console.log("Performing dynamic client registration with the IDP!")
const client = new udapClient(process.env.SERVER_KEY, process.env.SERVER_KEY_PWD, process.env.COMMUNITY_CERT, null, idpUri, process.env.ORGANIZATION_ID, process.env.ORGANIZATION_NAME, process.env.PURPOSE_OF_USE)
const externalIdpData = await client.udapDynamicClientRegistration(authzCodeRegistrationObject)
const externalIdpData = await udapClient.udapDynamicClientRegistration(authzCodeRegistrationObject)

console.log("Registration result:")
console.log(externalIdpData)
Expand All @@ -206,8 +159,8 @@ async function registerOAuthIDP(idpUri, validatedIDPMetadata, oidcMetadata, oaut
console.log("Invoking the OAuth Platform API to create the IDP...")
const idpDetail = {
idpUri: idpUri,
authorizeUrl: validatedIDPMetadata.authorization_endpoint,
tokenUrl: validatedIDPMetadata.token_endpoint,
authorizeUrl: udapClient.signedMetadata.authorization_endpoint,
tokenUrl: udapClient.signedMetadata.token_endpoint,
userInfoUrl: oidcMetadata.userinfo_endpoint,
jwksUrl: oidcMetadata.jwks_uri,
clientId: externalIdpData.data.client_id,
Expand Down

0 comments on commit 0c83591

Please sign in to comment.