spacewander commented on a change in pull request #6382: URL: https://github.com/apache/apisix/pull/6382#discussion_r811634313
########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, Review comment: Let's remove the casdoor_ prefix ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, Review comment: Let's remove the casdoor_ prefix ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") Review comment: Let's sort the imports like https://github.com/apache/apisix/blob/462413551e2eca0ed1ced54742d3c961b9dc5f06/apisix/plugins/authz-casbin.lua#L20 ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", + { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.casdoor_client_id, + client_secret = conf.casdoor_client_secret + } + } + ) + if not res then + log.err("failed when accessing token. ", err) + return nil + end + local data = cjson.decode(res.body) + if not data.access_token then + log.err("failed when accessing token: no access_token contained") + return nil + end + return data.access_token +end + +function _M.check_schema(conf) + return core.schema.check(schema, conf) +end + +function _M.access(conf, ctx) + log.warn("hit auth-casdoor access") + local current_uri = ngx.var.request_uri Review comment: ```suggestion local current_uri = ctx.var.uri ``` ########## File path: conf/config-default.yaml ########## @@ -340,6 +340,7 @@ plugins: # plugin list (sorted by priority) - request-validation # priority: 2800 - openid-connect # priority: 2599 - authz-casbin # priority: 2560 + - auth-casdoor # priority: 2561 Review comment: Please sort according to the priority and fix the indent ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, Review comment: priority mismatch ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", + { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.casdoor_client_id, + client_secret = conf.casdoor_client_secret + } + } + ) + if not res then + log.err("failed when accessing token. ", err) + return nil + end + local data = cjson.decode(res.body) Review comment: Need to check if decode succeed ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() Review comment: ```suggestion local args = core.request.get_uri_args() ``` ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil Review comment: ```suggestion return nil, err ``` and log the err outside would be better ########## File path: docs/en/latest/plugins/auth-casdoor.md ########## @@ -0,0 +1,76 @@ +--- +title: auth-casdoor +--- + +<!-- +# +# 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. +# +--> + +## 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 | +| ----------- | ------ | ----------- | ------- | ----- | ------------------------------------------------------------ | +| casdoor_endpoint | string | required | | | The url of casdoor. | +| casdoor_client_id | string | required | | | The client id in casdoor. | +| casdoor_client_secret | string | required | | | The client secret in casdoor. | +| casdoor_callback_url | string | required | | | The callback url which is used to receive state and code. | + +## 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": { + "casdoor_callback_url":"http://localhost:9080/anything/callback", + "casdoor_endpoint":"http://localhost:8000", + "casdoor_client_id":"7ceb9b7fda4a9061ec1c", + "casdoor_client_secret":"3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } +}' + +``` + +By doing this all requests toward `/anything/*` will be intercepted and whether this user has logged in via Casdoor will be checked (by checking session). If not, the user will be redirected to login page of casdoor, thus implementing authentication without modifying server's code. Review comment: Could you provide a step-by-step example? I still can't fully understand it after reading it twice... It looks like the callback_url needs to contain part of the request host & path? ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", + { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.casdoor_client_id, + client_secret = conf.casdoor_client_secret + } + } + ) + if not res then + log.err("failed when accessing token. ", err) + return nil + end + local data = cjson.decode(res.body) + if not data.access_token then + log.err("failed when accessing token: no access_token contained") + return nil + end + return data.access_token +end + +function _M.check_schema(conf) + return core.schema.check(schema, conf) +end + +function _M.access(conf, ctx) + log.warn("hit auth-casdoor access") + local current_uri = ngx.var.request_uri + local session_obj_read = session.open() + -- step 1: check whether hits the callback + if get_path(current_uri) == get_path(conf.casdoor_callback_url) then + local access_token = fetch_access_token(conf) + if not access_token then + return 500, "failed to fetch access token" Review comment: ```suggestion return 503, "failed to fetch access token" ``` ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", + { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.casdoor_client_id, + client_secret = conf.casdoor_client_secret + } + } + ) + if not res then + log.err("failed when accessing token. ", err) + return nil + end + local data = cjson.decode(res.body) + if not data.access_token then + log.err("failed when accessing token: no access_token contained") + return nil + end + return data.access_token +end + +function _M.check_schema(conf) + return core.schema.check(schema, conf) +end + +function _M.access(conf, ctx) + log.warn("hit auth-casdoor access") Review comment: We should remove such a per-req log ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", + { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.casdoor_client_id, + client_secret = conf.casdoor_client_secret + } + } + ) + if not res then + log.err("failed when accessing token. ", err) + return nil + end + local data = cjson.decode(res.body) + if not data.access_token then + log.err("failed when accessing token: no access_token contained") + return nil + end + return data.access_token +end + +function _M.check_schema(conf) + return core.schema.check(schema, conf) +end + +function _M.access(conf, ctx) + log.warn("hit auth-casdoor access") + local current_uri = ngx.var.request_uri + local session_obj_read = session.open() + -- step 1: check whether hits the callback + if get_path(current_uri) == get_path(conf.casdoor_callback_url) then + local access_token = fetch_access_token(conf) + if not access_token then + return 500, "failed to fetch access token" + else + local original_url = session_obj_read.data.original_uri + local session_obj_write = session.start() + session_obj_write.data.access_token = access_token + session_obj_write:save() + ngx.redirect(original_url, 302) + return + end + end + + --step 2: check whether session exists + + if session_obj_read.data.access_token then + -- session exists + log.warn("session exists") Review comment: Ditto. Warn log should not be used in per-req level ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", + { + method = "POST", + query = { + code = args.code, + grant_type = "authorization_code", + client_id = conf.casdoor_client_id, + client_secret = conf.casdoor_client_secret + } + } + ) + if not res then + log.err("failed when accessing token. ", err) + return nil + end + local data = cjson.decode(res.body) + if not data.access_token then + log.err("failed when accessing token: no access_token contained") + return nil + end + return data.access_token +end + +function _M.check_schema(conf) + return core.schema.check(schema, conf) +end + +function _M.access(conf, ctx) + log.warn("hit auth-casdoor access") + local current_uri = ngx.var.request_uri + local session_obj_read = session.open() + -- step 1: check whether hits the callback + if get_path(current_uri) == get_path(conf.casdoor_callback_url) then + local access_token = fetch_access_token(conf) + if not access_token then + return 500, "failed to fetch access token" + else Review comment: ``` if ... return end -- the other branch ``` is prefer ########## File path: apisix/plugins/auth-casdoor.lua ########## @@ -0,0 +1,128 @@ +-- +-- 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 log = core.log +local ngx = ngx +local session = require("resty.session") +local http = require("resty.http") +local cjson = require("cjson") + +local plugin_name = "auth-casdoor" +local schema = { + type = "object", + properties = { + casdoor_endpoint = { type = "string" }, + casdoor_client_id = { type = "string" }, + casdoor_client_secret = { type = "string" }, + casdoor_callback_url = { type = "string" }, + }, + required = { + "casdoor_callback_url", + "casdoor_endpoint", + "casdoor_client_id", + "casdoor_client_secret" + } +} + +local _M = { + version = 0.1, + priority = 12, + name = plugin_name, + schema = schema, +} + +local function get_path(uri) + local without_query = uri:match("(.-)%?") or uri + return without_query:match(".-//[^/]+(/.*)") or without_query +end + +local function fetch_access_token(conf) + local args = ngx.req.get_uri_args() + if not args.code or not args.state then + log.err("failed when accessing token. Invalid code or state ") + return nil + end + local client = http.new() + local res, err = client:request_uri( + get_path(conf.casdoor_endpoint) .. "/api/login/oauth/access_token", Review comment: Let's check if the endpoint contains `?` in the schema instead of split it at runtime -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
