You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2020/02/24 02:54:55 UTC

[incubator-apisix] branch master updated: feature: Support password auth for plugin limit-count-redis (#1150)

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

membphis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 5b1a47a  feature: Support password auth for plugin limit-count-redis (#1150)
5b1a47a is described below

commit 5b1a47a38ec6d76d62132e02448bc1e122d16b90
Author: wonglend <gk...@qq.com>
AuthorDate: Mon Feb 24 10:54:48 2020 +0800

    feature: Support password auth for plugin limit-count-redis (#1150)
---
 .travis.yml                                        |   6 +-
 lua/apisix/plugins/limit-count.lua                 |   5 +-
 .../plugins/limit-count/limit-count-redis.lua      |  14 ++
 t/plugin/limit-count-redis.t                       | 234 +++++++++++++++++++++
 4 files changed, 256 insertions(+), 3 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index ee84fd8..58ce94f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,7 @@ matrix:
   include:
     - os: linux
       services:
-        - redis-server
+        - docker
       env: OSNAME=linux_openresty
     - os: osx
       env: OSNAME=osx_openresty
@@ -21,7 +21,7 @@ matrix:
           - /usr/local/Homebrew
     - os: linux
       services:
-        - redis-server
+        - docker
       env: OSNAME=linux_tengine
     - os: linux
       env: OSNAME=linux_apisix_luarocks
@@ -51,6 +51,8 @@ before_cache:
   - brew cleanup
 
 before_install:
+  - docker pull redis:3.0-alpine
+  - docker run --rm -itd -p 6379:6379 --name apisix_redis redis:3.0-alpine
   - echo $OSNAME
   - $PWD/.travis/${OSNAME}_runner.sh before_install
 
diff --git a/lua/apisix/plugins/limit-count.lua b/lua/apisix/plugins/limit-count.lua
index 8989d42..c95e3f6 100644
--- a/lua/apisix/plugins/limit-count.lua
+++ b/lua/apisix/plugins/limit-count.lua
@@ -45,6 +45,9 @@ local schema = {
         redis_port = {
             type = "integer", minimum = 1
         },
+        redis_password = {
+            type = "string", minLength = 0
+        },
         redis_timeout = {
             type = "integer", minimum = 1
         },
@@ -122,7 +125,7 @@ function _M.access(conf, ctx)
         end
 
         core.log.error("failed to limit req: ", err)
-        return 500
+        return 500, {error_msg = "failed to limit count: ", err}
     end
 
     core.response.set_header("X-RateLimit-Limit", conf.count,
diff --git a/lua/apisix/plugins/limit-count/limit-count-redis.lua b/lua/apisix/plugins/limit-count/limit-count-redis.lua
index ef86ab1..ab5dbeb 100644
--- a/lua/apisix/plugins/limit-count/limit-count-redis.lua
+++ b/lua/apisix/plugins/limit-count/limit-count-redis.lua
@@ -51,6 +51,20 @@ function _M.incoming(self, key)
         return false, err
     end
 
+    local count
+    count, err = red:get_reused_times()
+    if 0 == count then
+        if conf.redis_password and conf.redis_password ~= '' then
+            local ok, err = red:auth(conf.redis_password)
+            if not ok then
+                return nil, err
+            end
+        end
+    elseif err then
+        -- core.log.info(" err: ", err)
+        return nil, err
+    end
+
     local limit = self.limit
     local window = self.window
     local remaining
diff --git a/t/plugin/limit-count-redis.t b/t/plugin/limit-count-redis.t
index 63860ac..559d8a8 100644
--- a/t/plugin/limit-count-redis.t
+++ b/t/plugin/limit-count-redis.t
@@ -209,3 +209,237 @@ passed
 [404, 503, 404, 503, 503]
 --- no_error_log
 [error]
+
+
+
+=== TEST 6: set route, with redis host, port and right password
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            -- set redis password
+            local redis = require "resty.redis"
+
+            local red = redis:new()
+
+            red:set_timeout(1000) -- 1 sec
+
+            local ok, err = red:connect("127.0.0.1", 6379)
+            if not ok then
+                ngx.say("failed to connect: ", err)
+                return
+            end
+
+            -- for get_reused_times works
+            -- local ok, err = red:set_keepalive(10000, 100)
+            -- if not ok then
+            --     ngx.say("failed to set keepalive: ", err)
+            --     return
+            -- end
+
+            local count
+            count, err = red:get_reused_times()
+            if 0 == count then
+                local res, err = red:eval([[
+                    local key = 'requirepass'
+                    local value = "foobared"
+                    -- redis.replicate_commands()
+                    local val = redis.pcall('CONFIG', 'SET', key, value)
+                    return val
+                    ]], 0)
+                -- 
+                if not res then
+                    ngx.say("failed to set: ", err)
+                    return
+                end
+            elseif err then
+                -- ngx.say("already set requirepass done: ", err)
+                return
+            end
+
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "/hello",
+                    "plugins": {
+                        "limit-count": {
+                            "count": 2,
+                            "time_window": 60,
+                            "rejected_code": 503,
+                            "key": "remote_addr",
+                            "policy": "redis",
+                            "redis_host": "127.0.0.1",
+                            "redis_port": 6379,
+                            "redis_timeout": 1001,
+                            "redis_password": "foobared"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    }
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 7: up the limit
+--- pipelined_requests eval
+["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
+--- error_code eval
+[200, 200, 503, 503]
+--- no_error_log
+[error]
+
+
+
+=== TEST 8: up the limit
+--- pipelined_requests eval
+["GET /hello1", "GET /hello", "GET /hello2", "GET /hello", "GET /hello"]
+--- error_code eval
+[404, 503, 404, 503, 503]
+--- no_error_log
+[error]
+
+
+
+=== TEST 9: set route, with redis host, port and wrong password
+--- 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": {
+                        "limit-count": {
+                            "count": 2,
+                            "time_window": 60,
+                            "rejected_code": 503,
+                            "key": "remote_addr",
+                            "policy": "redis",
+                            "redis_host": "127.0.0.1",
+                            "redis_port": 6379,
+                            "redis_timeout": 1001,
+                            "redis_password": "WRONG_foobared"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello_new"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.print(body)
+        }
+    }
+--- request
+GET /t
+--- error_code eval
+200
+--- no_error_log
+[error]
+
+
+
+=== TEST 10: request for TEST 9
+--- request
+GET /hello_new
+--- error_code eval
+500
+--- response_body
+{"1":"ERR invalid password","error_msg":"failed to limit count: "}
+--- error_log
+failed to limit req: ERR invalid password
+
+
+
+=== TEST 11: multi request for TEST 9
+--- pipelined_requests eval
+["GET /hello_new", "GET /hello1", "GET /hello1", "GET /hello_new"]
+--- error_code eval
+[500, 404, 404, 500]
+
+
+
+=== TEST 12: restore redis password to ''
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            -- set redis password
+            local redis = require "resty.redis"
+
+            local red = redis:new()
+
+            red:set_timeout(1000) -- 1 sec
+
+            local ok, err = red:connect("127.0.0.1", 6379)
+            if not ok then
+                ngx.say("failed to connect: ", err)
+                return
+            end
+
+            -- for get_reused_times works
+            -- local ok, err = red:set_keepalive(10000, 100)
+            -- if not ok then
+            --     ngx.say("failed to set keepalive: ", err)
+            --     return
+            -- end
+
+            local count
+            count, err = red:get_reused_times()
+            if 0 == count then
+                local redis_password = "foobared"
+                if redis_password and redis_password ~= '' then
+                    local ok, err = red:auth(redis_password)
+                    if not ok then
+                        return nil, err
+                    end
+                end
+                local res, err = red:eval([[
+                    local key = 'requirepass'
+                    local value = ''
+                    -- redis.replicate_commands()
+                    local val = redis.pcall('CONFIG', 'SET', key, value)
+                    return val
+                    ]], 0)
+                -- 
+                if not res then
+                    ngx.say("failed to set: ", err)
+                    return
+                end
+            elseif err then
+                -- ngx.say("already set requirepass done: ", err)
+                return
+            end
+        }
+    }
+--- request
+GET /t
+--- error_code eval
+200
+--- no_error_log
+[error]