Cache OIDC provider records to skip per-login discovery (#9295)

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
Dexterity 2026-05-19 11:38:08 -04:00 committed by GitHub
parent bcc0b0d313
commit ade587968f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 10 deletions

View File

@ -27,6 +27,7 @@
[app.rpc.commands.profile :as profile]
[app.setup :as-alias setup]
[app.tokens :as tokens]
[app.util.cache :as cache]
[app.util.inet :as inet]
[app.util.json :as json]
[buddy.sign.jwk :as jwk]
@ -694,15 +695,24 @@
(db/pgarray? roles)
(assoc :roles (db/decode-pgarray roles #{}))))
;; TODO: add cache layer for avoid build an discover each time
;; A short TTL avoids paying the OIDC discovery + JWKS fetch on every
;; login; Caffeine will not store the entry when the load fn throws,
;; so a transient failure at the provider's discovery endpoint does
;; not poison the cache.
(defonce ^:private provider-cache
(cache/create :expire "10m" :max-size 64))
(defn- load-provider
[cfg id]
(when-let [params (some->> (db/get* cfg :sso-provider {:id id :is-enabled true})
(decode-row))]
(case (:type params)
"oidc" (prepare-oidc-provider cfg params))))
(defn get-provider
[cfg id]
(try
(when-let [params (some->> (db/get* cfg :sso-provider {:id id :is-enabled true})
(decode-row))]
(case (:type params)
"oidc" (prepare-oidc-provider cfg params)))
(cache/get provider-cache id (partial load-provider cfg))
(catch Throwable cause
(l/err :hint "unable to configure custom SSO provider"
:provider (str id)

View File

@ -12,7 +12,6 @@
[app.common.time :as ct]
[promesa.exec :as px])
(:import
com.github.benmanes.caffeine.cache.AsyncCache
com.github.benmanes.caffeine.cache.Cache
com.github.benmanes.caffeine.cache.Caffeine
com.github.benmanes.caffeine.cache.RemovalListener
@ -47,15 +46,18 @@
:miss-rate (.missRate stats)}))
(defn create
[& {:keys [executor on-remove max-size keepalive]}]
"Build an in-memory cache. Loads run synchronously on the calling
thread, so when a load fn throws or returns nil the entry is not
stored concurrent loads for the same key still deduplicate."
[& {:keys [executor on-remove max-size keepalive expire]}]
(let [cache (as-> (Caffeine/newBuilder) builder
(if (fn? on-remove) (.removalListener builder (create-listener on-remove)) builder)
(if executor (.executor builder ^Executor (px/resolve-executor executor)) builder)
(if keepalive (.expireAfterAccess builder ^Duration (ct/duration keepalive)) builder)
(if expire (.expireAfterWrite builder ^Duration (ct/duration expire)) builder)
(if (int? max-size) (.maximumSize builder (long max-size)) builder)
(.recordStats builder)
(.buildAsync builder))
cache (.synchronous ^AsyncCache cache)]
(.build builder))]
(reify
ICache
(get [_ k]
@ -69,7 +71,7 @@
(invalidate! [_]
(.invalidateAll ^Cache cache))
(invalidate! [_ k]
(.invalidateAll ^Cache cache ^Object k))
(.invalidate ^Cache cache ^Object k))
ICacheStats
(stats [_]