Skip to content

Commit

Permalink
config: attempt to harden jwk cache
Browse files Browse the repository at this point in the history
Replace failover with outageTolerantForever.

Failover is evaluated lazily, which makes little sense as it'll also
fail whenever the primary cache fails. The outage tolerant cache instead
populates its cache as the primary source successfully fetches new keys.

Also enable single retry for transient network errors, and set more
reasonable time-related properties.
  • Loading branch information
tronghn committed Sep 13, 2024
1 parent 8274c48 commit 8b35236
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import java.net.URL
import java.time.Duration
import java.util.concurrent.TimeUnit
import javax.sql.DataSource
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.seconds

private val log = KotlinLogging.logger {}

Expand Down Expand Up @@ -135,11 +136,11 @@ class SubjectTokenIssuer(private val wellKnownUrl: String, val subjectTokenClaim
}
val issuer = wellKnown.issuer
val cacheProperties = CacheProperties(
lifeSpan = 180.minutes,
refreshTime = 60.minutes,
timeToLive = 6.hours,
jwksURL = URL(wellKnown.jwksUri),
connectionTimeout = 5_000,
readTimeOut = 5_000,
connectionTimeout = 5.seconds,
readTimeout = 5.seconds,
refreshAheadTime = 1.hours,
)

init {
Expand Down
36 changes: 19 additions & 17 deletions src/main/kotlin/io/nais/security/oauth2/model/CacheProperties.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@ package io.nais.security.oauth2.model

import com.nimbusds.jose.jwk.source.JWKSource
import com.nimbusds.jose.jwk.source.JWKSourceBuilder
import com.nimbusds.jose.jwk.source.JWKSourceBuilder.DEFAULT_HTTP_CONNECT_TIMEOUT
import com.nimbusds.jose.jwk.source.JWKSourceBuilder.DEFAULT_HTTP_READ_TIMEOUT
import com.nimbusds.jose.jwk.source.JWKSourceBuilder.DEFAULT_HTTP_SIZE_LIMIT
import com.nimbusds.jose.proc.SecurityContext
import com.nimbusds.jose.util.DefaultResourceRetriever
import java.net.URL
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit

data class CacheProperties(
val lifeSpan: Duration,
val refreshTime: Duration,
val jwksURL: URL,
val connectionTimeout: Int = DEFAULT_HTTP_CONNECT_TIMEOUT,
val readTimeOut: Int = DEFAULT_HTTP_READ_TIMEOUT,
val sizeLimit: Int = DEFAULT_HTTP_SIZE_LIMIT
val timeToLive: Duration,
val connectionTimeout: Duration = JWKSourceBuilder.DEFAULT_HTTP_CONNECT_TIMEOUT.milliseconds,
val readTimeout: Duration = JWKSourceBuilder.DEFAULT_HTTP_READ_TIMEOUT.milliseconds,
val refreshAheadTime: Duration = JWKSourceBuilder.DEFAULT_REFRESH_AHEAD_TIME.milliseconds,
val refreshAheadScheduled: Boolean = true,
val refreshTimeout: Duration = JWKSourceBuilder.DEFAULT_CACHE_REFRESH_TIMEOUT.milliseconds,
val sizeLimitBytes: Int = JWKSourceBuilder.DEFAULT_HTTP_SIZE_LIMIT,
) {
private val foreverJwkSource = JWKSourceBuilder
.create<SecurityContext>(jwksURL, DefaultResourceRetriever(connectionTimeout, readTimeOut, sizeLimit))
.cacheForever()
.build()

private val resourceRetriever = DefaultResourceRetriever(
connectionTimeout.toInt(DurationUnit.MILLISECONDS),
readTimeout.toInt(DurationUnit.MILLISECONDS),
sizeLimitBytes
)
val jwkSource: JWKSource<SecurityContext> = JWKSourceBuilder
.create<SecurityContext>(jwksURL, DefaultResourceRetriever(connectionTimeout, readTimeOut, sizeLimit))
.cache(lifeSpan.inWholeMilliseconds, refreshTime.inWholeMilliseconds)
.failover(foreverJwkSource)
.create<SecurityContext>(jwksURL, resourceRetriever)
.cache(timeToLive.inWholeMilliseconds, refreshTimeout.inWholeMilliseconds)
.outageTolerantForever()
.rateLimited(false)
.refreshAheadCache(lifeSpan.inWholeMilliseconds / 2, true)
.refreshAheadCache(refreshAheadTime.inWholeMilliseconds, refreshAheadScheduled)
.retrying(true)
.build()
}

0 comments on commit 8b35236

Please sign in to comment.