This is an automated email from the ASF dual-hosted git repository.

shreemaan-abhishek 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 503e9f5da fix(authz-casdoor): scope session cookie per Casdoor client 
(#13387)
503e9f5da is described below

commit 503e9f5da472295fb5ee357d6777b67709434650
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Thu May 28 12:50:50 2026 +0800

    fix(authz-casdoor): scope session cookie per Casdoor client (#13387)
---
 apisix/plugins/authz-casdoor.lua |  29 ++++++-
 t/plugin/authz-casdoor.t         | 171 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 197 insertions(+), 3 deletions(-)

diff --git a/apisix/plugins/authz-casdoor.lua b/apisix/plugins/authz-casdoor.lua
index cbaa7b707..e5fd6f192 100644
--- a/apisix/plugins/authz-casdoor.lua
+++ b/apisix/plugins/authz-casdoor.lua
@@ -17,11 +17,16 @@
 local core = require("apisix.core")
 local http = require("resty.http")
 local session = require("resty.session")
+local resty_sha256 = require("resty.sha256")
+local str = require("resty.string")
 local ngx = ngx
 local rand = math.random
 local tostring = tostring
 
 
+local cookie_name_cache = {}
+
+
 local plugin_name = "authz-casdoor"
 local schema = {
     type = "object",
@@ -45,6 +50,19 @@ local _M = {
     schema = schema
 }
 
+
+local function session_opts(conf)
+    local name = cookie_name_cache[conf.client_id]
+    if not name then
+        local sha256 = resty_sha256:new()
+        sha256:update(conf.client_id)
+        name = "authz_casdoor_session_" .. str.to_hex(sha256:final())
+        cookie_name_cache[conf.client_id] = name
+    end
+    return { cookie_name = name }
+end
+
+
 local function fetch_access_token(code, conf)
     local client = http.new()
     local url = conf.endpoint_addr .. "/api/login/oauth/access_token"
@@ -93,7 +111,8 @@ end
 
 function _M.access(conf, ctx)
     local current_uri = ctx.var.uri
-    local session_obj, sess_err, session_present = session.open()
+    local opts = session_opts(conf)
+    local session_obj, sess_err, session_present = session.open(opts)
     -- step 1: check whether hits the callback
     local m, err = ngx.re.match(conf.callback_url, ".+//[^/]+(/.*)", "jo")
     if err or not m then
@@ -142,20 +161,24 @@ function _M.access(conf, ctx)
             return 503
         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)
         session_obj_write:save()
         core.response.set_header("Location", original_url)
         return 302
     end
 
     -- step 2: check whether session exists
-    if not (session_present and session_obj:get("access_token")) then
+    if not (session_present
+            and session_obj:get("access_token")
+            and session_obj:get("client_id") == conf.client_id) then
         -- session not exists, redirect to login page
         local state = rand(0x7fffffff)
-        local session_obj_write = session.start()
+        local session_obj_write = session.start(opts)
         session_obj_write:set("original_uri", current_uri)
         session_obj_write:set("state", state)
         session_obj_write:save()
diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t
index aef07facc..9a25d76d0 100644
--- a/t/plugin/authz-casdoor.t
+++ b/t/plugin/authz-casdoor.t
@@ -512,3 +512,174 @@ apisix:
 --- response_body
 3416238e1edf915eac08b8fe345b2b95cdba7e04
 YUfqAO0kPXjZIoAbPSuryCkUDksEmwSq08UDTIUWolN6KQwEUrh72TazePueo4/S
+
+
+
+=== TEST 11: configure two routes with different client_id values
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+
+            local fake_uri = "http://127.0.0.1:10420";
+            local low_callback = "http://127.0.0.1:"; .. ngx.var.server_port ..
+                                 "/low/callback"
+            local high_callback = "http://127.0.0.1:"; .. ngx.var.server_port ..
+                                  "/high/callback"
+
+            local code, body = t('/apisix/admin/routes/11',
+                ngx.HTTP_PUT,
+                [[{
+                    "methods": ["GET"],
+                    "uri": "/low/*",
+                    "plugins": {
+                        "authz-casdoor": {
+                            "callback_url":"]] .. low_callback .. [[",
+                            "endpoint_addr":"]] .. fake_uri .. [[",
+                            "client_id":"low-client",
+                            "client_secret":"low-secret"
+                        },
+                        "proxy-rewrite": {
+                            "uri": "/echo"
+                        }
+                    },
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "test.com:1980": 1
+                        }
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.say("failed to set up low route")
+                return
+            end
+
+            local code, body = t('/apisix/admin/routes/12',
+                ngx.HTTP_PUT,
+                [[{
+                    "methods": ["GET"],
+                    "uri": "/high/*",
+                    "plugins": {
+                        "authz-casdoor": {
+                            "callback_url":"]] .. high_callback .. [[",
+                            "endpoint_addr":"]] .. fake_uri .. [[",
+                            "client_id":"high-client",
+                            "client_secret":"high-secret"
+                        },
+                        "proxy-rewrite": {
+                            "uri": "/echo"
+                        }
+                    },
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "test.com:1980": 1
+                        }
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.say("failed to set up high route")
+                return
+            end
+            ngx.say("done")
+        }
+    }
+--- response_body
+done
+
+
+
+=== TEST 12: session cookie scoped per client_id
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local log = core.log
+            local httpc = require("resty.http").new()
+
+            local base = "http://127.0.0.1:"; .. ngx.var.server_port
+            local low_url = base .. "/low/data"
+            local high_url = base .. "/high/data"
+
+            -- step 1: unauthenticated GET on /low/data -> 302 to Casdoor for 
low-client
+            local res1, err1 = httpc:request_uri(low_url, {method = "GET"})
+            if not res1 then
+                log.error(err1)
+                return
+            end
+            ngx.say("step1_status=", res1.status)
+            local loc1 = res1.headers["Location"] or ""
+            if ngx.re.find(loc1, "client_id=low-client", "jo") then
+                ngx.say("step1_to_low_client=yes")
+            else
+                ngx.say("step1_to_low_client=no loc=", loc1)
+            end
+
+            local pre_cookie = res1.headers["Set-Cookie"]
+            local m, err = ngx.re.match(loc1, "state=([0-9]*)", "jo")
+            if err or not m then
+                log.error(err or "no state")
+                return
+            end
+            local state = m[1]
+
+            -- step 2: complete the callback to establish a session for 
low-client
+            local callback_url = base .. "/low/callback?code=aaa&state=" .. 
state
+            local res2, err2 = httpc:request_uri(callback_url, {
+                method = "GET",
+                headers = {Cookie = pre_cookie}
+            })
+            if not res2 then
+                log.error(err2)
+                return
+            end
+            ngx.say("step2_status=", res2.status)
+            local post_cookie = res2.headers["Set-Cookie"]
+
+            -- step 3: reuse the post-login cookie against /high/data
+            -- (different client_id) -> must redirect for high-client
+            local res3, err3 = httpc:request_uri(high_url, {
+                method = "GET",
+                headers = {Cookie = post_cookie}
+            })
+            if not res3 then
+                log.error(err3)
+                return
+            end
+            ngx.say("step3_status=", res3.status)
+            local loc3 = res3.headers["Location"] or ""
+            if ngx.re.find(loc3, "client_id=high-client", "jo") then
+                ngx.say("step3_to_high_client=yes")
+            else
+                ngx.say("step3_to_high_client=no loc=", loc3)
+            end
+
+            -- Confirm the Set-Cookie names differ between routes, proving the
+            -- cookie-name scoping layer is active independent of the 
in-session
+            -- client_id check.
+            local function cookie_name(set_cookie)
+                if type(set_cookie) == "table" then
+                    set_cookie = set_cookie[1]
+                end
+                return set_cookie and set_cookie:match("^([^=]+)=")
+            end
+            local low_name = cookie_name(pre_cookie)
+            local high_name = cookie_name(res3.headers["Set-Cookie"])
+            if low_name and high_name and low_name ~= high_name then
+                ngx.say("cookie_names_differ=yes")
+            else
+                ngx.say("cookie_names_differ=no low=", tostring(low_name),
+                        " high=", tostring(high_name))
+            end
+        }
+    }
+--- response_body
+step1_status=302
+step1_to_low_client=yes
+step2_status=302
+step3_status=302
+step3_to_high_client=yes
+cookie_names_differ=yes

Reply via email to