From 13534cdbda6a135f49256424a3db9ec58673543f Mon Sep 17 00:00:00 2001 From: Lien Date: Mon, 20 Jan 2020 09:58:13 +0800 Subject: [PATCH 01/16] doc: getting-started.md check (#1084) --- doc/getting-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/getting-started.md b/doc/getting-started.md index 3c78e5b37fc0..9d2f1564d14a 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -33,12 +33,12 @@ Let's deconstruct the above URL. - Scheme: HTTPS - Host/Address: httpbin.org - Port: 443 -- URI: get +- URI: /get - Query Parameters: foo1, foo2 ## Prerequisites -- The guide uses docker and docker-compose to setup APISIX. But if you have already installed APISIX via other methods, then you can skip to step 2. +- This guide uses docker and docker-compose to setup APISIX. But if you have already installed APISIX in other ways, you can just skip to [step 2](getting-started.md#step-2-create-a-route-in-apisix). - Curl: The guide uses curl command for API testing, but you can also use any other tool of your choice (Eg- Postman). ## Step 1: Install APISIX From 92d867619e7393d3145e1ca9aebad4f43f9e800a Mon Sep 17 00:00:00 2001 From: Lien Date: Mon, 20 Jan 2020 10:36:08 +0800 Subject: [PATCH 02/16] doc: response-rewrite.md optimiazition (#1083) --- doc/plugins/response-rewrite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/plugins/response-rewrite.md b/doc/plugins/response-rewrite.md index eb0983d742ad..0857f37c8b27 100644 --- a/doc/plugins/response-rewrite.md +++ b/doc/plugins/response-rewrite.md @@ -31,7 +31,7 @@ response rewrite plugin, rewrite the content from upstream. **senario**: 1. can set `Access-Control-Allow-*` series field to support CORS(Cross-origin Resource Sharing). -2. we can set customized `status_code` and `Location` field in header to achieve redirect, you can alse use [redirect](redirect-cn.md) plugin if you just want a redirect function.function +2. we can set customized `status_code` and `Location` field in header to achieve redirect, you can alse use [redirect](redirect-cn.md) plugin if you just want a redirection. ## Attributes |Name |Requirement|Description| From ff235940be54c98a2118bbc43f3c5a4539648b0c Mon Sep 17 00:00:00 2001 From: Nirojan Selvanathan Date: Tue, 21 Jan 2020 08:03:52 +0530 Subject: [PATCH 03/16] doc: Add contribution guidelines for the documentation (#1086) --- Contributing.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Contributing.md b/Contributing.md index 9b0f19075b9f..0a37ada77e9a 100644 --- a/Contributing.md +++ b/Contributing.md @@ -49,6 +49,43 @@ Once we've discussed your changes and you've got your code ready, make sure that * References the original issue in description, e.g. "Resolves #123". * Has a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +## Contribution Guidelines for Documentation + +* Active Voice + + In general use active voice when formulating the sentence instead of passive voice. A sentence written in the active voice will emphasize + the person or thing who is performing an action (eg.The dog chased the ball). In contrast, the passive voice will highlight + the recipient of the action (The ball was chased by the dog). Therefor use the passive voice, only when it's less important + who or what completed the action and more important that the action was completed. For example: + + - Recommended: The key-auth plugin authenticates the requests. + - Not recommended: The requests are authenticated by the key-auth plugin. + +* Capitalization: + + * For titles of a section, capitalize the first letter of each word except for the [closed-class words](http://babelnet.sbg.ac.at/themepark/grammar/classes.htm) + such as determiners, pronouns, conjunctions, and prepositions. Use the following [link](https://capitalizemytitle.com/#Chicago) for guidance. + - Recommended: Authentication **with** APISIX + + * For normal sentences don't [capitalize](https://www.grammarly.com/blog/capitalization-rules/) random words in the middle of the sentences. + Use the Chicago manual for capitalization rules for the documentation. + +* Second Person + + In general, use second person in your docs rather than first person. For example: + + - Recommended: You are recommended to use the docker based deployment. + - Not Recommended: We recommend to use the docker based deployment. + +* Spellings + + Use [American spellings](https://www.oxfordinternationalenglish.com/differences-in-british-and-american-spelling/) when + contributing to the documentation. + +* Voice + + * Use a friendly and conversational tone. Always use simple sentences. If the sentence is lengthy try to break it in to smaller sentences. + ## Do you have questions about the source code? - **QQ group**: 552030619 From 1c58e19cbdda43cb40f74bf13e23d962830888e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=90=9A=E8=87=B4=E8=BF=9C?= Date: Tue, 21 Jan 2020 17:58:24 +0800 Subject: [PATCH 04/16] doc: Update README.md (#1087) --- README.md | 17 ++++++++++------- README_CN.md | 15 +++++++++------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d21b30f03a80..6b7112bb9fca 100644 --- a/README.md +++ b/README.md @@ -138,20 +138,23 @@ you can follow the [documentation of limit count](doc/plugins/limit-count.md). Then you can try more [plugins](doc/README.md#plugins). ## Dashboard -APISIX has built-in support for dashboards, as follows: +APISIX has built-in support for Dashboard, as follows: -- Download the source code of [dashboard](https://github.com/apache/incubator-apisix-dashboard): +1. Please make sure your machine has Node 8.x or higher, or there will occur build issues. + +2. Download the source codes of [Dashboard](https://github.com/apache/incubator-apisix-dashboard): ``` git clone https://github.com/apache/incubator-apisix-dashboard.git ``` -- install yarn: refer to [documentation](https://yarnpkg.com/en/docs/install) -- Install dependencies and build + +3. Install [yarn](https://yarnpkg.com/en/docs/install) + +4. Install dependencies then run build command: ``` -yarn -yarn run build:prod +yarn && yarn build:prod ``` -- Integration with APISIX +5. Integration with APISIX Copy the compiled files under `/dist` directory to the `apisix/dashboard` directory, open `http://127.0.0.1:9080/apisix/dashboard/` in the browser. Do not need to fill the user name and password, log in directly. diff --git a/README_CN.md b/README_CN.md index 7346f3bbd8c7..19e3acac41b9 100644 --- a/README_CN.md +++ b/README_CN.md @@ -140,18 +140,21 @@ sudo apisix start APISIX 内置了对 Dashboard 的支持,使用步骤如下: -- 下载 [Dashboard](https://github.com/apache/incubator-apisix-dashboard) 的源码: +1. 确保你的运行环境中的 Node 版本高于或等于 8.x。 + +2. 下载 [Dashboard](https://github.com/apache/incubator-apisix-dashboard) 的源码: ``` git clone https://github.com/apache/incubator-apisix-dashboard.git ``` -- 安装yarn: 参考[安装文档](https://yarnpkg.com/zh-Hans/docs/install) -- 安装依赖并构建 + +3. 安装 [yarn](https://yarnpkg.com/zh-Hans/docs/install) + +4. 安装依赖并构建 ``` -yarn -yarn run build:prod +yarn && yarn build:prod ``` -- 与 APISIX 集成 +5. 与 APISIX 集成 把编译后的在 `/dist` 目录下的所有文件,拷贝到 `apisix/dashboard` 目录下。 使用浏览器打开 `http://127.0.0.1:9080/apisix/dashboard/` 即可使用, 不用填写用户名和密码,直接登录。 From 5f2210b421aa42cae77971bc04f50dab2bc57e8b Mon Sep 17 00:00:00 2001 From: YuanSheng Wang Date: Wed, 22 Jan 2020 16:19:01 +0800 Subject: [PATCH 05/16] travis: run a APISIX instance which intalled by luarocks. (#1063) --- .travis.yml | 3 + .travis/linux_apisix_luarocks_runner.sh | 74 +++++++++++++++++++++++++ utils/install-apisix.sh | 6 +- 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100755 .travis/linux_apisix_luarocks_runner.sh diff --git a/.travis.yml b/.travis.yml index 287fbb60ab0e..ee84fd88c3b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ matrix: fast_finish: true allow_failures: - os: osx + - env: OSNAME=linux_apisix_luarocks include: - os: linux @@ -22,6 +23,8 @@ matrix: services: - redis-server env: OSNAME=linux_tengine + - os: linux + env: OSNAME=linux_apisix_luarocks language: c diff --git a/.travis/linux_apisix_luarocks_runner.sh b/.travis/linux_apisix_luarocks_runner.sh new file mode 100755 index 000000000000..8a494ffdb739 --- /dev/null +++ b/.travis/linux_apisix_luarocks_runner.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# +# 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. +# + +set -ex + +export_or_prefix() { + export OPENRESTY_PREFIX="/usr/local/openresty-debug" +} + +do_install() { + wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add - + sudo apt-get -y update --fix-missing + sudo apt-get -y install software-properties-common + sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" + sudo add-apt-repository -y ppa:longsleep/golang-backports + + sudo apt-get update + sudo apt-get install openresty-debug +} + +script() { + export_or_prefix + export PATH=$OPENRESTY_PREFIX/nginx/sbin:$OPENRESTY_PREFIX/luajit/bin:$OPENRESTY_PREFIX/bin:$PATH + openresty -V + sudo service etcd start + + # install APISIX by shell + sudo mkdir -p /usr/local/apisix/deps + sudo PATH=$PATH ./utils/install-apisix.sh install + + sudo apisix help + sudo apisix init + sudo apisix start + sudo apisix stop + + sudo PATH=$PATH ./utils/install-apisix.sh remove + + # install APISIX by luarocks + sudo luarocks install rockspec/apisix-master-0.rockspec + + sudo apisix help + sudo apisix init + sudo apisix start + sudo apisix stop + + sudo luarocks remove rockspec/apisix-master-0.rockspec +} + +case_opt=$1 +shift + +case ${case_opt} in +do_install) + do_install "$@" + ;; +script) + script "$@" + ;; +esac diff --git a/utils/install-apisix.sh b/utils/install-apisix.sh index 9cdfb6c7c914..75295ddc5218 100755 --- a/utils/install-apisix.sh +++ b/utils/install-apisix.sh @@ -43,13 +43,13 @@ echo $UNAME do_install() { if [ "$UNAME" = "Darwin" ]; then - luarocks install --lua-dir=$LUA_JIT_DIR $APISIX_VER --tree=/usr/local/apisix/deps --local + sudo luarocks install --lua-dir=$LUA_JIT_DIR $APISIX_VER --tree=/usr/local/apisix/deps --local elif [ "$LUAROCKS_VER" = 'luarocks 3.' ]; then - luarocks install --lua-dir=$LUA_JIT_DIR $APISIX_VER --tree=/usr/local/apisix/deps --local + sudo luarocks install --lua-dir=$LUA_JIT_DIR $APISIX_VER --tree=/usr/local/apisix/deps --local else - luarocks install $APISIX_VER --tree=/usr/local/apisix/deps --local + sudo luarocks install $APISIX_VER --tree=/usr/local/apisix/deps --local fi sudo rm -f /usr/local/bin/apisix From affe4b7da284850f28c20a780e769d3526b98313 Mon Sep 17 00:00:00 2001 From: WenMing Date: Thu, 23 Jan 2020 22:06:02 +0800 Subject: [PATCH 06/16] doc: add English article. (#1089) --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index 6b7112bb9fca..698a9f594cb2 100644 --- a/README.md +++ b/README.md @@ -211,13 +211,7 @@ Using AWS's 8 core server, APISIX's QPS reach to 140,000 with a latency of only | Support any Nginx variable as routing condition | Yes | No | ## Videos And Articles -- 2019.12.14 [From 0 to 1: APISIX's Apache travel(Chinese)](https://zhuanlan.zhihu.com/p/99620158) -- 2019.12.14 [Next-generation microservice architecture based on Apache APISIX(Chinese)](https://www.upyun.com/opentalk/445.html) -- 2019.10.30 [Introduction to Apache APISIX Microservice Gateway Extreme Performance Architecture(Chinese)](https://www.upyun.com/opentalk/440.html) -- 2019.9.27 [Want to run APISIX on an ARM64 platform? Just three steps(Chinese)](https://zhuanlan.zhihu.com/p/84467919) -- 2019.8.31 [APISIX technology selection, testing and continuous integration(Chinese)](https://www.upyun.com/opentalk/433.html) -- 2019.8.31 [APISIX high performance practice 2(Chinese)](https://www.upyun.com/opentalk/437.html) -- 2019.7.6 [APISIX high performance practice(Chinese)](https://www.upyun.com/opentalk/429.html) +- 2019.8.31 [APISIX technology selection, testing and continuous integration](https://medium.com/@ming_wen/apache-apisixs-technology-selection-testing-and-continuous-integration-313221b02542) ## User Stories - [ke.com: How to Build a Gateway Based on Apache APISIX(Chinese)](https://mp.weixin.qq.com/s/yZl9MWPyF1-gOyCp8plflA) From 9889d66f269f73c67e45661d295f55870515ba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Mon, 27 Jan 2020 09:51:37 +0800 Subject: [PATCH 07/16] ci: remove patch which is no longer necessary and removed in the upstream. (#1090) --- .travis/linux_tengine_runner.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis/linux_tengine_runner.sh b/.travis/linux_tengine_runner.sh index c17566496188..6ce1a27ae49a 100755 --- a/.travis/linux_tengine_runner.sh +++ b/.travis/linux_tengine_runner.sh @@ -75,7 +75,6 @@ tengine_install() { wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-cache_manager_exit.patch wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-daemon_destroy_pool.patch wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-delayed_posted_events.patch - wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-gcc-maybe-uninitialized-warning.patch wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-hash_overflow.patch wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-init_cycle_pool_release.patch wget -P patches https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.17.4-larger_max_error_str.patch @@ -102,7 +101,6 @@ tengine_install() { patch -p1 < ../../patches/nginx-1.17.4-cache_manager_exit.patch patch -p1 < ../../patches/nginx-1.17.4-daemon_destroy_pool.patch patch -p1 < ../../patches/nginx-1.17.4-delayed_posted_events.patch - patch -p1 < ../../patches/nginx-1.17.4-gcc-maybe-uninitialized-warning.patch patch -p1 < ../../patches/nginx-1.17.4-hash_overflow.patch patch -p1 < ../../patches/nginx-1.17.4-init_cycle_pool_release.patch patch -p1 < ../../patches/nginx-1.17.4-larger_max_error_str.patch From 6240d1a9b426f48811af740b84e49b8c4979b8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Tue, 28 Jan 2020 12:11:47 +0800 Subject: [PATCH 08/16] chore: improve the core.log module (#1093) 1. implement the debug method with the generic logic, so you don't need to go into the method if you don't need it. 2. avoid computing the same result among different log levels --- lua/apisix/core/log.lua | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/lua/apisix/core/log.lua b/lua/apisix/core/log.lua index b0b60de97be5..902b88f3d7f2 100644 --- a/lua/apisix/core/log.lua +++ b/lua/apisix/core/log.lua @@ -32,37 +32,22 @@ local log_levels = { error = ngx.ERR, warn = ngx.WARN, notice = ngx.NOTICE, - info = ngx.INFO + info = ngx.INFO, + debug = ngx.DEBUG, } -do - local cur_level - -function _M.debug(...) - if not cur_level then - cur_level = ngx.config.subsystem == "http" and - require "ngx.errlog" .get_sys_filter_level() - end - - if not DEBUG and cur_level and ngx_DEBUG > cur_level then - return - end - - return ngx_log(ngx_DEBUG, ...) -end - -end -- do - - +local cur_level = ngx.config.subsystem == "http" and + require "ngx.errlog" .get_sys_filter_level() +local do_nothing = function() end setmetatable(_M, {__index = function(self, cmd) - local cur_level = ngx.config.subsystem == "http" and - require "ngx.errlog" .get_sys_filter_level() local log_level = log_levels[cmd] local method - if cur_level and log_levels[cmd] > cur_level then - method = function() end + if cur_level and (log_level > cur_level or + (log_level == ngx_DEBUG and not DEBUG)) + then + method = do_nothing else method = function(...) return ngx_log(log_level, ...) From 7a5bd663ca83e9d85a6a3e498aa9fca1bfbbda01 Mon Sep 17 00:00:00 2001 From: YuanSheng Wang Date: Tue, 28 Jan 2020 12:13:03 +0800 Subject: [PATCH 09/16] test: style, formatted by reindex. (#1081) --- t/plugin/fault-injection.t | 1 - t/plugin/udp-logger.t | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/t/plugin/fault-injection.t b/t/plugin/fault-injection.t index 14e3770c0448..1038d14a37d5 100644 --- a/t/plugin/fault-injection.t +++ b/t/plugin/fault-injection.t @@ -523,4 +523,3 @@ GET /hello HTTP/1.1 Fault Injection! --- no_error_log [error] - diff --git a/t/plugin/udp-logger.t b/t/plugin/udp-logger.t index 3ad4035fbb17..e30066cd6016 100644 --- a/t/plugin/udp-logger.t +++ b/t/plugin/udp-logger.t @@ -44,6 +44,7 @@ done [error] + === TEST 2: missing host --- config location /t { @@ -66,6 +67,7 @@ done [error] + === TEST 3: wrong type of string --- config location /t { @@ -88,6 +90,7 @@ done [error] + === TEST 4: add plugin --- config location /t { @@ -147,6 +150,7 @@ passed [error] + === TEST 5: access --- request GET /opentracing @@ -157,6 +161,7 @@ opentracing --- wait: 0.2 + === TEST 6: error log --- config location /t { From 76b62544479cab8da961fcf1ba03b91412ddefef Mon Sep 17 00:00:00 2001 From: WenMing Date: Sat, 1 Feb 2020 11:30:41 +0800 Subject: [PATCH 10/16] doc: add more english article. (#1092) --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 698a9f594cb2..364bd105db13 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against - **Multi protocols** - [TCP/UDP Proxy](doc/stream-proxy.md): Dynamic TCP/UDP proxy. - [Dynamic MQTT Proxy](doc/plugins/mqtt-proxy.md): Supports to load balance MQTT by `client_id`, both support MQTT [3.1.*](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html), [5.0](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html). - - [gRPC proxy](doc/grpc-proxy.md):Proxying gRPC traffic. - - [gRPC transcoding](doc/plugins/grpc-transcoding.md):Supports protocol transcoding so that clients can access your gRPC API by using HTTP/JSON. + - [gRPC proxy](doc/grpc-proxy.md): Proxying gRPC traffic. + - [gRPC transcoding](doc/plugins/grpc-transcoding.md): Supports protocol transcoding so that clients can access your gRPC API by using HTTP/JSON. - Proxy Websocket - Proxy Dubbo: Dubbo Proxy based on Tengine. - HTTP(S) Forward Proxy @@ -69,7 +69,7 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against - [Serverless](doc/plugins/serverless.md): Invoke functions in each phase in APISIX. - Dynamic Load Balancing: Round-robin load balancing with weight. - Hash-based Load Balancing: Load balance with consistent hashing sessions. - - [Health Checks](doc/health-check.md):Enable health check on the upstream node, and will automatically filter unhealthy nodes during load balancing to ensure system stability. + - [Health Checks](doc/health-check.md): Enable health check on the upstream node, and will automatically filter unhealthy nodes during load balancing to ensure system stability. - Circuit-Breaker: Intelligent tracking of unhealthy upstream services. - **Fine-grained routing** @@ -211,7 +211,8 @@ Using AWS's 8 core server, APISIX's QPS reach to 140,000 with a latency of only | Support any Nginx variable as routing condition | Yes | No | ## Videos And Articles -- 2019.8.31 [APISIX technology selection, testing and continuous integration](https://medium.com/@ming_wen/apache-apisixs-technology-selection-testing-and-continuous-integration-313221b02542) +- [APISIX technology selection, testing and continuous integration](https://medium.com/@ming_wen/apache-apisixs-technology-selection-testing-and-continuous-integration-313221b02542) +- [Analysis of Excellent Performance of Apache APISIX Microservices Gateway](https://medium.com/@ming_wen/analysis-of-excellent-performance-of-apache-apisix-microservices-gateway-fc77db4090b5) ## User Stories - [ke.com: How to Build a Gateway Based on Apache APISIX(Chinese)](https://mp.weixin.qq.com/s/yZl9MWPyF1-gOyCp8plflA) From 0ddf40a9106c4530a8f70f5e0878ec39809a8c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Sat, 1 Feb 2020 19:56:36 +0800 Subject: [PATCH 11/16] test: always specify perl include path. (#1097) Close #1091. --- Makefile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Makefile b/Makefile index bd60e0cc7022..a72f75ff20e6 100644 --- a/Makefile +++ b/Makefile @@ -168,12 +168,7 @@ install: ### test: Run the test case test: -ifeq ($(UNAME),Darwin) prove -I../test-nginx/lib -I./ -r -s t/ -else - prove -I../test-nginx/lib -r -s t/ -endif - ### license-check: Check Lua source code for Apache License .PHONY: license-check From 734b1650dd7911185928b17fe4cc95ffdb5f150c Mon Sep 17 00:00:00 2001 From: YuanSheng Wang Date: Sun, 2 Feb 2020 09:13:10 +0800 Subject: [PATCH 12/16] doc: check code style and test case style. (#1099) --- Contributing.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Contributing.md b/Contributing.md index 0a37ada77e9a..787a8501d9f2 100644 --- a/Contributing.md +++ b/Contributing.md @@ -86,6 +86,45 @@ Once we've discussed your changes and you've got your code ready, make sure that * Use a friendly and conversational tone. Always use simple sentences. If the sentence is lengthy try to break it in to smaller sentences. +## Check code style and test case style + +* code style + * Please take a look at [OpenResty Lua Coding Style Guide](CODE_STYLE.md). + * Use tool to check your code statically by command: `make lint`. +```shell + # install `luacheck` first before run it + $ luarocks install luacheck + # check source code + $ make lint + luacheck -q lua + Total: 0 warnings / 0 errors in 74 files + ./utils/lj-releng lua/*.lua \ + lua/apisix/*.lua \ + lua/apisix/admin/*.lua \ + lua/apisix/core/*.lua \ + lua/apisix/http/*.lua \ + lua/apisix/http/router/*.lua \ + lua/apisix/plugins/*.lua \ + lua/apisix/plugins/grpc-transcode/*.lua \ + lua/apisix/plugins/limit-count/*.lua > \ + /tmp/check.log 2>&1 || (cat /tmp/check.log && exit 1) +``` +* test case style + * Use tool to check your test case style statically by command, eg: `reindex t/admin/*.t`. +```shell + # install `reindex` first before run it + # wget https://raw.githubusercontent.com/iresty/openresty-devel-utils/master/reindex + # ./reindex test cases + $ reindex t/admin/*.t + reindex: t/plugin/example.t: skipped. # No changes needed + reindex: t/plugin/fault-injection.t: done. # updated + reindex: t/plugin/grpc-transcode.t: skipped. + ... ... + reindex: t/plugin/udp-logger.t: done. + reindex: t/plugin/zipkin.t: skipped. +``` + * By the way, we can download "reindex" to another path and add this path to "PATH" environment. + ## Do you have questions about the source code? - **QQ group**: 552030619 From fda20d99d55d91905622b9d780e4dce79d128e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Sun, 2 Feb 2020 09:13:34 +0800 Subject: [PATCH 13/16] feature: make the number of file is as configurable as the connections. (#1098) --- bin/apisix | 9 ++++++++- conf/config.yaml | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/bin/apisix b/bin/apisix index 89b26326258e..0102c389c135 100755 --- a/bin/apisix +++ b/bin/apisix @@ -88,7 +88,7 @@ worker_cpu_affinity auto; error_log {* error_log *} {* error_log_level or "error" *}; pid logs/nginx.pid; -worker_rlimit_nofile 20480; +worker_rlimit_nofile {* worker_rlimit_nofile *}; events { accept_mutex off; @@ -524,6 +524,13 @@ local function init() sys_conf[k] = v end + local wrn = sys_conf["worker_rlimit_nofile"] + local wc = sys_conf["event"]["worker_connections"] + if not wrn or wrn <= wc then + -- ensure the number of fds is slightly larger than the number of conn + sys_conf["worker_rlimit_nofile"] = wc + 128 + end + if(sys_conf["enable_dev_mode"] == true) then sys_conf["worker_processes"] = 1 else diff --git a/conf/config.yaml b/conf/config.yaml index 18d1ec3f4113..274a8cfed08c 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -59,6 +59,7 @@ apisix: nginx_config: # config for render the template to genarate nginx.conf error_log: "logs/error.log" error_log_level: "warn" # warn,error + worker_rlimit_nofile: 20480 # the number of files a worker process can open, should be larger than worker_connections event: worker_connections: 10620 http: From abcd1973120fc67bbe7f0c43c08e349d2cf9dcad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Tue, 4 Feb 2020 11:02:07 +0800 Subject: [PATCH 14/16] feature: increase the default size of the core file (#1105) Close #1101. --- bin/apisix | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/bin/apisix b/bin/apisix index 0102c389c135..69b745318d32 100755 --- a/bin/apisix +++ b/bin/apisix @@ -95,7 +95,7 @@ events { worker_connections {* event.worker_connections *}; } -worker_rlimit_core 500M; +worker_rlimit_core {* worker_rlimit_core *}; working_directory /tmp/apisix_cores/; worker_shutdown_timeout 3; @@ -437,6 +437,17 @@ local function get_openresty_version() return nil end +local function is_32bit_arch() + local ok, ffi = pcall(require, "ffi") + if ok then + -- LuaJIT + return ffi.abi("32bit") + end + local ret = excute_cmd("getconf LONG_BIT") + local bits = tonumber(ret) + return bits <= 32 +end + local function split(self, sep) local sep, fields = sep or ":", {} local pattern = string.format("([^%s]+)", sep) @@ -517,6 +528,12 @@ local function init() error("failed to read `nginx_config` field from yaml file") end + if is_32bit_arch() then + sys_conf["worker_rlimit_core"] = "4G" + else + sys_conf["worker_rlimit_core"] = "16G" + end + for k,v in pairs(yaml_conf.apisix) do sys_conf[k] = v end From a9f05e531b7fccf9093639f838bf23e3a34d41d8 Mon Sep 17 00:00:00 2001 From: WenMing Date: Thu, 6 Feb 2020 11:33:56 +0800 Subject: [PATCH 15/16] doc: updated the download link of rpm. (#1108) --- doc/how-to-build-cn.md | 2 +- doc/how-to-build.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/how-to-build-cn.md b/doc/how-to-build-cn.md index 7ed6b514d045..b63028672f20 100644 --- a/doc/how-to-build-cn.md +++ b/doc/how-to-build-cn.md @@ -45,7 +45,7 @@ make deps ### 通过 RPM 包安装(CentOS 7) ```shell -sudo yum install -y https://github.com/apache/incubator-apisix/releases/download/v1.0/apisix-1.0-0.el7.noarch.rpm +sudo yum install -y https://github.com/apache/incubator-apisix/releases/download/1.0/apisix-1.0-0.el7.noarch.rpm ``` ### 通过 Luarocks 安装 (不支持 macOS) diff --git a/doc/how-to-build.md b/doc/how-to-build.md index 82c1b899ebc0..4675629247fc 100644 --- a/doc/how-to-build.md +++ b/doc/how-to-build.md @@ -46,7 +46,7 @@ make deps ### Installation via RPM package (CentOS 7) ```shell -sudo yum install -y https://github.com/apache/incubator-apisix/releases/download/v1.0/apisix-1.0-0.el7.noarch.rpm +sudo yum install -y https://github.com/apache/incubator-apisix/releases/download/1.0/apisix-1.0-0.el7.noarch.rpm ``` ### Installation via Luarocks (macOS not supported) From 5fff97d0b1650dbcc0a0761b83e5e9419ea6d79f Mon Sep 17 00:00:00 2001 From: iGeeky Date: Thu, 6 Feb 2020 15:22:49 +0800 Subject: [PATCH 16/16] feature: Add wolf rbac plugin (#1095) --- .travis/ASF-Release.cfg | 1 - conf/config.yaml | 1 + doc/images/plugin/wolf-rbac-1.png | Bin 0 -> 79987 bytes doc/images/plugin/wolf-rbac-2.png | Bin 0 -> 85769 bytes doc/plugins/wolf-rbac-cn.md | 207 ++++++++++++++++ doc/plugins/wolf-rbac.md | 209 ++++++++++++++++ lua/apisix/plugins/wolf-rbac.lua | 386 ++++++++++++++++++++++++++++++ t/admin/plugins.t | 2 +- t/debug/debug-mode.t | 1 + t/lib/server.lua | 58 ++++- t/plugin/wolf-rbac.t | 334 ++++++++++++++++++++++++++ 11 files changed, 1191 insertions(+), 8 deletions(-) create mode 100644 doc/images/plugin/wolf-rbac-1.png create mode 100644 doc/images/plugin/wolf-rbac-2.png create mode 100644 doc/plugins/wolf-rbac-cn.md create mode 100644 doc/plugins/wolf-rbac.md create mode 100644 lua/apisix/plugins/wolf-rbac.lua create mode 100644 t/plugin/wolf-rbac.t diff --git a/.travis/ASF-Release.cfg b/.travis/ASF-Release.cfg index e967bdcccf3d..703a3611f957 100644 --- a/.travis/ASF-Release.cfg +++ b/.travis/ASF-Release.cfg @@ -87,7 +87,6 @@ grpc_server_example .travis.yml grpcurl t/servroot -grpcurl conf .travis/openwhisk-utilities diff --git a/conf/config.yaml b/conf/config.yaml index 274a8cfed08c..57efc2abad9b 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -96,6 +96,7 @@ plugins: # plugin list - response-rewrite - fault-injection - udp-logger + - wolf-rbac stream_plugins: - mqtt-proxy diff --git a/doc/images/plugin/wolf-rbac-1.png b/doc/images/plugin/wolf-rbac-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ce888d88289c9f21b8ddd2edab8029a4825ef401 GIT binary patch literal 79987 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 Wp4S|GTossW89ZJ6T-G@yGywo5DkcU1 literal 0 HcmV?d00001 diff --git a/doc/images/plugin/wolf-rbac-2.png b/doc/images/plugin/wolf-rbac-2.png new file mode 100644 index 0000000000000000000000000000000000000000..e1223c927268d97a7df159b3536379dee4bebb76 GIT binary patch literal 85769 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 + +[English](wolf-rbac.md) + +# 目录 + +- [**名字**](#名字) +- [**属性**](#属性) +- [**依赖项**](#依赖项) +- [**如何启用**](#如何启用) +- [**测试插件**](#测试插件) +- [**禁用插件**](#禁用插件) + +## 名字 + +`wolf-rbac` 是一个认证及授权(rbac)插件,它需要与 `consumer` 一起配合才能工作。同时需要添加 `wolf-rbac` 到一个 `service` 或 `route` 中。 +rbac功能由[wolf](https://github.com/iGeeky/wolf)提供, 有关 `wolf` 的更多信息, 请参考[wolf文档](https://github.com/iGeeky/wolf)。 + + +## 属性 + +* `server`: 设置 `wolf-server` 的访问地址, 如果未设置, 默认为: `http://127.0.0.1:10080`. +* `appid`: 设置应用id, 该应用id, 需要是在 `wolf-console` 中已经添加的应用id. + + +## 依赖项 + +### 安装 wolf, 并启动服务 + +[Wolf快速起步](https://github.com/iGeeky/wolf/blob/master/quick-start-with-docker/README-CN.md) + +### 添加应用, 管理员, 普通用户, 权限, 资源 及给用户授权. + +[Wolf管理使用](https://github.com/iGeeky/wolf/blob/master/docs/usage.md) + + +## 如何启用 + +1. 创建一个 consumer 对象,并设置插件 `wolf-rbac` 的值。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d ' +{ + "username":"wolf_rbac", + "plugins":{ + "wolf-rbac":{ + "server":"http://127.0.0.1:10080", + "appid":"restful" + } + }, + "desc":"wolf-rbac" +}' +``` + +你可以使用浏览器打开 dashboard:`http://127.0.0.1:9080/apisix/dashboard/`,通过 web 界面来完成上面的操作,先增加一个 consumer: +![](../images/plugin/wolf-rbac-1.png) + +然后在 consumer 页面中添加 wolf-rbac 插件: +![](../images/plugin/wolf-rbac-2.png) + +注意: 上面填写的 `appid` 需要在wolf控制台中已经存在的. + +2. 创建 Route 或 Service 对象,并开启 `wolf-rbac` 插件。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/*", + "plugins": { + "wolf-rbac": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "www.baidu.com:80": 1 + } + } +}' +``` + +## 测试插件 + +#### 首先进行登录获取 `wolf-rbac` token: + +下面的 `appid`, `username`, `password` 必须为wolf系统中真实存在的. + +* 以POST application/json方式登陆. + +```shell +curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \ +-H "Content-Type: application/json" \ +-d '{"appid": "restful", "username":"test", "password":"user-password"}' + +HTTP/1.1 200 OK +Date: Wed, 24 Jul 2019 10:33:31 GMT +Content-Type: text/plain +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX web server +{"rbac_token":"V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts","user_info":{"nickname":"test","username":"test","id":"749"}} +``` + +* 以POST x-www-form-urlencoded方式登陆 + +```shell +curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \ +-H "Content-Type: application/x-www-form-urlencoded" \ +-d 'appid=restful&username=test&password=user-password' +``` + + +#### 使用获取到的 token 进行请求尝试 + +* 缺少 token + +```shell +curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" -i + +HTTP/1.1 401 Unauthorized +... +{"message":"Missing rbac token in request"} +``` + +* token 放到请求头(Authorization)中: + +```shell +curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" \ +-H 'Authorization: V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -i + +HTTP/1.1 200 OK + + +``` + +* token 放到请求头(x-rbac-token)中: + +```shell +curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" \ +-H 'x-rbac-token: V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -i + + +HTTP/1.1 200 OK + + +``` + +* token 放到请求参数中: + +```shell +curl 'http://127.0.0.1:9080?rbac_token=V1%23restful%23eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -H"Host: www.baidu.com" -i + + +HTTP/1.1 200 OK + + +``` + +* token 放到 cookie 中: + +```shell +curl http://127.0.0.1:9080 -H"Host: www.baidu.com" \ +--cookie x-rbac-token=V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts -i + + +HTTP/1.1 200 OK + + +``` + +## 禁用插件 + +当你想去掉 `rbac-wolf` 插件的时候,很简单,在routes中的插件配置中把对应的 `插件` 配置删除即可,无须重启服务,即刻生效: + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/*", + "plugins": { + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "www.baidu.com:80": 1 + } + } +}' +``` + diff --git a/doc/plugins/wolf-rbac.md b/doc/plugins/wolf-rbac.md new file mode 100644 index 000000000000..639070b59df1 --- /dev/null +++ b/doc/plugins/wolf-rbac.md @@ -0,0 +1,209 @@ + + +[中文](wolf-rbac-cn.md) + +# Summary + +- [**Name**](#name) +- [**Attributes**](#attributes) +- [**Dependencies**](#dependencies) +- [**How To Enable**](#how-to-enable) +- [**Test Plugin**](#test-plugin) +- [**Disable Plugin**](#disable-plugin) + +## Name + +`wolf-rbac` is an authentication and authorization (rbac) plugin. It needs to work with `consumer`. Also need to add `wolf-rbac` to a` service` or `route`. +The rbac feature is provided by [wolf] (https://github.com/iGeeky/wolf). For more information about `wolf`, please refer to [wolf documentation] (https://github.com/iGeeky/wolf). + + +## Attributes + +* `server`: Set the service address of` wolf-server`. If not set, the default is: `http://127.0.0.1:10080`. +* `appid`: Set the app id. The app id must be added in wolf-console. + + +## Dependencies + +### Install wolf and start the service + +[Wolf quick start](https://github.com/iGeeky/wolf/blob/master/quick-start-with-docker/README.md) + +### Add `application`,` admin`, `normal user`,` permission`, `resource` and user authorize + +[Wolf-console usage](https://github.com/iGeeky/wolf/blob/master/docs/usage.md) + + +## How To Enable + +1. set a consumer and config the value of the `wolf-rbac`。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d ' +{ + "username":"wolf_rbac", + "plugins":{ + "wolf-rbac":{ + "server":"http://127.0.0.1:10080", + "appid":"restful" + } + }, + "desc":"wolf-rbac" +}' +``` + +You can visit the dashboard: `http://127.0.0.1:9080/apisix/dashboard/`, to complete the above operations through the web interface, first add a consumer: +![](../images/plugin/wolf-rbac-1.png) + +Then add the wolf-rbac plugin to the consumer page: +![](../images/plugin/wolf-rbac-2.png) + +Notes: The `appid` filled in above needs to already exist in the wolf system. + +1. Add a `Route` or `Service` and enable the wolf-rbac plugin. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/*", + "plugins": { + "wolf-rbac": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "www.baidu.com:80": 1 + } + } +}' +``` + +## Test Plugin + +#### Login and get `wolf-rbac` token: + +The following `appid`,` username`, and `password` must be real ones in the wolf system. + +* Login as `POST application/json` + +```shell +curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \ +-H "Content-Type: application/json" \ +-d '{"appid": "restful", "username":"test", "password":"user-password"}' + +HTTP/1.1 200 OK +Date: Wed, 24 Jul 2019 10:33:31 GMT +Content-Type: text/plain +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX web server +{"rbac_token":"V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts","user_info":{"nickname":"test","username":"test","id":"749"}} +``` + +* Login as `POST x-www-form-urlencoded` + +```shell +curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \ +-H "Content-Type: application/x-www-form-urlencoded" \ +-d 'appid=restful&username=test&password=user-password' +``` + + +#### try request with token + +* without token + +```shell +curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" -i + +HTTP/1.1 401 Unauthorized +... +{"message":"Missing rbac token in request"} +``` + +* request header(Authorization) with token: + +```shell +curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" \ +-H 'Authorization: V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -i + +HTTP/1.1 200 OK + + +``` + +* request header(x-rbac-token) with token: + +```shell +curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" \ +-H 'x-rbac-token: V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -i + + +HTTP/1.1 200 OK + + +``` + +* request params with token: + +```shell +curl 'http://127.0.0.1:9080?rbac_token=V1%23restful%23eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -H"Host: www.baidu.com" -i + + +HTTP/1.1 200 OK + + +``` + +* request cookie with token: + +```shell +curl http://127.0.0.1:9080 -H"Host: www.baidu.com" \ +--cookie x-rbac-token=V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts -i + + +HTTP/1.1 200 OK + + +``` + +## Disable Plugin + +When you want to disable the `wolf-rbac` plugin, it is very simple, + you can delete the corresponding json configuration in the plugin configuration, + no need to restart the service, it will take effect immediately: + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/*", + "plugins": { + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "www.baidu.com:80": 1 + } + } +}' +``` + diff --git a/lua/apisix/plugins/wolf-rbac.lua b/lua/apisix/plugins/wolf-rbac.lua new file mode 100644 index 000000000000..b38501ea1016 --- /dev/null +++ b/lua/apisix/plugins/wolf-rbac.lua @@ -0,0 +1,386 @@ +-- +-- 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 consumer = require("apisix.consumer") +local json = require("apisix.core.json") +local ngx_re = require("ngx.re") +local http = require("resty.http") +local ipairs = ipairs +local ngx = ngx +local tostring = tostring +local rawget = rawget +local rawset = rawset +local setmetatable = setmetatable +local type = type +local string = string + +local plugin_name = "wolf-rbac" + + +local schema = { + type = "object", + properties = { + appid = { + type = "string", + default = "unset" + }, + server = { + type = "string", + default = "http://127.0.0.1:10080" + }, + } +} + +local _M = { + version = 0.1, + priority = 2555, + type = 'auth', + name = plugin_name, + schema = schema, +} + + +local create_consume_cache +do + local consumer_ids = {} + + function create_consume_cache(consumers) + core.table.clear(consumer_ids) + + for _, consumer in ipairs(consumers.nodes) do + core.log.info("consumer node: ", core.json.delay_encode(consumer)) + consumer_ids[consumer.auth_conf.appid] = consumer + end + + return consumer_ids + end + +end -- do + +local token_version = 'V1' +local function create_rbac_token(appid, wolf_token) + return token_version .. "#" .. appid .. "#" .. wolf_token +end + +local function parse_rbac_token(rbac_token) + local res, err = ngx_re.split(rbac_token, "#", nil, nil, 3) + if not res then + return nil, err + end + + if #res ~= 3 or res[1] ~= token_version then + return nil, 'invalid rbac token: version' + end + local appid = res[2] + local wolf_token = res[3] + + return {appid = appid, wolf_token = wolf_token} +end + +local function new_headers() + local t = {} + local lt = {} + local _mt = { + __index = function(t, k) + return rawget(lt, string.lower(k)) + end, + __newindex = function(t, k, v) + rawset(t, k, v) + rawset(lt, string.lower(k), v) + end, + } + return setmetatable(t, _mt) +end + +-- timeout in ms +local function http_req(method, uri, body, myheaders, timeout) + if myheaders == nil then myheaders = new_headers() end + + local httpc = http.new() + if timeout then + httpc:set_timeout(timeout) + end + + local params = {method = method, headers = myheaders, body = body, ssl_verify = false} + local res, err = httpc:request_uri(uri, params) + if err then + core.log.error("FAIL REQUEST [ ",core.json.delay_encode( + {method = method, uri = uri, body = body, headers = myheaders}), + " ] failed! res is nil, err:", err) + return nil, err + end + + return res +end + +local function http_get(uri, myheaders, timeout) + return http_req("GET", uri, nil, myheaders, timeout) +end + +local function http_post(uri, body, myheaders, timeout) + return http_req("POST", uri, body, myheaders, timeout) +end + +function _M.check_schema(conf) + core.log.info("input conf: ", core.json.delay_encode(conf)) + + local ok, err = core.schema.check(schema, conf) + if not ok then + return false, err + end + + return true +end + + +local function fetch_rbac_token(ctx) + if ctx.var.arg_rbac_token then + return ngx.unescape_uri(ctx.var.arg_rbac_token) + end + + if ctx.var.http_authorization then + return ctx.var.http_authorization + end + + if ctx.var.http_x_rbac_token then + return ctx.var.http_x_rbac_token + end + + return ctx.var['cookie_x-rbac-token'] +end + + +local function check_url_permission(server, appid, action, resName, clientIP, wolf_token) + local retry_max = 3 + local errmsg + local userInfo + local res + local err + local access_check_url = server .. "/wolf/rbac/access_check" + local headers = new_headers() + headers["x-rbac-token"] = wolf_token + headers["Content-Type"] = "application/json; charset=utf-8" + local args = { appID = appid, resName = resName, action = action, clientIP = clientIP} + local url = access_check_url .. "?" .. ngx.encode_args(args) + local timeout = 1000 * 10 + + for i = 1, retry_max do + -- TODO: read apisix info. + res, err = http_get(url, headers, timeout) + if err then + break + else + core.log.info("check permission request:", url, ", status:", res.status, + ",body:", core.json.delay_encode(res.body)) + if res.status < 500 then + break + else + core.log.info("request [curl -v ", url, "] failed! status:", res.status) + if i < retry_max then + ngx.sleep(0.1) + end + end + end + end + + if err then + core.log.error("fail request: ", url, ", err:", err) + return {status = 500, err = "request to wolf-server failed, err:" .. tostring(err)} + end + + if res.status ~= 200 and res.status ~= 401 then + return {status = 500, err = 'request to wolf-server failed, status:' .. tostring(res.status)} + end + + local body, err = json.decode(res.body) + if err then + errmsg = 'check permission failed! parse response json failed!' + core.log.error( "json.decode(", res.body, ") failed! err:", err) + return {status = res.status, err = errmsg} + else + if body.data then + userInfo = body.data.userInfo + end + errmsg = body.reason + return {status = res.status, err = errmsg, userInfo = userInfo} + end +end + + +function _M.rewrite(conf, ctx) + local url = ctx.var.uri + local action = ctx.var.request_method + local clientIP = core.request.get_ip(ctx) + local permItem = {action = action, url = url, clientIP = clientIP} + core.log.info("hit wolf-rbac rewrite") + + local rbac_token = fetch_rbac_token(ctx) + if rbac_token == nil then + core.log.info("no permission to access ", core.json.delay_encode(permItem), ", need login!") + return 401, {message = "Missing rbac token in request"} + end + + local tokenInfo, err = parse_rbac_token(rbac_token) + core.log.info("token info: ", core.json.delay_encode(tokenInfo), ", err: ", err) + if err then + return 401, {message = 'invalid rbac token: parse failed'} + end + + local appid = tokenInfo.appid + local wolf_token = tokenInfo.wolf_token + permItem.appid = appid + permItem.wolf_token = wolf_token + + local consumer_conf = consumer.plugin(plugin_name) + if not consumer_conf then + return 401, {message = "Missing related consumer"} + end + + local consumers = core.lrucache.plugin(plugin_name, "consumers_key", + consumer_conf.conf_version, + create_consume_cache, consumer_conf) + + core.log.info("------ consumers: ", core.json.delay_encode(consumers)) + local consumer = consumers[appid] + if not consumer then + core.log.error("consumer [", appid, "] not found") + return 401, {message = "Invalid appid in rbac token"} + end + core.log.info("consumer: ", core.json.delay_encode(consumer)) + local server = consumer.auth_conf.server + + local url = ctx.var.uri + local action = ctx.var.request_method + local clientIP = core.request.get_ip(ctx) + local permItem = {appid = appid, action = action, url = url, clientIP = clientIP, wolf_token = wolf_token} + + local res = check_url_permission(server, appid, action, url, clientIP, wolf_token) + core.log.info(" check_url_permission(", core.json.delay_encode(permItem), ") res: ",core.json.delay_encode(res)) + + local username = nil + local nickname = nil + if type(res.userInfo) == 'table' then + local userInfo = res.userInfo + core.response.set_header("X-UserId", userInfo.id) + core.response.set_header("X-Username", userInfo.username) + core.response.set_header("X-Nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username) + ctx.userInfo = userInfo + username = userInfo.username + nickname = userInfo.nickname + end + + if res.status ~= 200 then + -- no permission. + core.log.error(" check_url_permission(", core.json.delay_encode(permItem), + ") failed, res: ",core.json.delay_encode(res)) + return 401, {message = res.err, username = username, nickname = nickname} + end + core.log.info("wolf-rbac check permission passed") +end + +local function get_args() + local ctx = ngx.ctx.api_ctx + local args, err + ngx.req.read_body() + if string.find(ctx.var.http_content_type or "","application/json", 1, true) then + args, err = json.decode(ngx.req.get_body_data()) + if err then + core.log.error("json.decode(", ngx.req.get_body_data(), ") failed! ", err) + end + else + args = ngx.req.get_post_args() + end + return args +end + +local function login() + local args = get_args() + if not args then + return core.response.exit(400, {message = "invalid request"}) + end + if not args.appid then + return core.response.exit(400, {message = "appid is missing"}) + end + + local appid = args.appid + + local consumer_conf = consumer.plugin(plugin_name) + if not consumer_conf then + return core.response.exit(500) + end + + local consumers = core.lrucache.plugin(plugin_name, "consumers_key", + consumer_conf.conf_version, + create_consume_cache, consumer_conf) + + core.log.info("------ consumers: ", core.json.delay_encode(consumers)) + local consumer = consumers[appid] + if not consumer then + core.log.info("request appid [", appid, "] not found") + return core.response.exit(400, {message = "appid [" .. tostring(appid) .. "] not found"}) + end + + core.log.info("consumer: ", core.json.delay_encode(consumer)) + + local uri = consumer.auth_conf.server .. '/wolf/rbac/login.rest' + local headers = new_headers() + headers["Content-Type"] = "application/json; charset=utf-8" + local timeout = 1000 * 5 + local request_debug = core.json.delay_encode( + {method = 'POST', uri = uri, body = args, headers = headers,timeout = timeout}) + core.log.info("login request [", request_debug, "] ....") + local res, err = http_post(uri, core.json.encode(args), headers, timeout) + if err or not res then + core.log.error("login request [", request_debug, "] failed! err: ", err) + return core.response.exit(500, {message = "request to wolf-server failed! " .. tostring(err)}) + end + core.log.info("login request [", request_debug, "] status: ", res.status, ", body: ", res.body) + + if res.status ~= 200 then + core.log.error("login request [", request_debug, "] failed! status: ", res.status) + return core.response.exit(500, {message = "request to wolf-server failed! status:" .. tostring(res.status) }) + end + local body, err = json.decode(res.body) + if err or not body then + core.log.error("login request [", request_debug, "] failed! err:", err) + return core.response.exit(500, {message = "request to wolf-server failed!"}) + end + if not body.ok then + core.log.error("user login [", request_debug, "] failed! response body:", core.json.delay_encode(body)) + return core.response.exit(200, {message = body.reason}) + end + core.log.info("user login [", request_debug, "] success! response body:", core.json.delay_encode(body)) + + local userInfo = body.data.userInfo + local wolf_token = body.data.token + + local rbac_token = create_rbac_token(appid, wolf_token) + core.response.exit(200, {rbac_token = rbac_token, user_info = userInfo}) +end + +function _M.api() + return { + { + methods = {"POST"}, + uri = "/apisix/plugin/wolf-rbac/login", + handler = login, + } + } +end + +return _M diff --git a/t/admin/plugins.t b/t/admin/plugins.t index b36a49140562..031eaff9f961 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -30,6 +30,6 @@ __DATA__ --- request GET /apisix/admin/plugins/list --- response_body_like eval -qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection",["udp-logger"]\]/ +qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac"\]/ --- no_error_log [error] diff --git a/t/debug/debug-mode.t b/t/debug/debug-mode.t index 23b6e90b1f11..b069a23d0eca 100644 --- a/t/debug/debug-mode.t +++ b/t/debug/debug-mode.t @@ -59,6 +59,7 @@ loaded plugin and sort by priority: 11000 name: fault-injection loaded plugin and sort by priority: 10000 name: serverless-pre-function loaded plugin and sort by priority: 3000 name: ip-restriction loaded plugin and sort by priority: 2599 name: openid-connect +loaded plugin and sort by priority: 2555 name: wolf-rbac loaded plugin and sort by priority: 2520 name: basic-auth loaded plugin and sort by priority: 2510 name: jwt-auth loaded plugin and sort by priority: 2500 name: key-auth diff --git a/t/lib/server.lua b/t/lib/server.lua index 60f57d97f3dc..a843158ae2f5 100644 --- a/t/lib/server.lua +++ b/t/lib/server.lua @@ -15,6 +15,7 @@ -- limitations under the License. -- local json_decode = require("cjson").decode +local json_encode = require("cjson").encode local _M = {} @@ -31,6 +32,9 @@ end function _M.server_port() ngx.print(ngx.var.server_port) end +_M.server_port_route2 = _M.server_port +_M.server_port_hello = _M.server_port +_M.server_port_aa = _M.server_port function _M.limit_conn() @@ -69,6 +73,8 @@ function _M.uri() ngx.say(k, ": ", v) end end +_M.uri_plugin_proxy_rewrite = _M.uri +_M.uri_plugin_proxy_rewrite_args = _M.uri function _M.old_uri() -- ngx.sleep(1) @@ -112,6 +118,50 @@ function _M.mock_zipkin() end end +function _M.wolf_rbac_login_rest() + ngx.req.read_body() + local data = ngx.req.get_body_data() + local args = json_decode(data) + if not args.username then + ngx.say(json_encode({ok=false, reason="ERR_USERNAME_MISSING"})) + ngx.exit(0) + end + if not args.password then + ngx.say(json_encode({ok=false, reason="ERR_PASSWORD_MISSING"})) + ngx.exit(0) + end + if args.username ~= "admin" then + ngx.say(json_encode({ok=false, reason="ERR_USER_NOT_FOUND"})) + ngx.exit(0) + end + if args.password ~= "123456" then + ngx.say(json_encode({ok=false, reason="ERR_PASSWORD_ERROR"})) + ngx.exit(0) + end + + ngx.say(json_encode({ok=true, data={token="wolf-rbac-token", + userInfo={nickname="administrator",username="admin", id="100"}}})) +end + +function _M.wolf_rbac_access_check() + local headers = ngx.req.get_headers() + local token = headers['x-rbac-token'] + if token ~= 'wolf-rbac-token' then + ngx.say(json_encode({ok=false, reason="ERR_TOKEN_INVALID"})) + ngx.exit(0) + end + + local args = ngx.req.get_uri_args() + local resName = args.resName + if resName == '/hello' then + ngx.say(json_encode({ok=true, data={ userInfo={nickname="administrator",username="admin", id="100"} }})) + else + ngx.status = 401 + ngx.say(json_encode({ok=false, reason="no permission to access"})) + end +end + + function _M.websocket_handshake() local websocket = require "resty.websocket.server" local wb, err = websocket:new() @@ -120,15 +170,11 @@ function _M.websocket_handshake() return ngx.exit(400) end end - +_M.websocket_handshake_route = _M.websocket_handshake function _M.go() local action = string.sub(ngx.var.uri, 2) - local find = string.find(action, "/", 1, true) - if find then - action = string.sub(action, 1, find - 1) - end - + action = string.gsub(action, "[/\\.]", "_") if not action or not _M[action] then return ngx.exit(404) end diff --git a/t/plugin/wolf-rbac.t b/t/plugin/wolf-rbac.t new file mode 100644 index 000000000000..e90e30775880 --- /dev/null +++ b/t/plugin/wolf-rbac.t @@ -0,0 +1,334 @@ +# +# 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(); +no_shuffle(); +run_tests; + +__DATA__ + +=== TEST 1: sanity +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.wolf-rbac") + local conf = { + + } + + local ok, err = plugin.check_schema(conf) + if not ok then + ngx.say(err) + end + + ngx.say(require("cjson").encode(conf)) + } + } +--- request +GET /t +--- response_body_like eval +qr/{"appid":"unset","server":"http:\\\/\\\/127\.0\.0\.1:10080"}/ +--- no_error_log +[error] + +=== TEST 2: wrong type of string +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.wolf-rbac") + local ok, err = plugin.check_schema({appid = 123}) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- request +GET /t +--- response_body +property "appid" validation failed: wrong type: expected string, got number +done +--- no_error_log +[error] + + +=== TEST 3: add consumer with username and plugins +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "wolf_rbac_unit_test", + "plugins": { + "wolf-rbac": { + "appid": "wolf-rbac-app", + "server": "http://127.0.0.1:1982" + } + } + }]], + [[{ + "node": { + "value": { + "username": "wolf_rbac_unit_test", + "plugins": { + "wolf-rbac": { + "appid": "wolf-rbac-app", + "server": "http://127.0.0.1:1982" + } + } + } + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + +=== TEST 4: enable wolf rbac plugin using admin api +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "wolf-rbac": {} + }, + "upstream": { + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello*" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + +=== TEST 5: login failed, appid is missing +--- request +POST /apisix/plugin/wolf-rbac/login +username=admin&password=123456 +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 400 +--- response_body_like eval +qr/appid is missing/ +--- no_error_log +[error] + + +=== TEST 6: login failed, appid not found +--- request +POST /apisix/plugin/wolf-rbac/login +appid=not-found&username=admin&password=123456 +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 400 +--- response_body_like eval +qr/appid \[not-found\] not found/ +--- no_error_log +[error] + + +=== TEST 7: login failed, username missing +--- request +POST /apisix/plugin/wolf-rbac/login +appid=wolf-rbac-app&password=123456 +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 200 +--- response_body_like eval +qr/ERR_USERNAME_MISSING/ + + +=== TEST 8: login failed, password missing +--- request +POST /apisix/plugin/wolf-rbac/login +appid=wolf-rbac-app&username=admin +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 200 +--- response_body_like eval +qr/ERR_PASSWORD_MISSING/ + + +=== TEST 9: login failed, username not found +--- request +POST /apisix/plugin/wolf-rbac/login +appid=wolf-rbac-app&username=not-found&password=123456 +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 200 +--- response_body_like eval +qr/ERR_USER_NOT_FOUND/ + + +=== TEST 10: login failed, wrong password +--- request +POST /apisix/plugin/wolf-rbac/login +appid=wolf-rbac-app&username=admin&password=wrong-password +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 200 +--- response_body_like eval +qr/ERR_PASSWORD_ERROR/ + + +=== TEST 11: login successfully +--- request +POST /apisix/plugin/wolf-rbac/login +{"appid": "wolf-rbac-app", "username": "admin","password": "123456"} +--- more_headers +Content-Type: application/json +--- error_code: 200 +--- response_body_like eval +qr/{"rbac_token":"V1#wolf-rbac-app#wolf-rbac-token","user_info":{"nickname":"administrator","username":"admin","id":"100"}}/ +--- no_error_log +[error] + + + +=== TEST 21: verify, missing token +--- request +GET /hello +--- error_code: 401 +--- response_body +{"message":"Missing rbac token in request"} +--- no_error_log +[error] + + +=== TEST 22: verify: invalid rbac token +--- request +GET /hello +--- error_code: 401 +--- more_headers +x-rbac-token: invalid-rbac-token +--- response_body +{"message":"invalid rbac token: parse failed"} +--- no_error_log +[error] + + +=== TEST 23: verify: invalid appid in rbac token +--- request +GET /hello +--- error_code: 401 +--- more_headers +x-rbac-token: V1#invalid-appid#rbac-token +--- response_body +{"message":"Invalid appid in rbac token"} + + +=== TEST 24: verify: failed +--- request +GET /hello1 +--- error_code: 401 +--- more_headers +x-rbac-token: V1#wolf-rbac-app#wolf-rbac-token +--- response_body +{"message":"no permission to access"} + + +=== TEST 25: verify (in argument) +--- request +GET /hello?rbac_token=V1%23wolf-rbac-app%23wolf-rbac-token +--- response_headers +X-UserId: 100 +X-Username: admin +X-Nickname: administrator +--- response_body +hello world +--- no_error_log +[error] + + +=== TEST 26: verify (in header Authorization) +--- request +GET /hello +--- more_headers +Authorization: V1#wolf-rbac-app#wolf-rbac-token +--- response_headers +X-UserId: 100 +X-Username: admin +X-Nickname: administrator +--- response_body +hello world +--- no_error_log +[error] + + +=== TEST 27: verify (in header x-rbac-token) +--- request +GET /hello +--- more_headers +x-rbac-token: V1#wolf-rbac-app#wolf-rbac-token +--- response_headers +X-UserId: 100 +X-Username: admin +X-Nickname: administrator +--- response_body +hello world +--- no_error_log +[error] + + +=== TEST 28: verify (in cookie) +--- request +GET /hello +--- more_headers +Cookie: x-rbac-token=V1#wolf-rbac-app#wolf-rbac-token +--- response_headers +X-UserId: 100 +X-Username: admin +X-Nickname: administrator +--- response_body +hello world +--- no_error_log +[error]