Skip to content

Commit ba4649e

Browse files
committed
Removing cache for signed JWT to OP
1 parent 294cc95 commit ba4649e

File tree

2 files changed

+18
-37
lines changed

2 files changed

+18
-37
lines changed

README.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ http {
128128
client_id = "<client_id>",
129129
client_secret = "<client_secret>",
130130
-- o If token_endpoint_auth_method is set to "private_key_jwt" authentication to Token endpoint is using client_id, client_rsa_private_key and client_rsa_private_key_id to compute a signed JWT
131-
-- client_rsa_private_key is the RSA private key to be used to sign the JWT generated by lua-restu-openidc for authentication to the OP
131+
-- client_rsa_private_key is the RSA private key to be used to sign the JWT generated by lua-resty-openidc for authentication to the OP
132132
-- client_rsa_private_key_id (optional) is the key id to be set in the JWT header to identify which public key the OP shall use to verify the JWT signature
133133
--client_id = "<client_id>",
134134
--client_rsa_private_key=[[-----BEGIN RSA PRIVATE KEY-----
@@ -137,10 +137,9 @@ MIIEogIBAAKCAQEAiThmpvXBYdur716D2q7fYKirKxzZIU5QrkBGDvUOwg5izcTv
137137
h2JHukolz9xf6qN61QMLSd83+kwoBr2drp6xg3eGDLIkQCQLrkY=
138138
-----END RSA PRIVATE KEY-----]],
139139
--client_rsa_private_key_id="key id#1",
140-
-- Computation of RSA signature is far more time-consuming than simply using a client_secret for the other authentication modes. In order to counter-balance the performance decrease,
141-
-- the signed JWT generated for authentication to the OP are cached for reuse. Default life duration of the JWT in the cache is 1 hour but can be overwritten. Value of 0 means: not cached.
142-
--client_jwt_assertion_expires_in = 60 * 60, -- 1h, expressed in seconds
143-
-- Note that the signed JWT tokens for authentication to the OP have an expiration that is 60 seconds after the expected cache life time.
140+
-- Life duration expressed in seconds of the signed JWT generated by lua-resty-openidc for authentication to the OP.
141+
-- (used when token_endpoint_auth_method is set to "private_key_jwt" authentication). Default is 60 seconds.
142+
--client_jwt_assertion_expires_in = 60,
144143
-- When using https to any OP endpoints, enforcement of SSL certificate check can be mandated ("yes") or not ("no").
145144
--ssl_verify = "no",
146145

lib/resty/openidc.lua

+14-32
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ local cjson = require("cjson")
5353
local cjson_s = require("cjson.safe")
5454
local http = require("resty.http")
5555
local r_session = require("resty.session")
56+
local r_jwt = require("resty.jwt")
5657
local string = string
5758
local ipairs = ipairs
5859
local pairs = pairs
@@ -387,30 +388,6 @@ local function openidc_configure_proxy(httpc, proxy_opts)
387388
end
388389
end
389390

390-
-- build client assertion for the 'private_key_jwt' authentication mode to the token endpoint
391-
local function get_client_assertion(opts, endpoint, private_key, key_id)
392-
local cache_key = endpoint.."~"..opts.client_id.."~"..((string.len(private_key) > 200) and private_key:sub(98, 161) or private_key).."~"..(key_id and key_id or "")
393-
394-
local assertion = openidc_cache_get ("jwks", cache_key)
395-
396-
if not assertion then
397-
local exptime = opts.client_jwt_assertion_expires_in or 60 * 60 -- expiration of the assertion in the cache
398-
local jwt_validity = 60 -- assertion is valid for 60 seconds after its expiration: assuming the check by the OP will not be done later than 60 sec after the assertion retrieval.
399-
400-
local now = ngx.time()
401-
local assertion_header = {typ = "JWT", alg = "RS256", kid = key_id}
402-
local assertion_payload = {sub = opts.client_id, iss = opts.client_id, aud = endpoint,
403-
exp = now + exptime + jwt_validity, jti = now, iat = now}
404-
405-
local jwt = require("resty.jwt")
406-
assertion = jwt:sign(private_key, { header = assertion_header, payload = assertion_payload })
407-
408-
openidc_cache_set("jwks", cache_key, assertion, exptime)
409-
end
410-
411-
return assertion
412-
end
413-
414391
-- make a call to the token endpoint
415392
function openidc.call_token_endpoint(opts, endpoint, body, auth, endpoint_name, ignore_body_on_success)
416393
local ignore_body_on_success = ignore_body_on_success or false
@@ -430,18 +407,24 @@ function openidc.call_token_endpoint(opts, endpoint, body, auth, endpoint_name,
430407
headers.Authorization = "Basic " .. b64(ngx.escape_uri(opts.client_id) .. ":")
431408
end
432409
log(DEBUG, "client_secret_basic: authorization header '" .. headers.Authorization .. "'")
433-
end
434-
if auth == "client_secret_post" then
410+
411+
elseif auth == "client_secret_post" then
435412
body.client_id = opts.client_id
436413
if opts.client_secret then
437414
body.client_secret = opts.client_secret
438415
end
439416
log(DEBUG, "client_secret_post: client_id and client_secret being sent in POST body")
440-
end
441-
if auth == "private_key_jwt" then
417+
418+
elseif auth == "private_key_jwt" then
442419
body.client_id=opts.client_id
443420
body.client_assertion_type="urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
444-
body.client_assertion=get_client_assertion(opts, endpoint, opts.client_rsa_private_key, opts.client_rsa_private_key_id)
421+
422+
local now = ngx.time()
423+
local assertion_header = {typ = "JWT", alg = "RS256", kid = opts.client_rsa_private_key_id}
424+
local assertion_payload = {sub = opts.client_id, iss = opts.client_id, aud = endpoint, jti = ngx.var.request_id,
425+
exp = now + (opts.client_jwt_assertion_expires_in and opts.client_jwt_assertion_expires_in or 60), iat = now}
426+
427+
body.client_assertion=r_jwt:sign(opts.client_rsa_private_key, { header = assertion_header, payload = assertion_payload })
445428
log(DEBUG, "private_key_jwt: client_id, client_assertion_type and client_assertion being sent in POST body")
446429
end
447430
end
@@ -895,7 +878,6 @@ end
895878
-- parse a JWT and verify its signature (if present)
896879
local function openidc_load_jwt_and_verify_crypto(opts, jwt_string, asymmetric_secret,
897880
symmetric_secret, expected_algs, ...)
898-
local jwt = require("resty.jwt")
899881
local enc_hdr, enc_payload, enc_sign = string.match(jwt_string, '^(.+)%.(.+)%.(.*)$')
900882
if enc_payload and (not enc_sign or enc_sign == "") then
901883
local jwt = openidc_load_jwt_none_alg(enc_hdr, enc_payload)
@@ -909,7 +891,7 @@ symmetric_secret, expected_algs, ...)
909891
end -- otherwise the JWT is invalid and load_jwt produces an error
910892
end
911893

912-
local jwt_obj = jwt:load_jwt(jwt_string, nil)
894+
local jwt_obj = r_jwt:load_jwt(jwt_string, nil)
913895
if not jwt_obj.valid then
914896
local reason = "invalid jwt"
915897
if jwt_obj.reason then
@@ -957,7 +939,7 @@ symmetric_secret, expected_algs, ...)
957939
jwt_validators.set_system_leeway(opts.iat_slack and opts.iat_slack or 120)
958940
end
959941

960-
jwt_obj = jwt:verify_jwt_obj(secret, jwt_obj, ...)
942+
jwt_obj = r_jwt:verify_jwt_obj(secret, jwt_obj, ...)
961943
if jwt_obj then
962944
log(DEBUG, "jwt: ", cjson.encode(jwt_obj), " ,valid: ", jwt_obj.valid, ", verified: ", jwt_obj.verified)
963945
end

0 commit comments

Comments
 (0)