This is an automated email from the ASF dual-hosted git repository.
monkeydluffy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new e6adec520 change(ua-restriction): allowlist and denylist can't be
enabled at the same time (#9841)
e6adec520 is described below
commit e6adec5202785ce70311acf08c334302df7d6996
Author: Fucheng Jiang <[email protected]>
AuthorDate: Mon Jul 24 09:45:43 2023 +0800
change(ua-restriction): allowlist and denylist can't be enabled at the same
time (#9841)
---
apisix/plugins/ua-restriction.lua | 78 ++++---
docs/en/latest/plugins/ua-restriction.md | 2 +-
docs/zh/latest/plugins/ua-restriction.md | 2 +-
t/plugin/ua-restriction.t | 358 ++++++++++++++-----------------
4 files changed, 215 insertions(+), 225 deletions(-)
diff --git a/apisix/plugins/ua-restriction.lua
b/apisix/plugins/ua-restriction.lua
index ec74e7592..577dc2b67 100644
--- a/apisix/plugins/ua-restriction.lua
+++ b/apisix/plugins/ua-restriction.lua
@@ -22,11 +22,8 @@ local type = type
local str_strip = stringx.strip
local re_find = ngx.re.find
-local MATCH_NONE = 0
-local MATCH_ALLOW = 1
-local MATCH_DENY = 2
-
-local lrucache_useragent = core.lrucache.new({ ttl = 300, count = 4096 })
+local lrucache_allow = core.lrucache.new({ ttl = 300, count = 4096 })
+local lrucache_deny = core.lrucache.new({ ttl = 300, count = 4096 })
local schema = {
type = "object",
@@ -58,6 +55,10 @@ local schema = {
default = "Not allowed"
},
},
+ oneOf = {
+ {required = {"allowlist"}},
+ {required = {"denylist"}}
+ }
}
local plugin_name = "ua-restriction"
@@ -69,27 +70,56 @@ local _M = {
schema = schema,
}
-local function match_user_agent(user_agent, conf)
- user_agent = str_strip(user_agent)
- if conf.allowlist then
- for _, rule in ipairs(conf.allowlist) do
+local function check_with_allow_list(user_agents, allowlist)
+ local check = function (user_agent)
+ user_agent = str_strip(user_agent)
+
+ for _, rule in ipairs(allowlist) do
if re_find(user_agent, rule, "jo") then
- return MATCH_ALLOW
+ return true
end
end
+ return false
end
- if conf.denylist then
- for _, rule in ipairs(conf.denylist) do
+ if type(user_agents) == "table" then
+ for _, v in ipairs(user_agents) do
+ if lrucache_allow(v, allowlist, check, v) then
+ return true
+ end
+ end
+ return false
+ else
+ return lrucache_allow(user_agents, allowlist, check, user_agents)
+ end
+end
+
+
+local function check_with_deny_list(user_agents, denylist)
+ local check = function (user_agent)
+ user_agent = str_strip(user_agent)
+
+ for _, rule in ipairs(denylist) do
if re_find(user_agent, rule, "jo") then
- return MATCH_DENY
+ return false
end
end
+ return true
end
- return MATCH_NONE
+ if type(user_agents) == "table" then
+ for _, v in ipairs(user_agents) do
+ if lrucache_deny(v, denylist, check, v) then
+ return false
+ end
+ end
+ return true
+ else
+ return lrucache_deny(user_agents, denylist, check, user_agents)
+ end
end
+
function _M.check_schema(conf)
local ok, err = core.schema.check(schema, conf)
@@ -118,6 +148,7 @@ function _M.check_schema(conf)
return true
end
+
function _M.access(conf, ctx)
local user_agent = core.request.header(ctx, "User-Agent")
@@ -128,21 +159,16 @@ function _M.access(conf, ctx)
return 403, { message = conf.message }
end
end
- local match = MATCH_NONE
- if type(user_agent) == "table" then
- for _, v in ipairs(user_agent) do
- if type(v) == "string" then
- match = lrucache_useragent(v, conf, match_user_agent, v, conf)
- if match > MATCH_ALLOW then
- break
- end
- end
- end
+
+ local is_passed
+
+ if conf.allowlist then
+ is_passed = check_with_allow_list(user_agent, conf.allowlist)
else
- match = lrucache_useragent(user_agent, conf, match_user_agent,
user_agent, conf)
+ is_passed = check_with_deny_list(user_agent, conf.denylist)
end
- if match > MATCH_ALLOW then
+ if not is_passed then
return 403, { message = conf.message }
end
end
diff --git a/docs/en/latest/plugins/ua-restriction.md
b/docs/en/latest/plugins/ua-restriction.md
index d9dce2ba0..538bf9950 100644
--- a/docs/en/latest/plugins/ua-restriction.md
+++ b/docs/en/latest/plugins/ua-restriction.md
@@ -43,7 +43,7 @@ A common scenario is to set crawler rules. `User-Agent` is
the identity of the c
:::note
-Both `allowlist` and `denylist` can be used on their own. If they are used
together, the `allowlist` matches before the `denylist`.
+Both `allowlist` and `denylist` can't be used at the same time.
:::
diff --git a/docs/zh/latest/plugins/ua-restriction.md
b/docs/zh/latest/plugins/ua-restriction.md
index 3f31e092c..d8e21b62f 100644
--- a/docs/zh/latest/plugins/ua-restriction.md
+++ b/docs/zh/latest/plugins/ua-restriction.md
@@ -43,7 +43,7 @@ description: 本文介绍了 Apache APISIX ua-restriction 插件的使用方法
:::note
-`allowlist` 和 `denylist` 可以同时启用。同时启用时,插件会根据 `User-Agent` 先检查 `allowlist`,再检查
`denylist`。
+`allowlist` 和 `denylist` 不可以同时启用。
:::
diff --git a/t/plugin/ua-restriction.t b/t/plugin/ua-restriction.t
index 0e8a9544b..56f07b39b 100644
--- a/t/plugin/ua-restriction.t
+++ b/t/plugin/ua-restriction.t
@@ -38,13 +38,12 @@ run_tests;
__DATA__
-=== TEST 1: set allowlist, denylist, bypass_missing and user-defined message
+=== TEST 1: set both allowlist and denylist
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.ua-restriction")
local conf = {
- bypass_missing = true,
allowlist = {
"my-bot1",
"my-bot2"
@@ -53,18 +52,18 @@ __DATA__
"my-bot1",
"my-bot2"
},
- message = "User-Agent Forbidden",
}
local ok, err = plugin.check_schema(conf)
if not ok then
ngx.say(err)
+ return
end
ngx.say(require("toolkit.json").encode(conf))
}
}
--- response_body
-{"allowlist":["my-bot1","my-bot2"],"bypass_missing":true,"denylist":["my-bot1","my-bot2"],"message":"User-Agent
Forbidden"}
+value should match only one schema, but matches both schemas 1 and 2
@@ -216,88 +215,30 @@ User-Agent:my-bot2
-=== TEST 9: hit route and user-agent match denylist regex
+=== TEST 9: hit route and user-agent in denylist with reverse order multiple
user-agent
--- request
GET /hello
--- more_headers
-User-Agent:Baiduspider/3.0
+User-Agent:my-bot2
+User-Agent:my-bot1
--- error_code: 403
--- response_body
{"message":"Not allowed"}
-=== TEST 10: hit route and user-agent not in denylist
---- request
-GET /hello
---- more_headers
-User-Agent:foo/bar
---- error_code: 200
---- response_body
-hello world
-
-
-
-=== TEST 11: set allowlist
---- 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,
- [[{
- "uri": "/hello",
- "upstream": {
- "type": "roundrobin",
- "nodes": {
- "127.0.0.1:1980": 1
- }
- },
- "plugins": {
- "ua-restriction": {
- "allowlist": [
- "my-bot1",
- "(Baiduspider)/(\\d+)\\.(\\d+)"
- ]
- }
- }
- }]]
- )
-
- if code >= 300 then
- ngx.status = code
- end
- ngx.say(body)
- }
- }
---- response_body
-passed
-
-
-
-=== TEST 12: hit route and user-agent in allowlist
---- request
-GET /hello
---- more_headers
-User-Agent:my-bot1
---- error_code: 200
---- response_body
-hello world
-
-
-
-=== TEST 13: hit route and user-agent match allowlist regex
+=== TEST 10: hit route and user-agent match denylist regex
--- request
GET /hello
--- more_headers
User-Agent:Baiduspider/3.0
---- error_code: 200
+--- error_code: 403
--- response_body
-hello world
+{"message":"Not allowed"}
-=== TEST 14: hit route and user-agent not in allowlist
+=== TEST 11: hit route and user-agent not in denylist
--- request
GET /hello
--- more_headers
@@ -308,7 +249,7 @@ hello world
-=== TEST 15: set config: user-agent in both allowlist and denylist
+=== TEST 12: set allowlist
--- config
location /t {
content_by_lua_block {
@@ -326,11 +267,7 @@ hello world
"plugins": {
"ua-restriction": {
"allowlist": [
- "foo/bar",
- "(Baiduspider)/(\\d+)\\.(\\d+)"
- ],
- "denylist": [
- "foo/bar",
+ "my-bot1",
"(Baiduspider)/(\\d+)\\.(\\d+)"
]
}
@@ -349,157 +286,62 @@ passed
-=== TEST 16: hit route and user-agent in both allowlist and denylist,
pass(part 1)
+=== TEST 13: hit route and user-agent in allowlist
--- request
GET /hello
--- more_headers
-User-Agent:foo/bar
+User-Agent:my-bot1
--- error_code: 200
--- response_body
hello world
-=== TEST 17: hit route and user-agent in both allowlist and denylist,
pass(part 2)
+=== TEST 14: hit route and user-agent match allowlist regex
--- request
GET /hello
--- more_headers
-User-Agent:Baiduspider/1.0
+User-Agent:Baiduspider/3.0
--- error_code: 200
--- response_body
hello world
-=== TEST 18: bypass_missing test, using default, reset conf(part1)
---- 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,
- [[{
- "uri": "/hello",
- "upstream": {
- "type": "roundrobin",
- "nodes": {
- "127.0.0.1:1980": 1
- }
- },
- "plugins": {
- "ua-restriction": {
- }
- }
- }]]
- )
-
- if code >= 300 then
- ngx.status = code
- end
- ngx.say(body)
- }
- }
---- response_body
-passed
-
-
-
-=== TEST 19: bypass_missing test, using default, send request without
User-Agent(part2)
+=== TEST 15: hit route and user-agent not in allowlist
--- request
GET /hello
+--- more_headers
+User-Agent:foo/bar
--- error_code: 403
--- response_body
{"message":"Not allowed"}
-=== TEST 20: bypass_missing test, set to true(part1)
---- 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,
- [[{
- "uri": "/hello",
- "upstream": {
- "type": "roundrobin",
- "nodes": {
- "127.0.0.1:1980": 1
- }
- },
- "plugins": {
- "ua-restriction": {
- "bypass_missing": true
- }
- }
- }]]
- )
-
- if code >= 300 then
- ngx.status = code
- end
- ngx.say(body)
- }
- }
---- response_body
-passed
-
-
-
-=== TEST 21: bypass_missing test, set to true, send request without
User-Agent(part2)
+=== TEST 16: hit route and user-agent in allowlist with multiple user-agent
--- request
GET /hello
---- error_code: 200
+--- more_headers
+User-Agent:foo/bar
+User-Agent:my-bot1
--- response_body
hello world
-=== TEST 22: bypass_missing test, set to false(part1)
---- 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,
- [[{
- "uri": "/hello",
- "upstream": {
- "type": "roundrobin",
- "nodes": {
- "127.0.0.1:1980": 1
- }
- },
- "plugins": {
- "ua-restriction": {
- "bypass_missing": false
- }
- }
- }]]
- )
-
- if code >= 300 then
- ngx.status = code
- end
- ngx.say(body)
- }
- }
---- response_body
-passed
-
-
-
-=== TEST 23: bypass_missing test, set to false, send request without
User-Agent(part2)
+=== TEST 17: hit route and user-agent in allowlist with reverse order
multiple user-agent
--- request
GET /hello
---- error_code: 403
+--- more_headers
+User-Agent:my-bot1
+User-Agent:foo/bar
--- response_body
-{"message":"Not allowed"}
+hello world
-=== TEST 24: message that do not reach the minimum range
+=== TEST 18: message that do not reach the minimum range
--- config
location /t {
content_by_lua_block {
@@ -530,7 +372,7 @@ qr/string too short, expected at least 1, got 0/
-=== TEST 25: exceeds the maximum limit of message
+=== TEST 19: exceeds the maximum limit of message
--- config
location /t {
content_by_lua_block {
@@ -568,7 +410,7 @@ qr/string too long, expected at most 1024, got 1025/
-=== TEST 26: set custom message
+=== TEST 20: set custom message
--- config
location /t {
content_by_lua_block {
@@ -606,7 +448,7 @@ passed
-=== TEST 27: test custom message
+=== TEST 21: test custom message
--- request
GET /hello
--- more_headers
@@ -617,7 +459,7 @@ User-Agent:Baiduspider/1.0
-=== TEST 28: test remove ua-restriction, add denylist(part 1)
+=== TEST 22: test remove ua-restriction, add denylist(part 1)
--- config
location /enable {
content_by_lua_block {
@@ -656,7 +498,7 @@ passed
-=== TEST 29: test remove ua-restriction, fail(part 2)
+=== TEST 23: test remove ua-restriction, fail(part 2)
--- request
GET /hello
--- more_headers
@@ -667,7 +509,7 @@ User-Agent:Baiduspider/1.0
-=== TEST 30: test remove ua-restriction, remove plugin(part 3)
+=== TEST 24: test remove ua-restriction, remove plugin(part 3)
--- config
location /disable {
content_by_lua_block {
@@ -701,7 +543,7 @@ passed
-=== TEST 31: test remove ua-restriction, check spider User-Agent(part 4)
+=== TEST 25: test remove ua-restriction, check spider User-Agent(part 4)
--- request
GET /hello
--- more_headers
@@ -711,7 +553,7 @@ hello world
-=== TEST 32: set disable=true
+=== TEST 26: set disable=true
--- config
location /t {
content_by_lua_block {
@@ -744,7 +586,7 @@ passed
-=== TEST 33: the element in allowlist is null
+=== TEST 27: the element in allowlist is null
--- config
location /t {
content_by_lua_block {
@@ -771,7 +613,7 @@ done
-=== TEST 34: the element in denylist is null
+=== TEST 28: the element in denylist is null
--- config
location /t {
content_by_lua_block {
@@ -795,3 +637,125 @@ done
--- response_body
property "denylist" validation failed: wrong type: expected array, got table
done
+
+
+
+=== TEST 29: test both allowlist and denylist are not exist
+--- 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,
+ [[{
+ "uri": "/hello",
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ },
+ "plugins": {
+ "ua-restriction": {
+ }
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"failed to check the configuration of plugin ua-restriction err:
value should match only one schema, but matches none"}
+
+
+
+=== TEST 30: test bypass_missing
+--- 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,
+ [[{
+ "uri": "/hello",
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ },
+ "plugins": {
+ "ua-restriction": {
+ "allowlist": [
+ "my-bot1"
+ ]
+ }
+ }
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 31: hit
+--- request
+GET /hello
+--- error_code: 403
+--- response_body
+{"message":"Not allowed"}
+
+
+
+=== TEST 32: test bypass_missing with true
+--- 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,
+ [[{
+ "uri": "/hello",
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ },
+ "plugins": {
+ "ua-restriction": {
+ "bypass_missing": true,
+ "denylist": [
+ "my-bot1"
+ ]
+ }
+ }
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 33: hit
+--- request
+GET /hello
+--- response_body
+hello world