diff --git a/ChangeLog b/ChangeLog index 4c764d3..cbeb423 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,9 +2,10 @@ - if lifecyle handlers return truthy values they cause the operation they are handlers of to fail; see #384; thanks to @arcivanov -09/19/2021 -- made jwt_verify() and bearer_jwt_verify() honor - opts.introspection_cache_ignore as well. +09/22/2021 +- made jwt_verify() and bearer_jwt_verify() use a separate cache named + "jwt_verification" and introduced opts.jwt_verification_cache_ignore + to disable caching completely 12/05/2020 - fixed a session leak in access_token() and for a very unlikely diff --git a/README.md b/README.md index 6258e3c..7f902f0 100644 --- a/README.md +++ b/README.md @@ -316,7 +316,7 @@ http { resolver 8.8.8.8; # cache for JWT verification results - lua_shared_dict introspection 10m; + lua_shared_dict jwt_verification 10m; server { listen 8080; @@ -376,9 +376,9 @@ lAc5Csj0o5Q+oEhPUAVBIF07m4rd0OvAVPOCQ2NJhQSL1oWASbf+fg== -- the expiration time in seconds for jwk cache, default is 1 day. --jwk_expires_in = 24 * 60 * 60 - -- It may be necessary to force an introspection call for a bearer token and ignore the existing cached - -- introspection results. If so you need to set set the introspection_cache_ignore option to true. - -- introspection_cache_ignore = true + -- It may be necessary to force verification for a bearer token and ignore the existing cached + -- verification results. If so you need to set set the jwt_verification_cache_ignore option to true. + -- jwt_verification_cache_ignore = true } -- call bearer_jwt_verify for OAuth 2.0 JWT validation diff --git a/lib/resty/openidc.lua b/lib/resty/openidc.lua index b4dfbfd..435e363 100644 --- a/lib/resty/openidc.lua +++ b/lib/resty/openidc.lua @@ -132,6 +132,7 @@ function openidc.invalidate_caches() openidc_cache_invalidate("discovery") openidc_cache_invalidate("jwks") openidc_cache_invalidate("introspection") + openidc_cache_invalidate("jwt_verification") end -- validate the contents of and id_token @@ -1612,6 +1613,20 @@ local function openidc_get_bearer_access_token(opts) return access_token, err end +local function get_cached_introspection(opts, access_token) + local introspection_cache_ignore = opts.introspection_cache_ignore or false + if not introspection_cache_ignore then + return openidc_cache_get("introspection", access_token) + end +end + +local function set_cached_introspection(opts, access_token, encoded_json, ttl) + local introspection_cache_ignore = opts.introspection_cache_ignore or false + if not introspection_cache_ignore then + openidc_cache_set("introspection", access_token, encoded_json, ttl) + end +end + -- main routine for OAuth 2.0 token introspection function openidc.introspect(opts) @@ -1623,12 +1638,7 @@ function openidc.introspect(opts) -- see if we've previously cached the introspection result for this access token local json - local v - local introspection_cache_ignore = opts.introspection_cache_ignore or false - - if not introspection_cache_ignore then - v = openidc_cache_get("introspection", access_token) - end + local v = get_cached_introspection(opts, access_token) if v then json = cjson.decode(v) @@ -1679,10 +1689,11 @@ function openidc.introspect(opts) end -- cache the results + local introspection_cache_ignore = opts.introspection_cache_ignore or false local expiry_claim = opts.introspection_expiry_claim or "exp" - local introspection_interval = opts.introspection_interval or 0 if not introspection_cache_ignore and json[expiry_claim] then + local introspection_interval = opts.introspection_interval or 0 local ttl = json[expiry_claim] if expiry_claim == "exp" then --https://tools.ietf.org/html/rfc7662#section-2.2 ttl = ttl - ngx.time() @@ -1693,39 +1704,46 @@ function openidc.introspect(opts) end end log(DEBUG, "cache token ttl: " .. ttl) - openidc_cache_set("introspection", access_token, cjson.encode(json), ttl) - + set_cached_introspection(opts, access_token, cjson.encode(json), ttl) end return json, err end +local function get_cached_jwt_verification(opts, access_token) + local jwt_verification_cache_ignore = opts.jwt_verification_cache_ignore or false + if not jwt_verification_cache_ignore then + return openidc_cache_get("jwt_verification", access_token) + end +end + +local function set_cached_jwt_verification(opts, access_token, encoded_json, ttl) + local jwt_verification_cache_ignore = opts.jwt_verification_cache_ignore or false + if not jwt_verification_cache_ignore then + openidc_cache_set("jwt_verification", access_token, encoded_json, ttl) + end +end + -- main routine for OAuth 2.0 JWT token validation -- optional args are claim specs, see jwt-validators in resty.jwt function openidc.jwt_verify(access_token, opts, ...) local err local json - local v - local introspection_cache_ignore = opts.introspection_cache_ignore or false + local v = get_cached_jwt_verification(opts, access_token) local slack = opts.iat_slack and opts.iat_slack or 120 - -- see if we've previously cached the validation result for this access token - if not introspection_cache_ignore then - v = openidc_cache_get("introspection", access_token) - end if not v then local jwt_obj jwt_obj, err = openidc_load_jwt_and_verify_crypto(opts, access_token, opts.public_key, opts.symmetric_key, opts.token_signing_alg_values_expected, ...) if not err then json = jwt_obj.payload - log(DEBUG, "jwt: ", cjson.encode(json)) + local encoded_json = cjson.encode(json) + log(DEBUG, "jwt: ", encoded_json) - if not introspection_cache_ignore then - local ttl = json.exp and json.exp - ngx.time() or 120 - openidc_cache_set("introspection", access_token, cjson.encode(json), ttl) - end + set_cached_jwt_verification(opts, access_token, encoded_json, + json.exp and json.exp - ngx.time() or 120) end else