This is an automated email from the ASF dual-hosted git repository.
nic-6443 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 993ca77d7 fix(authz-casdoor): expire the session when the Casdoor
token expires (#13500)
993ca77d7 is described below
commit 993ca77d7df9f968b8565e4c5a152c00cbc45e2c
Author: Nic <[email protected]>
AuthorDate: Thu Jun 11 09:58:07 2026 +0800
fix(authz-casdoor): expire the session when the Casdoor token expires
(#13500)
---
apisix/plugins/authz-casdoor.lua | 17 ++++--
t/plugin/authz-casdoor.t | 108 +++++++++++++++++++++++++++++++++++++++
2 files changed, 120 insertions(+), 5 deletions(-)
diff --git a/apisix/plugins/authz-casdoor.lua b/apisix/plugins/authz-casdoor.lua
index e5fd6f192..a9c100dac 100644
--- a/apisix/plugins/authz-casdoor.lua
+++ b/apisix/plugins/authz-casdoor.lua
@@ -22,6 +22,7 @@ local str = require("resty.string")
local ngx = ngx
local rand = math.random
local tostring = tostring
+local tonumber = tonumber
local cookie_name_cache = {}
@@ -94,11 +95,12 @@ local function fetch_access_token(code, conf)
"failed when accessing token: no access_token contained"
end
-- In the reply of casdoor, setting expires_in to 0 indicates that the
access_token is invalid.
- if not data.expires_in or data.expires_in == 0 then
+ local expires_in = tonumber(data.expires_in)
+ if not expires_in or expires_in <= 0 then
return nil, nil, "failed when accessing token: invalid access_token"
end
- return data.access_token, data.expires_in, nil
+ return data.access_token, expires_in, nil
end
@@ -162,20 +164,25 @@ function _M.access(conf, ctx)
end
local session_obj_write = session.new {
cookie_name = opts.cookie_name,
- cookie = {lifetime = lifetime}
}
session_obj_write:open()
session_obj_write:set("access_token", access_token)
session_obj_write:set("client_id", conf.client_id)
+ -- lua-resty-session 4.x no longer honors the old cookie.lifetime
option,
+ -- so bind the session to the access token's expiry explicitly and
enforce
+ -- it when the session is reused (see step 2 below).
+ session_obj_write:set("access_token_expires_at", ngx.time() + lifetime)
session_obj_write:save()
core.response.set_header("Location", original_url)
return 302
end
- -- step 2: check whether session exists
+ -- step 2: check whether a valid, unexpired session exists
+ local token_expires_at = session_present and
session_obj:get("access_token_expires_at")
if not (session_present
and session_obj:get("access_token")
- and session_obj:get("client_id") == conf.client_id) then
+ and session_obj:get("client_id") == conf.client_id
+ and (not token_expires_at or token_expires_at > ngx.time())) then
-- session not exists, redirect to login page
local state = rand(0x7fffffff)
local session_obj_write = session.start(opts)
diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t
index 9a25d76d0..f73edd748 100644
--- a/t/plugin/authz-casdoor.t
+++ b/t/plugin/authz-casdoor.t
@@ -45,6 +45,12 @@ add_block_preprocessor(sub {
return
end
+ if arg == "shortexp" then
+ ngx.status = 200
+ ngx.say(json_encode({ access_token = "cccccccccccccccc",
expires_in = 2 }))
+ return
+ end
+
ngx.status = 200
ngx.say(json_encode({ access_token = "aaaaaaaaaaaaaaaa",
expires_in = 1000000 }))
}
@@ -683,3 +689,105 @@ step2_status=302
step3_status=302
step3_to_high_client=yes
cookie_names_differ=yes
+
+
+
+=== TEST 13: route whose Casdoor token has a short expires_in
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local fake_uri = "http://127.0.0.1:10420"
+ local callback_url = "http://127.0.0.1:" .. ngx.var.server_port ..
+ "/shortexp/callback"
+ local code, body = t('/apisix/admin/routes/13',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "uri": "/shortexp/*",
+ "plugins": {
+ "authz-casdoor": {
+ "callback_url":"]] .. callback_url .. [[",
+ "endpoint_addr":"]] .. fake_uri .. [[",
+ "client_id":"7ceb9b7fda4a9061ec1c",
+
"client_secret":"3416238e1edf915eac08b8fe345b2b95cdba7e04"
+ },
+ "proxy-rewrite": {
+ "uri": "/echo"
+ }
+ },
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "test.com:1980": 1
+ }
+ }
+ }]]
+ )
+ if code >= 300 then
+ ngx.say("failed to set up routing rule")
+ end
+ ngx.say("done")
+ }
+ }
+--- response_body
+done
+
+
+
+=== TEST 14: session expires when the Casdoor token's expires_in elapses
+--- config
+ location /t {
+ content_by_lua_block {
+ local log = require("apisix.core").log
+ local httpc = require("resty.http").new()
+ local base = "http://127.0.0.1:" .. ngx.var.server_port
+
+ -- step 1: unauthenticated request -> redirect to Casdoor, get
state cookie
+ local res1 = httpc:request_uri(base .. "/shortexp/d", {method =
"GET"})
+ if not res1 or res1.status ~= 302 then
+ ngx.say("step1 expected 302, got: ", res1 and res1.status or
"nil")
+ return
+ end
+ local pre_cookie = res1.headers["Set-Cookie"]
+ local m = ngx.re.match(res1.headers["Location"] or "",
"state=([0-9]*)", "jo")
+ if not m then
+ ngx.say("no state in redirect")
+ return
+ end
+
+ -- step 2: complete the callback; Casdoor returns expires_in=2,
+ -- establishing the access-token session
+ local res2 = httpc:request_uri(
+ base .. "/shortexp/callback?code=shortexp&state=" .. m[1],
+ {method = "GET", headers = {Cookie = pre_cookie}})
+ if not res2 or res2.status ~= 302 then
+ ngx.say("step2 expected 302, got: ", res2 and res2.status or
"nil")
+ return
+ end
+ local post_cookie = res2.headers["Set-Cookie"]
+
+ -- step 3: the fresh session is valid -> request is proxied (200)
+ local res3 = httpc:request_uri(base .. "/shortexp/d",
+ {method = "GET", headers = {Cookie = post_cookie}})
+ if not res3 or res3.status ~= 200 then
+ ngx.say("step3 expected 200, got: ", res3 and res3.status or
"nil")
+ return
+ end
+
+ -- step 4: after expires_in (2s) the session must be rejected and
the
+ -- request redirected back to Casdoor for re-authentication
+ ngx.sleep(3)
+ local res4 = httpc:request_uri(base .. "/shortexp/d",
+ {method = "GET", headers = {Cookie = post_cookie}})
+ if not res4 or res4.status ~= 302 then
+ ngx.say("step4 expected 302 after expiry, got: ", res4 and
res4.status or "nil")
+ return
+ end
+
+ ngx.say("passed")
+ }
+ }
+--- timeout: 15
+--- response_body
+passed