From 05d588abcadf866beccfae9d828b023e3b48d03e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 04:14:51 +0000 Subject: [PATCH 1/7] Initial plan From c79744c7ec5c17859a7ad5aa44ee41de247c2bde Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 04:20:17 +0000 Subject: [PATCH 2/7] Fix multiple policy support across different routes Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- apisix-authz.lua | 59 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/apisix-authz.lua b/apisix-authz.lua index 4bfa46e..4c1c7c4 100644 --- a/apisix-authz.lua +++ b/apisix-authz.lua @@ -16,8 +16,10 @@ local Enforcer = require("casbin") local core = require("apisix.core") local get_headers = ngx.req.get_headers --- e is the Casbin Enforcer -local CasbinEnforcer +-- Table to store multiple Casbin Enforcers keyed by configuration +local CasbinEnforcers = {} +-- Reference to the last accessed enforcer (for API operations) +local CurrentEnforcer local plugin_name = "apisix-authz" @@ -41,18 +43,25 @@ local _M = { } function _M.rewrite(conf) - -- creates an enforcer when request sent for the first time - if not CasbinEnforcer then - CasbinEnforcer = Enforcer:new(conf.model_path, conf.policy_path) + -- Create a unique key for this configuration + local conf_key = conf.model_path .. "|" .. conf.policy_path + + -- creates an enforcer for this configuration if it doesn't exist + if not CasbinEnforcers[conf_key] then + CasbinEnforcers[conf_key] = Enforcer:new(conf.model_path, conf.policy_path) end + local enforcer = CasbinEnforcers[conf_key] + -- Set as current enforcer for potential API operations + CurrentEnforcer = enforcer + local path = ngx.var.request_uri local method = ngx.var.request_method local username = get_headers()[conf.username] if not username then username = "anonymous" end if path and method and username then - if not CasbinEnforcer:enforce(username, path, method) then + if not enforcer:enforce(username, path, method) then return 403, {message = "Access Denied"} end else @@ -62,6 +71,10 @@ end -- subject, object, action local function addPolicy() + if not CurrentEnforcer then + return 400, {message = "No enforcer available. Send a request through a configured route first."} + end + local headers = get_headers() local type = headers["type"] @@ -74,7 +87,7 @@ local function addPolicy() return 400, {message = "Invalid policy request."} end - if CasbinEnforcer:AddPolicy(subject, object, action) then + if CurrentEnforcer:AddPolicy(subject, object, action) then return 200, {message = "Successfully added policy."} else return 400, {message = "Invalid policy request."} @@ -87,7 +100,7 @@ local function addPolicy() return 400, {message = "Invalid policy request."} end - if CasbinEnforcer:AddGroupingPolicy(user, role) then + if CurrentEnforcer:AddGroupingPolicy(user, role) then return 200, {message = "Successfully added grouping policy."} else return 400, {message = "Invalid policy request."} @@ -98,6 +111,10 @@ local function addPolicy() end local function removePolicy() + if not CurrentEnforcer then + return 400, {message = "No enforcer available. Send a request through a configured route first."} + end + local headers = get_headers() local type = headers["type"] @@ -110,7 +127,7 @@ local function removePolicy() return 400, {message = "Invalid policy request."} end - if CasbinEnforcer:RemovePolicy(subject, object, action) then + if CurrentEnforcer:RemovePolicy(subject, object, action) then return 200, {message = "Successfully removed policy."} else return 400, {message = "Invalid policy request."} @@ -123,7 +140,7 @@ local function removePolicy() return 400, {message = "Invalid policy request."} end - if CasbinEnforcer:RemoveGroupingPolicy(user, role) then + if CurrentEnforcer:RemoveGroupingPolicy(user, role) then return 200, {message = "Successfully removed grouping policy."} else return 400, {message = "Invalid policy request."} @@ -135,6 +152,10 @@ end -- subject, object, action local function hasPolicy() + if not CurrentEnforcer then + return 400, {message = "No enforcer available. Send a request through a configured route first."} + end + local headers = get_headers() local type = headers["type"] @@ -147,7 +168,7 @@ local function hasPolicy() return 400, {message = "Invalid policy request."} end - if CasbinEnforcer:HasPolicy(subject, object, action) then + if CurrentEnforcer:HasPolicy(subject, object, action) then return 200, {data = "true"} else return 200, {data = "false"} @@ -160,7 +181,7 @@ local function hasPolicy() return 400, {message = "Invalid policy request."} end - if CasbinEnforcer:HasGroupingPolicy(user, role) then + if CurrentEnforcer:HasGroupingPolicy(user, role) then return 200, {data = "true"} else return 200, {data = "false"} @@ -171,18 +192,22 @@ local function hasPolicy() end local function getPolicy() + if not CurrentEnforcer then + return 400, {message = "No enforcer available. Send a request through a configured route first."} + end + local headers = get_headers() local type = headers["type"] if type == "p" then - local policy = CasbinEnforcer:GetPolicy() + local policy = CurrentEnforcer:GetPolicy() if policy then return 200, {data = policy} else return 400 end elseif type == "g" then - local groupingPolicy = CasbinEnforcer:GetGroupingPolicy() + local groupingPolicy = CurrentEnforcer:GetGroupingPolicy() if groupingPolicy then return 200, {data = groupingPolicy} else @@ -194,8 +219,12 @@ local function getPolicy() end local function savePolicy() + if not CurrentEnforcer then + return 400, {message = "No enforcer available. Send a request through a configured route first."} + end + local _, err = pcall(function () - CasbinEnforcer:savePolicy() + CurrentEnforcer:savePolicy() end) if not err then return 200, {message = "Successfully saved policy."} From f868abdd34da00cfa6f59874530ed6eb4c8f8f59 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 04:21:49 +0000 Subject: [PATCH 3/7] Add documentation for multiple routes with different policies Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index 6fef16e..7f2a447 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,42 @@ curl -X PUT \ As per the current configuration, if the request is authorized, the execution will proceed normally. While if it is not authorized, it will return "Access Denied" message with the 403 exit code and stop any further execution. +### Multiple Routes with Different Policies + +The plugin supports using different policies for different routes. Each unique combination of `model_path` and `policy_path` creates a separate enforcer instance. For example: + +```bash +# Route 1 with policy A +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/api/v1/*", + "plugins": { + "apisix-authz": { + "model_path": "/path/to/model.conf", + "policy_path": "/path/to/policy_v1.csv", + "username": "user" + } + }, + "upstream": {...} +}' + +# Route 2 with policy B +curl http://127.0.0.1:9080/apisix/admin/routes/2 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/api/v2/*", + "plugins": { + "apisix-authz": { + "model_path": "/path/to/model.conf", + "policy_path": "/path/to/policy_v2.csv", + "username": "user" + } + }, + "upstream": {...} +}' +``` + +Each route will use its own policy file and enforce authorization rules independently. + ## Development If you wish to customize this according to your scenario, you can do so by customizing the apisix-authz.lua file from your plugins directory. From 188606b7dc7a0cc14e8c5cc5f35c4b4752775bf8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 05:44:03 +0000 Subject: [PATCH 4/7] Fix API function syntax - remove extra closing brace Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- apisix-authz.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apisix-authz.lua b/apisix-authz.lua index 4c1c7c4..e7690d2 100644 --- a/apisix-authz.lua +++ b/apisix-authz.lua @@ -260,8 +260,8 @@ function _M.api() methods = {"POST"}, uri = "/apisix/plugin/casbin/save", handler = savePolicy, - }, } + } end function _M.check_schema(conf) From cdfed73b4939e066404363f7af4728e621fcd1cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 07:16:56 +0000 Subject: [PATCH 5/7] Update CI workflow to use APISIX 3.2.0 Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- .github/workflows/test.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2fdd768..350f6c5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,18 +32,18 @@ jobs: nohup etcd & - name: Install and configure APISIX run: | - mkdir apisix-2.7 - wget https://downloads.apache.org/apisix/2.7/apache-apisix-2.7-src.tgz - tar zxvf apache-apisix-2.7-src.tgz -C apisix-2.7 - cd apisix-2.7 + mkdir apisix-3.2 + wget https://downloads.apache.org/apisix/3.2.0/apache-apisix-3.2.0-src.tgz + tar zxvf apache-apisix-3.2.0-src.tgz -C apisix-3.2 --strip-components=1 + cd apisix-3.2 make deps make init cd .. - name: Configure apisix-authz run: | - cp apisix-authz.lua apisix-2.7/apisix/plugins/apisix-authz.lua + cp apisix-authz.lua apisix-3.2/apisix/plugins/apisix-authz.lua # append plugins to config - cat <> apisix-2.7/conf/config.yaml + cat <> apisix-3.2/conf/config.yaml plugins: # plugin list (sorted by priority) - client-control # priority: 22000 - ext-plugin-pre-req # priority: 12000 @@ -100,7 +100,7 @@ jobs: sudo luarocks install https://raw.githubusercontent.com/casbin/lua-casbin/master/casbin-1.16.1-1.rockspec - name: Start the server run: | - cd apisix-2.7 + cd apisix-3.2 make run curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { From ad802764b8da858eaa282f91f988aa931db74fe9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 07:44:17 +0000 Subject: [PATCH 6/7] Update CI workflow to use APISIX 2.15.3 Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- .github/workflows/test.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 350f6c5..c29f675 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,18 +32,18 @@ jobs: nohup etcd & - name: Install and configure APISIX run: | - mkdir apisix-3.2 - wget https://downloads.apache.org/apisix/3.2.0/apache-apisix-3.2.0-src.tgz - tar zxvf apache-apisix-3.2.0-src.tgz -C apisix-3.2 --strip-components=1 - cd apisix-3.2 + mkdir apisix-2.15 + wget https://downloads.apache.org/apisix/2.15.3/apache-apisix-2.15.3-src.tgz + tar zxvf apache-apisix-2.15.3-src.tgz -C apisix-2.15 --strip-components=1 + cd apisix-2.15 make deps make init cd .. - name: Configure apisix-authz run: | - cp apisix-authz.lua apisix-3.2/apisix/plugins/apisix-authz.lua + cp apisix-authz.lua apisix-2.15/apisix/plugins/apisix-authz.lua # append plugins to config - cat <> apisix-3.2/conf/config.yaml + cat <> apisix-2.15/conf/config.yaml plugins: # plugin list (sorted by priority) - client-control # priority: 22000 - ext-plugin-pre-req # priority: 12000 @@ -100,7 +100,7 @@ jobs: sudo luarocks install https://raw.githubusercontent.com/casbin/lua-casbin/master/casbin-1.16.1-1.rockspec - name: Start the server run: | - cd apisix-3.2 + cd apisix-2.15 make run curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { From 55466ad0def687534166e28d4add5d1d5709a121 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Oct 2025 12:55:37 +0000 Subject: [PATCH 7/7] Fix CI by using ubuntu-22.04 instead of ubuntu-latest Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c29f675..a0189be 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ on: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: fail-fast: false steps: