From 3752e64a77c5e46023eb5066eb21257540ff6204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Sat, 26 Feb 2022 21:02:06 +0800 Subject: [PATCH 01/13] feat: add auth plugin for casdoor --- apisix/plugins/auth-casdoor.lua | 121 +++++++++++ conf/config-default.yaml | 1 + docs/en/latest/config.json | 1 + docs/en/latest/plugins/auth-casdoor.md | 94 +++++++++ t/admin/plugins.t | 1 + t/plugin/auth-casdoor.t | 280 +++++++++++++++++++++++++ 6 files changed, 498 insertions(+) create mode 100644 apisix/plugins/auth-casdoor.lua create mode 100644 docs/en/latest/plugins/auth-casdoor.md create mode 100644 t/plugin/auth-casdoor.t diff --git a/apisix/plugins/auth-casdoor.lua b/apisix/plugins/auth-casdoor.lua new file mode 100644 index 000000000000..837bfe80c64e --- /dev/null +++ b/apisix/plugins/auth-casdoor.lua @@ -0,0 +1,121 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one or more +-- contributor license agreements. See the NOTICE file distributed with +-- this work for additional information regarding copyright ownership. +-- The ASF licenses this file to You under the Apache License, Version 2.0 +-- (the "License"); you may not use this file except in compliance with +-- the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +local core = require("apisix.core") +local http = require("resty.http") +local session = require("resty.session") +local ngx = ngx + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + --Note: endpoint_addr and callback_url should not end with '/' + endpoint_addr = {type = "string", pattern = "^[^%?]+[^/]$"}, + client_id = {type = "string"}, + client_secret = {type = "string"}, + callback_url = {type = "string", pattern = "^[^%?]+[^/]$"}, + }, + required = { + "callback_url", "endpoint_addr", "client_id", "client_secret" + } +} + +local _M = { + version = 0.1, + priority = 2559, + name = plugin_name, + schema = schema +} + +local function fetch_access_token(ctx, conf) + local args = core.request.get_uri_args(ctx) + if not args or not args.code or not args.state then + return nil, "failed when accessing token. Invalid code or state" + end + local client = http.new() + local url = conf.endpoint_addr .. "/api/login/oauth/access_token" + + local res, err = client:request_uri(url, { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.client_id, + client_secret = conf.client_secret + } + }) + if not res then return nil, err end + local data, err = core.cjson.decode(res.body) + + if err or not data then + err = "failed to parse casdoor response data: " .. err + return nil, err + end + + if not data.access_token then + return nil, "failed when accessing token: no access_token contained" + end + + return data.access_token, nil +end + +function _M.check_schema(conf) return core.schema.check(schema, conf) end + +function _M.access(conf, ctx) + -- log.info("hit auth-casdoor access") + local current_uri = ctx.var.uri + local session_obj_read, session_present = session.open() + + -- step 1: check whether hits the callback + local real_callback_url=ngx.re.match(conf.callback_url, ".-//[^/]+(/.*)") + if current_uri == real_callback_url then + local access_token, err = fetch_access_token(ctx, conf) + if access_token then + if not session_present then + return 503, "no session found" + end + local original_url = session_obj_read.data.original_uri + if not original_url then + return 503, "no original_url found in session" + end + local session_obj_write = session.start() + session_obj_write.data.access_token = access_token + session_obj_write:save() + core.response.set_header("Location", original_url) + return 302 + else + return 503, err + end + end + + -- step 2: check whether session exists + if not (session_present and session_obj_read.data.access_token) then + -- session not exists, redirect to login page + local session_obj_write = session.start() + session_obj_write.data.original_uri = current_uri + session_obj_write:save() + local redirect_url = conf.endpoint_addr .. + "/login/oauth/authorize?response_type=code&scope=read" .. + "&state=casdoor&client_id=" .. conf.client_id .. + "&redirect_uri=" .. conf.callback_url + core.response.set_header("Location", redirect_url) + return 302 + end + +end + +return _M diff --git a/conf/config-default.yaml b/conf/config-default.yaml index f96b8395c735..89788d59741f 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -344,6 +344,7 @@ plugins: # plugin list (sorted by priority) - request-validation # priority: 2800 - openid-connect # priority: 2599 - authz-casbin # priority: 2560 + - auth-casdoor # priority: 2559 - wolf-rbac # priority: 2555 - ldap-auth # priority: 2540 - hmac-auth # priority: 2530 diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json index f4d1e5ad3309..f470bb0aedfd 100644 --- a/docs/en/latest/config.json +++ b/docs/en/latest/config.json @@ -71,6 +71,7 @@ "plugins/jwt-auth", "plugins/basic-auth", "plugins/authz-keycloak", + "plugins/auth-casdoor", "plugins/wolf-rbac", "plugins/openid-connect", "plugins/hmac-auth", diff --git a/docs/en/latest/plugins/auth-casdoor.md b/docs/en/latest/plugins/auth-casdoor.md new file mode 100644 index 000000000000..39a75090da6b --- /dev/null +++ b/docs/en/latest/plugins/auth-casdoor.md @@ -0,0 +1,94 @@ +--- +title: auth-casdoor +--- + + + +## Summary + +- [**Name**](#name) +- [**Attributes**](#attributes) +- [**Metadata**](#metadata) +- [**How To Enable**](#how-to-enable) +- [**Test Plugin**](#test-plugin) +- [**Disable Plugin**](#disable-plugin) +- [**Examples**](#examples) + +## Name + +`auth-casdoor` is an authorization plugin based on [Casdoor](https://casdoor.org/). Casdoor is a centralized authentication / Single-Sign-On (SSO) platform supporting OAuth 2.0, OIDC and SAML, integrated with Casbin RBAC and ABAC permission management. + +## Attributes + +| Name | Type | Requirement | Default | Valid | Description | +| ----------- | ------ | ----------- | ------- | ----- | ------------------------------------------------------------ | +| endpoint_addr | string | required | | | The url of casdoor. | +| client_id | string | required | | | The client id in casdoor. | +| client_secret | string | required | | | The client secret in casdoor. | +| callback_url | string | required | | | The callback url which is used to receive state and code. | + +*Note: endpoint_addr and callback_url should not end with '/'* + +## How To Enable + +You can enable the plugin on any route by giving out all four attributes mentioned above. + +### Example + +```shell +curl "http://127.0.0.1:9080/apisix/admin/routes/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/anything/*", + "plugins": { + "auth-casdoor": { + "endpoint_addr":"http://localhost:8000", + "callback_url":"http://localhost:9080/anything/callback", + "client_id":"7ceb9b7fda4a9061ec1c", + "client_secret":"3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } +}' + +``` + +In this example, using apisix's admin API we created a route "/anything/*" pointed to "httpbin.org:80", and with "auth-casdoor" enabled. This route is now under authentication protection of Casdoor. + +#### Explanations about parameters of this plugin + +In the configuration of "auth-casdoor" plugin we can see four parameters. + +The first one is "callback_url". This is exactly the callback url in OAuth2. It should be emphasized that this callback url **must belong to the "uri" you specified for the route**, for example, in this example, http://localhost:9080/anything/callback obviously belong to "/anything/*". Only by this way can the visit toward callback_url can be intercepted and utilized by the plugin(so that the plugin can get the code and state in Oauth2). The logic of callback_url is implemented completely by the plugin so that there is no need to modify the server to implement this callback. + +The second parameter "endpoint_addr" is obviously the url of Casdoor. The third and fourth parameters are "client_id" and "client_secret", which you can acquire from Casdoor when you register an app. + +#### How it works? + +Suppose a new user who has never visited this route before is going to visit it (http://localhost:9080/anything/d?param1=foo¶m2=bar), considering that "auth-casdoor" is enabled, this visit would be processed by "auth-casdoor" plugin first. After checking the session and confirming that this user hasn't been authenticated, the visit will be intercepted. With the original url user wants to visit kept, he will be redirected to the login page of Casdoor. + +After successfully logging in with username and password(or whatever method he uses), Casdoor will redirect this user to the "callback_url" with GET parameter "code" and "state" specified. Because the "callback_url" is known by the plugin, when the visit toward the "callback_url" is intercepted this time, the logic of "Authorization code Grant Flow" in Oauth2 will be triggered, which means this plugin will request the access token to confirm whether this user is really logged in. After this confirmation, this plugin will redirect this user to the original url user wants to visit, which was kept by us previously. The logged-in status will also be kept in the session. + +Next time this user want to visit url behind this route (for example, http://localhost:9080/anything/d), after discovering that this user has been authenticated previously, this plugin won't redirect this user anymore so that this user can visit whatever he wants under this route without being interfered. diff --git a/t/admin/plugins.t b/t/admin/plugins.t index 2cd06c809029..898625cc58ad 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -79,6 +79,7 @@ uri-blocker request-validation openid-connect authz-casbin +auth-casdoor wolf-rbac ldap-auth hmac-auth diff --git a/t/plugin/auth-casdoor.t b/t/plugin/auth-casdoor.t new file mode 100644 index 000000000000..4061b4de1e7d --- /dev/null +++ b/t/plugin/auth-casdoor.t @@ -0,0 +1,280 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +use t::APISIX 'no_plan'; + +repeat_each(1); +no_long_string(); +no_root_location(); +add_block_preprocessor(sub { + my ($block) = @_; + + if ((!defined $block->error_log) && (!defined $block->no_error_log)) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + my $http_config = $block->http_config // <<_EOC_; + server { + listen 10420; + location /api/login/oauth/access_token { + content_by_lua_block { + local json_encode = require("toolkit.json").encode + ngx.status = 200 + ngx.say(json_encode({ access_token = "aaaaaaaaaaaaaaaa" })) + } + } + } +_EOC_ + + $block->set_value("http_config", $http_config); +}); +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.auth-casdoor") + local fake_uri = "http://127.0.0.1:" .. ngx.var.server_port + local callback_url = "http://127.0.0.1:" .. ngx.var.server_port .. + "/anything/callback" + local conf = { + callback_url = callback_url, + endpoint_addr = fake_uri, + client_id = "7ceb9b7fda4a9061ec1c", + client_secret = "3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + local ok, err = plugin.check_schema(conf) + if not ok then ngx.say(err) end + + local conf2 = { + callback_url = callback_url .. "/?code=aaa", + endpoint_addr = fake_uri, + client_id = "7ceb9b7fda4a9061ec1c", + client_secret = "3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + local ok2, err2 = plugin.check_schema(conf2) + if ok2 then ngx.say(err) end + + local conf3 = { + callback_url = callback_url, + endpoint_addr = fake_uri .. "/", + client_id = "7ceb9b7fda4a9061ec1c", + client_secret = "3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + local ok3, err3 = plugin.check_schema(conf3) + if ok3 then ngx.say(err) end + + ngx.say("done") + + } + } +--- response_body +done + + + +=== TEST 2: enable plugin test redirect +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.auth-casdoor") + local core = require("apisix.core") + local log = core.log + 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 .. + "/anything/callback" + local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, [[{ + "methods": ["GET"], + "uri": "/anything/*", + "plugins": { + "auth-casdoor": { + "callback_url":"]] .. callback_url .. [[", + "endpoint_addr":"]] .. fake_uri .. [[", + "client_id":"7ceb9b7fda4a9061ec1c", + "client_secret":"3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }]]) + if not code == 200 then ngx.say("failed to set up routing rule") end + ngx.say("done") + + } + } +--- response_body +done + + + +=== TEST 3: test redirect +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.auth-casdoor") + local core = require("apisix.core") + local log = core.log + local t = require("lib.test_admin").test + + local code, body = t('/anything/d?param1=foo¶m2=bar', ngx.HTTP_GET, [[]]) + if not code == 302 then ngx.say("should have redirected") end + + ngx.say("done") + + } + } +--- response_body +done + + + +=== TEST 4: enable fake casdoor +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + + "uri": "/api/login/oauth/access_token", + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + } + }]] + ) + + if not code == 200 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 5: test fake casdoor +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.auth-casdoor") + local core = require("apisix.core") + local log = core.log + local t = require("lib.test_admin").test + local httpc = require("resty.http").new() + local cjson = require("cjson") + local fake_uri = "http://127.0.0.1:10420/api/login/oauth/access_token" + + local res, err = httpc:request_uri(fake_uri, {method = "GET"}) + if not res then ngx.say(err) end + + local data = cjson.decode(res.body) + if not data then ngx.say("invalid res.body") end + + if not data.access_token == "aaaaaaaaaaaaaaaa" then ngx.say("invalid token") end + ngx.say("done") + + } + } +--- response_body +done + + + +=== TEST 6: test code handling +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.auth-casdoor") + local core = require("apisix.core") + local log = core.log + local t = require("lib.test_admin").test + local cjson = require("cjson") + local fake_uri = "http://127.0.0.1:" .. ngx.var.server_port .. + "/anything/d?param1=foo¶m2=bar" + local callback_url = "http://127.0.0.1:" .. ngx.var.server_port .. + "/anything/callback?code=aaa&state=bbb" + + local httpc = require("resty.http").new() + local res1, err1 = httpc:request_uri(fake_uri, {method = "GET"}) + if not res1 then ngx.say(err1) end + + local cookie = res1.headers["Set-Cookie"] + + local res2, err2 = httpc:request_uri(callback_url, { + method = "GET", + headers = {Cookie = cookie} + }) + if not res2 then ngx.say(err) end + if not res2.code == 302 then log.error(res2.code) end + + local cookie2 = res1.headers["Set-Cookie"] + local res3, err3 = httpc:request_uri(fake_uri, { + method = "GET", + headers = {Cookie = cookie2} + + }) + if not res3 then ngx.say(err) end + if not res3.status == 200 then log.error(res3.status) end + ngx.say("done") + + } + } +--- response_body +done + + + +=== TEST 7: incorrect test code handling +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.auth-casdoor") + local core = require("apisix.core") + local log = core.log + local t = require("lib.test_admin").test + local cjson = require("cjson") + + local callback_url = "http://127.0.0.1:" .. ngx.var.server_port .. + "/anything/callback?code=aaa&state=bbb" + + local httpc = require("resty.http").new() + local res1, err1 = httpc:request_uri(callback_url, {method = "GET"}) + if not res1.status == 503 then ngx.say(res1.status) end + ngx.say("done") + } + } +--- response_body +done From 6097607865138b9f2ef45cf45da071f2be98b873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Tue, 15 Mar 2022 20:04:31 +0800 Subject: [PATCH 02/13] fix: revisions according to review comments --- .../{auth-casdoor.lua => authz-casdoor.lua} | 51 +++++++++--- conf/config-default.yaml | 2 +- docs/en/latest/config.json | 2 +- .../{auth-casdoor.md => authz-casdoor.md} | 14 ++-- t/admin/plugins.t | 2 +- t/plugin/{auth-casdoor.t => authz-casdoor.t} | 78 ++++++++++++++++--- 6 files changed, 117 insertions(+), 32 deletions(-) rename apisix/plugins/{auth-casdoor.lua => authz-casdoor.lua} (72%) rename docs/en/latest/plugins/{auth-casdoor.md => authz-casdoor.md} (82%) rename t/plugin/{auth-casdoor.t => authz-casdoor.t} (77%) diff --git a/apisix/plugins/auth-casdoor.lua b/apisix/plugins/authz-casdoor.lua similarity index 72% rename from apisix/plugins/auth-casdoor.lua rename to apisix/plugins/authz-casdoor.lua index 837bfe80c64e..28b599f451fc 100644 --- a/apisix/plugins/auth-casdoor.lua +++ b/apisix/plugins/authz-casdoor.lua @@ -18,8 +18,9 @@ local core = require("apisix.core") local http = require("resty.http") local session = require("resty.session") local ngx = ngx +local rand = math.random -local plugin_name = "auth-casdoor" +local plugin_name = "authz-casdoor" local schema = { type = "object", properties = { @@ -41,11 +42,14 @@ local _M = { schema = schema } -local function fetch_access_token(ctx, conf) +local function fetch_access_token(ctx, conf,state_in_session) local args = core.request.get_uri_args(ctx) if not args or not args.code or not args.state then return nil, "failed when accessing token. Invalid code or state" end + if not args.state == state_in_session then + return nil,"invalid state" + end local client = http.new() local url = conf.endpoint_addr .. "/api/login/oauth/access_token" @@ -58,8 +62,9 @@ local function fetch_access_token(ctx, conf) client_secret = conf.client_secret } }) + if not res then return nil, err end - local data, err = core.cjson.decode(res.body) + local data, err = core.json.decode(res.body) if err or not data then err = "failed to parse casdoor response data: " .. err @@ -69,6 +74,9 @@ local function fetch_access_token(ctx, conf) if not data.access_token then return nil, "failed when accessing token: no access_token contained" end + if not data.expires_in or data.expires_in == 0 then + return nil, "failed when accessing token: invalid access_token" + end return data.access_token, nil end @@ -76,21 +84,38 @@ end function _M.check_schema(conf) return core.schema.check(schema, conf) end function _M.access(conf, ctx) - -- log.info("hit auth-casdoor access") local current_uri = ctx.var.uri local session_obj_read, session_present = session.open() - -- step 1: check whether hits the callback - local real_callback_url=ngx.re.match(conf.callback_url, ".-//[^/]+(/.*)") + local m, err = ngx.re.match(conf.callback_url, ".+//[^/]+(/.*)") + if err or not m then + core.log.error(err) + return 503, err + end + local real_callback_url=m[1] if current_uri == real_callback_url then - local access_token, err = fetch_access_token(ctx, conf) + if not session_present then + err = "no session found" + core.log.error(err) + return 503, err + end + local state_in_session = session_obj_read.data.state + if not state_in_session then + err = "no state found in session" + core.log.error(err) + return 503, err + end + local access_token, err = fetch_access_token(ctx, conf,state_in_session) + if err then + core.log.error(err) + return 503, err + end if access_token then - if not session_present then - return 503, "no session found" - end local original_url = session_obj_read.data.original_uri if not original_url then - return 503, "no original_url found in session" + err = "no original_url found in session" + core.log.error(err) + return 503, err end local session_obj_write = session.start() session_obj_write.data.access_token = access_token @@ -105,12 +130,14 @@ function _M.access(conf, ctx) -- step 2: check whether session exists if not (session_present and session_obj_read.data.access_token) then -- session not exists, redirect to login page + local state=rand(0x7fffffff) local session_obj_write = session.start() session_obj_write.data.original_uri = current_uri + session_obj_write.data.state=state session_obj_write:save() local redirect_url = conf.endpoint_addr .. "/login/oauth/authorize?response_type=code&scope=read" .. - "&state=casdoor&client_id=" .. conf.client_id .. + "&state="..state.."&client_id=" .. conf.client_id .. "&redirect_uri=" .. conf.callback_url core.response.set_header("Location", redirect_url) return 302 diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 89788d59741f..8677549a0126 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -344,7 +344,7 @@ plugins: # plugin list (sorted by priority) - request-validation # priority: 2800 - openid-connect # priority: 2599 - authz-casbin # priority: 2560 - - auth-casdoor # priority: 2559 + - authz-casdoor # priority: 2559 - wolf-rbac # priority: 2555 - ldap-auth # priority: 2540 - hmac-auth # priority: 2530 diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json index f470bb0aedfd..e29a3d25019e 100644 --- a/docs/en/latest/config.json +++ b/docs/en/latest/config.json @@ -71,7 +71,7 @@ "plugins/jwt-auth", "plugins/basic-auth", "plugins/authz-keycloak", - "plugins/auth-casdoor", + "plugins/authz-casdoor", "plugins/wolf-rbac", "plugins/openid-connect", "plugins/hmac-auth", diff --git a/docs/en/latest/plugins/auth-casdoor.md b/docs/en/latest/plugins/authz-casdoor.md similarity index 82% rename from docs/en/latest/plugins/auth-casdoor.md rename to docs/en/latest/plugins/authz-casdoor.md index 39a75090da6b..9a9dbd79519c 100644 --- a/docs/en/latest/plugins/auth-casdoor.md +++ b/docs/en/latest/plugins/authz-casdoor.md @@ -1,5 +1,5 @@ --- -title: auth-casdoor +title: authz-casdoor --- -## Summary - -- [**Description**](#description) -- [**Attributes**](#attributes) -- [**How To Enable**](#how-to-enable) -- [**Example**](#example) - ## Description `authz-casdoor` is an authorization plugin based on [Casdoor](https://casdoor.org/). Casdoor is a centralized authentication / Single-Sign-On (SSO) platform supporting OAuth 2.0, OIDC and SAML, integrated with Casbin RBAC and ABAC permission management. diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index db6b9ca86feb..3b6963baa1c8 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -162,8 +162,6 @@ done location /t { content_by_lua_block { local plugin = require("apisix.plugins.authz-casdoor") - local core = require("apisix.core") - local log = core.log local t = require("lib.test_admin").test local code, body = t('/anything/d?param1=foo¶m2=bar', ngx.HTTP_GET, [[]]) @@ -215,8 +213,6 @@ passed location /t { content_by_lua_block { local plugin = require("apisix.plugins.authz-casdoor") - local core = require("apisix.core") - local log = core.log local t = require("lib.test_admin").test local httpc = require("resty.http").new() local cjson = require("cjson") @@ -308,8 +304,6 @@ done location /t { content_by_lua_block { local plugin = require("apisix.plugins.authz-casdoor") - local core = require("apisix.core") - local log = core.log local t = require("lib.test_admin").test local cjson = require("cjson") From e2a242d027758b9571a5fa1503a2e292849cb74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Thu, 24 Mar 2022 19:24:11 +0800 Subject: [PATCH 06/13] fix: fix some problems according to the comments --- t/plugin/authz-casdoor.t | 51 +++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index 3b6963baa1c8..4bd95e738e17 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -43,7 +43,7 @@ add_block_preprocessor(sub { local core = require("apisix.core") local log = core.log - if arg=="wrong" then + if arg == "wrong" then ngx.status = 200 ngx.say(json_encode({ access_token = "bbbbbbbbbb", expires_in = 0 })) return @@ -87,9 +87,9 @@ __DATA__ client_id = "7ceb9b7fda4a9061ec1c", client_secret = "3416238e1edf915eac08b8fe345b2b95cdba7e04" } - local ok2, err2 = plugin.check_schema(conf2) - if ok2 then - ngx.say(err) + ok, err = plugin.check_schema(conf2) + if ok then + ngx.say("err") end local conf3 = { @@ -98,9 +98,9 @@ __DATA__ client_id = "7ceb9b7fda4a9061ec1c", client_secret = "3416238e1edf915eac08b8fe345b2b95cdba7e04" } - local ok3, err3 = plugin.check_schema(conf3) - if ok3 then - ngx.say(err) + ok, err = plugin.check_schema(conf3) + if ok then + ngx.say("err") end ngx.say("done") @@ -117,8 +117,6 @@ done location /t { content_by_lua_block { local plugin = require("apisix.plugins.authz-casdoor") - local core = require("apisix.core") - local log = core.log local t = require("lib.test_admin").test local fake_uri = "http://127.0.0.1:10420" @@ -165,7 +163,7 @@ done local t = require("lib.test_admin").test local code, body = t('/anything/d?param1=foo¶m2=bar', ngx.HTTP_GET, [[]]) - if not code == 302 then + if code ~= 302 then ngx.say("should have redirected") end @@ -186,7 +184,6 @@ done local code, body = t('/apisix/admin/routes/2', ngx.HTTP_PUT, [[{ - "uri": "/api/login/oauth/access_token", "upstream": { "nodes": { @@ -197,7 +194,7 @@ done }]] ) - if not code == 200 then + if code ~= 200 then ngx.status = code end ngx.say(body) @@ -272,10 +269,10 @@ done headers = {Cookie = cookie} }) if not res2 then - ngx.say(err) + ngx.say(err2) end - if not res2.code == 302 then - log.error(res2.code) + if res2.status ~= 302 then + log.error(res2.status) end local cookie2 = res1.headers["Set-Cookie"] @@ -285,7 +282,7 @@ done }) if not res3 then - ngx.say(err) + ngx.say(err3) end if not res3.status == 200 then log.error(res3.status) @@ -312,7 +309,7 @@ done local httpc = require("resty.http").new() local res1, err1 = httpc:request_uri(callback_url, {method = "GET"}) - if not res1.status == 503 then + if res1.status ~= 503 then ngx.say(res1.status) end ngx.say("done") @@ -347,7 +344,7 @@ no session found local cookie = res1.headers["Set-Cookie"] local re_url = res1.headers["Location"] - local m,err=ngx.re.match(re_url, "state=([0-9]*)") + local m, err = ngx.re.match(re_url, "state=([0-9]*)") if err or not m then log.error(err) end @@ -358,10 +355,10 @@ no session found headers = {Cookie = cookie} }) if not res2 then - ngx.say(err) + ngx.say(err2) end - if not res2.code == 302 then - log.error(res2.code) + if res2.status ~= 302 then + log.error(res2.status) end local cookie2 = res1.headers["Set-Cookie"] @@ -370,9 +367,9 @@ no session found headers = {Cookie = cookie2} }) if not res3 then - ngx.say(err) + ngx.say(err3) end - if not res3.status == 503 then + if res3.status ~= 503 then log.error(res3.status) end ngx.say("done") @@ -422,8 +419,8 @@ invalid state if not res2 then ngx.say(err) end - if not res2.code == 302 then - log.error(res2.code) + if res2.status ~= 302 then + log.error(res2.status) end local cookie2 = res1.headers["Set-Cookie"] @@ -433,9 +430,9 @@ invalid state }) if not res3 then - ngx.say(err) + ngx.say(err3) end - if not res3.status == 503 then + if res3.status ~= 503 then log.error(res3.status) end ngx.say("done") From 4407bb760b55d61f2edf10e4803f60397b15909d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Thu, 24 Mar 2022 19:39:13 +0800 Subject: [PATCH 07/13] feat: small revisions --- t/plugin/authz-casdoor.t | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index 4bd95e738e17..3ac8c3f6aaf2 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -275,7 +275,7 @@ done log.error(res2.status) end - local cookie2 = res1.headers["Set-Cookie"] + local cookie2 = res2.headers["Set-Cookie"] local res3, err3 = httpc:request_uri(fake_uri, { method = "GET", headers = {Cookie = cookie2} @@ -284,8 +284,8 @@ done if not res3 then ngx.say(err3) end - if not res3.status == 200 then - log.error(res3.status) + if res3.status ~= 200 then + log.error(res3.status,res3.headers["Location"]) end ngx.say("done") @@ -361,7 +361,7 @@ no session found log.error(res2.status) end - local cookie2 = res1.headers["Set-Cookie"] + local cookie2 = res2.headers["Set-Cookie"] local res3, err3 = httpc:request_uri(fake_uri, { method = "GET", headers = {Cookie = cookie2} @@ -417,13 +417,13 @@ invalid state headers = {Cookie = cookie} }) if not res2 then - ngx.say(err) + ngx.say(err2) end if res2.status ~= 302 then log.error(res2.status) end - local cookie2 = res1.headers["Set-Cookie"] + local cookie2 = res2.headers["Set-Cookie"] local res3, err3 = httpc:request_uri(fake_uri, { method = "GET", headers = {Cookie = cookie2} From d3e5ac1b45fa2276934e3562955ee81d4cafa867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Thu, 24 Mar 2022 23:15:26 +0800 Subject: [PATCH 08/13] fix: revision --- t/plugin/authz-casdoor.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index 3ac8c3f6aaf2..4289c8dd92a3 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -143,7 +143,7 @@ done } }]] ) - if not code == 200 then + if code ~= 200 then ngx.say("failed to set up routing rule") end ngx.say("done") From 9b013f89f254a1a6c1a72b173aa5fef0f309bb7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Fri, 25 Mar 2022 10:06:06 +0800 Subject: [PATCH 09/13] fix: revision --- apisix/plugins/authz-casdoor.lua | 13 ++++++++----- t/plugin/authz-casdoor.t | 6 +++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apisix/plugins/authz-casdoor.lua b/apisix/plugins/authz-casdoor.lua index e082a28e99d6..daa22e0571a0 100644 --- a/apisix/plugins/authz-casdoor.lua +++ b/apisix/plugins/authz-casdoor.lua @@ -44,15 +44,13 @@ local _M = { schema = schema } -local function fetch_access_token(ctx, conf, state_in_session) - local args = core.request.get_uri_args(ctx) +local function fetch_access_token(code, conf) local client = http.new() local url = conf.endpoint_addr .. "/api/login/oauth/access_token" - local res, err = client:request_uri(url, { method = "POST", body = ngx.encode_args({ - code = args.code, + code = code, grant_type = "authorization_code", client_id = conf.client_id, client_secret = conf.client_secret @@ -123,8 +121,13 @@ function _M.access(conf, ctx) core.log.error(err) return 400, err end + if not args.code then + err = "invalid code" + core.log.error(err) + return 400, err + end local access_token, lifetime, err = - fetch_access_token(ctx, conf, state_in_session) + fetch_access_token(args.code, conf) if err then core.log.error(err) return 503 diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index 4289c8dd92a3..23c418a7f1de 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -143,7 +143,7 @@ done } }]] ) - if code ~= 200 then + if code >= 300 then ngx.say("failed to set up routing rule") end ngx.say("done") @@ -194,7 +194,7 @@ done }]] ) - if code ~= 200 then + if code >= 300 then ngx.status = code end ngx.say(body) @@ -284,7 +284,7 @@ done if not res3 then ngx.say(err3) end - if res3.status ~= 200 then + if res3.status >= 300 then log.error(res3.status,res3.headers["Location"]) end ngx.say("done") From 897c7a92216e5b9ed30319b2a0c3d40ed1223148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Sat, 26 Mar 2022 11:00:53 +0800 Subject: [PATCH 10/13] fix: rebase --- t/plugin/authz-casdoor.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index 23c418a7f1de..df42d46f3812 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -89,7 +89,7 @@ __DATA__ } ok, err = plugin.check_schema(conf2) if ok then - ngx.say("err") + ngx.say("err: shouldn't have passed sanity check") end local conf3 = { @@ -100,7 +100,7 @@ __DATA__ } ok, err = plugin.check_schema(conf3) if ok then - ngx.say("err") + ngx.say("err: shouln't have passed sanity check") end ngx.say("done") From aea4d1ada99747f1d9f43f8dddd13c0bedfd7053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Sun, 27 Mar 2022 23:38:41 +0800 Subject: [PATCH 11/13] fix: fix spelling mistakes --- t/plugin/authz-casdoor.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index df42d46f3812..a192064d1038 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -100,7 +100,7 @@ __DATA__ } ok, err = plugin.check_schema(conf3) if ok then - ngx.say("err: shouln't have passed sanity check") + ngx.say("err: shouldn't have passed sanity check") end ngx.say("done") From 3c616487c1f1425e43a379311209d1693ac0b0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Sun, 27 Mar 2022 23:41:41 +0800 Subject: [PATCH 12/13] fix: revisions --- apisix/plugins/authz-casdoor.lua | 33 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/apisix/plugins/authz-casdoor.lua b/apisix/plugins/authz-casdoor.lua index daa22e0571a0..8124f4d004fa 100644 --- a/apisix/plugins/authz-casdoor.lua +++ b/apisix/plugins/authz-casdoor.lua @@ -128,26 +128,25 @@ function _M.access(conf, ctx) end local access_token, lifetime, err = fetch_access_token(args.code, conf) - if err then + if not access_token then core.log.error(err) return 503 end - if access_token then - local original_url = session_obj_read.data.original_uri - if not original_url then - err = "no original_url found in session" - core.log.error(err) - return 503 - end - local session_obj_write = session.new { - cookie = {lifetime = lifetime} - } - session_obj_write:start() - session_obj_write.data.access_token = access_token - session_obj_write:save() - core.response.set_header("Location", original_url) - return 302 + local original_url = session_obj_read.data.original_uri + if not original_url then + err = "no original_url found in session" + core.log.error(err) + return 503 end + local session_obj_write = session.new { + cookie = {lifetime = lifetime} + } + session_obj_write:start() + session_obj_write.data.access_token = access_token + session_obj_write:save() + core.response.set_header("Location", original_url) + return 302 + end -- step 2: check whether session exists @@ -159,7 +158,7 @@ function _M.access(conf, ctx) session_obj_write.data.state = state session_obj_write:save() - local redirect_url=conf.endpoint_addr .. "/login/oauth/authorize?" .. ngx.encode_args({ + local redirect_url = conf.endpoint_addr .. "/login/oauth/authorize?" .. ngx.encode_args({ response_type = "code", scope = "read", state = state, From 07bdf0014b398a35282e7c75a52b64f93ef285f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D0=B8=D1=89=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B8=D1=81=D1=82?= <2962928213@qq.com> Date: Sun, 27 Mar 2022 23:42:40 +0800 Subject: [PATCH 13/13] fix: revision --- apisix/plugins/authz-casdoor.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/apisix/plugins/authz-casdoor.lua b/apisix/plugins/authz-casdoor.lua index 8124f4d004fa..9fd8d8da8f1b 100644 --- a/apisix/plugins/authz-casdoor.lua +++ b/apisix/plugins/authz-casdoor.lua @@ -146,7 +146,6 @@ function _M.access(conf, ctx) session_obj_write:save() core.response.set_header("Location", original_url) return 302 - end -- step 2: check whether session exists