Skip to content

Commit

Permalink
fix(config): retry request failures when fetching well-known documents
Browse files Browse the repository at this point in the history
  • Loading branch information
tronghn committed Sep 20, 2023
1 parent 844ebab commit 1e9380f
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 4 deletions.
21 changes: 20 additions & 1 deletion src/main/kotlin/io/nais/security/oauth2/TokenExchangeApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.nimbusds.oauth2.sdk.ErrorObject
import com.nimbusds.oauth2.sdk.OAuth2Error
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.HttpRequestRetry
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.jackson.jackson
Expand Down Expand Up @@ -57,9 +58,11 @@ import org.slf4j.event.Level
import java.util.UUID
import java.util.concurrent.TimeUnit.SECONDS
import kotlin.system.exitProcess
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation as ClientContentNegotiation

private val log = KotlinLogging.logger { }

const val httpClientMaxRetries = 10
const val shutdownGracePeriod = 10L
const val shutdownMaxWait = 20L

Expand Down Expand Up @@ -141,12 +144,15 @@ fun Application.tokenExchangeApp(config: AppConfiguration, routing: ApiRouting)
val includeErrorDetails = isNonProd()
call.respondWithError(cause, includeErrorDetails)
}

is BadRequestException -> {
call.respond(HttpStatusCode.BadRequest, "invalid request content")
}

is JsonProcessingException -> {
call.respond(HttpStatusCode.BadRequest, "invalid request content")
}

else -> {
call.respond(HttpStatusCode.InternalServerError, "unknown internal server error")
}
Expand Down Expand Up @@ -195,10 +201,23 @@ private fun ErrorObject.toGeneric(): ErrorObject =
)

internal val defaultHttpClient = HttpClient(CIO) {
install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
install(ClientContentNegotiation) {
jackson() {
setSerializationInclusion(NON_NULL)
configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
}
}
}

internal val retryingHttpClient = HttpClient(CIO) {
install(ClientContentNegotiation) {
jackson() {
setSerializationInclusion(NON_NULL)
configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
}
}
install(HttpRequestRetry) {
retryOnExceptionOrServerErrors(maxRetries = httpClientMaxRetries)
exponentialDelay()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import io.nais.security.oauth2.authentication.BearerTokenAuth
import io.nais.security.oauth2.config.JwkCache.BUCKET_SIZE
import io.nais.security.oauth2.config.JwkCache.CACHE_SIZE
import io.nais.security.oauth2.config.JwkCache.EXPIRES_IN
import io.nais.security.oauth2.defaultHttpClient
import io.nais.security.oauth2.health.DatabaseHealthCheck
import io.nais.security.oauth2.health.HealthCheck
import io.nais.security.oauth2.keystore.RotatingKeyStore
Expand All @@ -23,6 +22,7 @@ import io.nais.security.oauth2.model.ClaimMappings
import io.nais.security.oauth2.model.WellKnown
import io.nais.security.oauth2.registration.ClientRegistry
import io.nais.security.oauth2.registration.ClientRegistryPostgres
import io.nais.security.oauth2.retryingHttpClient
import io.nais.security.oauth2.token.TokenIssuer
import kotlinx.coroutines.runBlocking
import mu.KotlinLogging
Expand Down Expand Up @@ -85,7 +85,7 @@ class AuthProvider(
fun fromWellKnown(wellKnownUrl: String): AuthProvider {
val wellKnown: WellKnown = runBlocking {
log.info("getting OpenID Connect server metadata from well-known url=$wellKnownUrl")
defaultHttpClient.get(wellKnownUrl).body()
retryingHttpClient.get(wellKnownUrl).body()
}
val jwk = JwkProviderBuilder(URL(wellKnown.jwksUri))
.cached(CACHE_SIZE, EXPIRES_IN, TimeUnit.HOURS)
Expand Down Expand Up @@ -130,7 +130,7 @@ class AuthorizationServerProperties(
class SubjectTokenIssuer(private val wellKnownUrl: String, val subjectTokenClaimMappings: ClaimMappings = emptyMap()) {
val wellKnown: WellKnown = runBlocking {
log.info("getting OAuth2 server metadata from well-known url=$wellKnownUrl")
defaultHttpClient.get(wellKnownUrl).body()
retryingHttpClient.get(wellKnownUrl).body()
}
val issuer = wellKnown.issuer
val cacheProperties = CacheProperties(
Expand Down

0 comments on commit 1e9380f

Please sign in to comment.