Skip to content

Commit

Permalink
split caches of token introspection and JWT verification
Browse files Browse the repository at this point in the history
see #399

Signed-off-by: Stefan Bodewig <stefan.bodewig@innoq.com>
  • Loading branch information
bodewig committed Sep 23, 2021
1 parent 6ba3a5f commit a73ebd9
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 27 deletions.
7 changes: 4 additions & 3 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
58 changes: 38 additions & 20 deletions lib/resty/openidc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down

0 comments on commit a73ebd9

Please sign in to comment.