Skip to content

Commit

Permalink
Fixed CheckFunction to allow check report URL endpoint alive (#15850)
Browse files Browse the repository at this point in the history
* Fixed CheckFunction to allow check report URL endpoint alive

* Cleanup

* Moved common code to getAccessToken function

* Moved common code to getAccessToken function
  • Loading branch information
oslynn authored Sep 16, 2024
1 parent 5042115 commit fe3d9d7
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 35 deletions.
1 change: 1 addition & 0 deletions .environment/gitleaks/gitleaks-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ title = "PRIME ReportStream Gitleaks Configuration"
'authority\", \"extension\"', # FHIR extension URL also shows up in normal FHIR test data
'ApiKeyCredential\(\"flexion\"',
'authType: \"two-legged\"',
'authType == "two-legged"',
'\"apiKey\"',
'api-key\" to \"oracle123\"',
'Authorization-Type: \"username/password\"',
Expand Down
75 changes: 60 additions & 15 deletions prime-router/src/main/kotlin/azure/CheckFunction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ import gov.cdc.prime.router.common.JacksonMapperUtilities
import gov.cdc.prime.router.tokens.AuthenticatedClaims
import gov.cdc.prime.router.tokens.authenticationFailure
import gov.cdc.prime.router.transport.RESTTransport
import gov.cdc.prime.router.transport.RESTTransport.Companion.buildHeaders
import gov.cdc.prime.router.transport.SftpTransport
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import net.schmizz.sshj.sftp.RemoteResourceFilter
Expand Down Expand Up @@ -342,6 +348,8 @@ class CheckFunction : Logging {
): Boolean {
logger.info("REST Transport $restTransportType")
responseBody.add("${receiver.fullName}: REST Transport")
var msg = "${receiver.fullName}: Success: received connection is alive"
var retVal = true
try {
val theRESTTransport = RESTTransport()
val reportId = UUID.randomUUID().toString()
Expand All @@ -354,28 +362,65 @@ class CheckFunction : Logging {
runBlocking {
launch {
val httpHeaders = theRESTTransport.getHeaders(restTransportType, reportId)
val accessToken: String =
theRESTTransport.getOAuthToken(
restTransportType,
jksCredential,
credential,
aLogger

val accessToken = theRESTTransport.getAccessToken(
restTransportType,
jksCredential,
credential,
httpHeaders,
aLogger
)

// Try to GET something from the endpoint
val response = getFromUrl(
restTransportType.reportUrl,
httpHeaders,
RESTTransport.createDefaultHttpClient(
jksCredential, accessToken,
restTransportType
)
)

val msg = when {
accessToken.isNotEmpty() -> "${receiver.fullName}: Success: received OAuth token"
httpHeaders.isNotEmpty() -> "${receiver.fullName}: Success: received Authentication header"
else -> error("${receiver.fullName}: Failure: no valid response from RESTTransport")
if (response.status == HttpStatusCode.InternalServerError) {
msg = "${receiver.fullName}: Failure: 500 Internal Error Occured"
retVal = false
}
logger.info(msg)
responseBody.add(msg)
}
}
} catch (t: Throwable) {
trackException(t, responseBody, receiver)
return false
if (t.message!!.contains("connect_timeout") ||
t.message!!.contains("Unable to find credentials")
) {
// Fail if there is timeout or Unable to find credential from Vault
trackException(t, responseBody, receiver)
return false
}
}

responseBody.add(msg)
return retVal
}

/**
* getFromURL extracts something from provided URL.
*
* @param url - Url to extract
* @param headers - headers
* @param httpClient - given http client engine
*
*/
suspend fun getFromUrl(
url: String,
headers: Map<String, String>,
httpClient: HttpClient,
): HttpResponse {
httpClient.use { client ->
return client.get(url) {
buildHeaders(
headers.map { (key, value) -> Pair(key, value) }.toMap()
)
}
}
return true
}

/**
Expand Down
65 changes: 45 additions & 20 deletions prime-router/src/main/kotlin/transport/RESTTransport.kt
Original file line number Diff line number Diff line change
Expand Up @@ -109,26 +109,14 @@ class RESTTransport(private val httpClient: HttpClient? = null) : ITransport {
launch {
try {
val httpHeaders = getHeaders(restTransportInfo, reportId)
var accessToken: String? = null

if (restTransportInfo.authType == "apiKey") {
val apiKeyCredential = credential as UserApiKeyCredential
httpHeaders["shared-api-key"] = apiKeyCredential.apiKey
httpHeaders["System_ID"] = apiKeyCredential.user
httpHeaders["Key"] = apiKeyCredential.apiKey
accessToken = apiKeyCredential.apiKey
}

if (restTransportInfo.authType == "two-legged" || restTransportInfo.authType == null) {
// parse headers for any dynamic values, OK needs the report ID
accessToken = getOAuthToken(
restTransportInfo,
jksCredential,
credential,
logger
)
logger.info("Token successfully added!")
}
val accessToken = getAccessToken(
restTransportInfo,
jksCredential,
credential,
httpHeaders,
logger
)

// If encryption is needed.
if (restTransportInfo.encryptionKeyUrl.isNotEmpty()) {
Expand Down Expand Up @@ -322,6 +310,43 @@ class RESTTransport(private val httpClient: HttpClient? = null) : ITransport {
}.toMutableMap()
}

/**
* Get the Accesstoken based on authType given in Restransport header
*
* @param restTransportInfo - Transport setting
* @param jksCredential The jks credential
*/
suspend fun getAccessToken(
restTransportInfo: RESTTransportType,
jksCredential: UserJksCredential?,
credential: RestCredential,
httpHeaders: MutableMap<String, String>,
logger: Logger,
): String? {
var accessToken: String? = null

if (restTransportInfo.authType == "apiKey") {
val apiKeyCredential = credential as UserApiKeyCredential
httpHeaders["shared-api-key"] = apiKeyCredential.apiKey
httpHeaders["System_ID"] = apiKeyCredential.user
httpHeaders["Key"] = apiKeyCredential.apiKey
accessToken = apiKeyCredential.apiKey
}

if (restTransportInfo.authType == "two-legged" || restTransportInfo.authType == null) {
// parse headers for any dynamic values, OK needs the report ID
accessToken = getOAuthToken(
restTransportInfo,
jksCredential,
credential,
logger
)
logger.info("Token successfully added!")
}

return accessToken
}

/**
* Get the OAuth token based on credential type
*
Expand Down Expand Up @@ -621,7 +646,7 @@ class RESTTransport(private val httpClient: HttpClient? = null) : ITransport {
}

/** Our default Http Client, with an optional SSL context, and optional auth token */
private fun createDefaultHttpClient(
fun createDefaultHttpClient(
jks: UserJksCredential?,
accessToken: String?,
restTransportInfo: RESTTransportType?,
Expand Down

0 comments on commit fe3d9d7

Please sign in to comment.