diff --git a/apisix/plugins/ua-restriction.lua b/apisix/plugins/ua-restriction.lua new file mode 100644 index 000000000000..95bc3d47a7f2 --- /dev/null +++ b/apisix/plugins/ua-restriction.lua @@ -0,0 +1,124 @@ +-- +-- 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 ipairs = ipairs +local core = require("apisix.core") +local stringx = require('pl.stringx') +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 schema = { + type = "object", + properties = { + bypass_missing = { + type = "boolean", + default = false, + }, + allowlist = { + type = "array", + minItems = 1 + }, + denylist = { + type = "array", + minItems = 1 + }, + message = { + type = "string", + minLength = 1, + maxLength = 1024, + default = "Not allowed" + }, + }, + additionalProperties = false, +} + +local plugin_name = "ua-restriction" + +local _M = { + version = 0.1, + priority = 2999, + name = plugin_name, + 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 + if re_find(user_agent, rule, "jo") then + return MATCH_ALLOW + end + end + end + + if conf.denylist then + for _, rule in ipairs(conf.denylist) do + if re_find(user_agent, rule, "jo") then + return MATCH_DENY + end + end + end + + return MATCH_NONE +end + +function _M.check_schema(conf) + local ok, err = core.schema.check(schema, conf) + + if not ok then + return false, err + end + + return true +end + +function _M.access(conf, ctx) + local user_agent = core.request.header(ctx, "User-Agent") + + if not user_agent then + if conf.bypass_missing then + return + else + 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 + else + match = lrucache_useragent(user_agent, conf, match_user_agent, user_agent, conf) + end + + if match > MATCH_ALLOW then + return 403, { message = conf.message } + end +end + +return _M diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 8db9af02f15f..4078600fdcd3 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -280,6 +280,7 @@ plugins: # plugin list (sorted by priority) - batch-requests # priority: 4010 - cors # priority: 4000 - ip-restriction # priority: 3000 + - ua-restriction # priority: 2999 - referer-restriction # priority: 2990 - uri-blocker # priority: 2900 - request-validation # priority: 2800 diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json index 2f088781efff..72565a642304 100644 --- a/docs/en/latest/config.json +++ b/docs/en/latest/config.json @@ -73,6 +73,7 @@ "plugins/cors", "plugins/uri-blocker", "plugins/ip-restriction", + "plugins/ua-restriction", "plugins/referer-restriction", "plugins/consumer-restriction" ] diff --git a/docs/en/latest/plugins/ua-restriction.md b/docs/en/latest/plugins/ua-restriction.md new file mode 100644 index 000000000000..7855ccff21c5 --- /dev/null +++ b/docs/en/latest/plugins/ua-restriction.md @@ -0,0 +1,130 @@ +--- +title: ua-restriction +--- + + + +## Summary + +- [**Name**](#name) +- [**Attributes**](#attributes) +- [**How To Enable**](#how-to-enable) +- [**Test Plugin**](#test-plugin) +- [**Disable Plugin**](#disable-plugin) + +## Name + +The `ua-restriction` can restrict access to a Service or a Route by `allowlist` and `denylist` `User-Agent` header. + +## Attributes + +| Name | Type | Requirement | Default | Valid | Description | +| --------- | ------------- | ----------- | ------- | ----- | ---------------------------------------- | +| bypass_missing | boolean | optional | false | | Whether to bypass the check when the User-Agent header is missing | +| allowlist | array[string] | optional | | | A list of allowed User-Agent headers. | +| denylist | array[string] | optional | | | A list of denied User-Agent headers. | +| message | string | optional | Not allowed. | length range: [1, 1024] | Message of deny reason. | + +Any of `allowlist` or `denylist` can be optional, and can work together in this order: allowlist->denylist + +The message can be user-defined. + +## How To Enable + +Creates a route or service object, and enable plugin `ua-restriction`. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/index.html", + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + }, + "plugins": { + "ua-restriction": { + "bypass_missing": true, + "allowlist": [ + "my-bot1", + "(Baiduspider)/(\\d+)\\.(\\d+)" + ], + "denylist": [ + "my-bot2", + "(Twitterspider)/(\\d+)\\.(\\d+)" + ] + } + } +}' +``` + +Default returns `{"message":"Not allowed"}` when rejected. If you want to use a custom message, you can configure it in the plugin section. + +```json +"plugins": { + "ua-restriction": { + "denylist": [ + "my-bot2", + "(Twitterspider)/(\\d+)\\.(\\d+)" + ], + "message": "Do you want to do something bad?" + } +} +``` + +## Test Plugin + +Requests from normal User-Agent: + +```shell +$ curl http://127.0.0.1:9080/index.html -i +HTTP/1.1 200 OK +... +``` + +Requests with the bot User-Agent: + +```shell +$ curl http://127.0.0.1:9080/index.html --header 'User-Agent: Twitterspider/2.0' +HTTP/1.1 403 Forbidden +``` + +## Disable Plugin + +When you want to disable the `ua-restriction` 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:2379/v2/keys/apisix/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d value=' +{ + "uri": "/index.html", + "plugins": {}, + "upstream": { + "type": "roundrobin", + "nodes": { + "39.97.63.215:80": 1 + } + } +}' +``` + +The `ua-restriction` plugin has been disabled now. It works for other plugins. diff --git a/docs/zh/latest/config.json b/docs/zh/latest/config.json index 9cda9ea311b5..524777800336 100644 --- a/docs/zh/latest/config.json +++ b/docs/zh/latest/config.json @@ -71,6 +71,7 @@ "plugins/cors", "plugins/uri-blocker", "plugins/ip-restriction", + "plugins/ua-restriction", "plugins/referer-restriction", "plugins/consumer-restriction" ] diff --git a/docs/zh/latest/plugins/ua-restriction.md b/docs/zh/latest/plugins/ua-restriction.md new file mode 100644 index 000000000000..a13b80658112 --- /dev/null +++ b/docs/zh/latest/plugins/ua-restriction.md @@ -0,0 +1,125 @@ +--- +title: ua-restriction +--- + + + +## 目录 + +- [**名字**](#名字) +- [**属性**](#属性) +- [**如何启用**](#如何启用) +- [**测试插件**](#测试插件) +- [**禁用插件**](#禁用插件) + +## 名字 + +`ua-restriction` 可以通过将指定 `User-Agent` 列入白名单或黑名单的方式来限制对服务或接口的访问。 + +## 属性 + +| 参数名 | 类型 | 可选项 | 默认值 | 有效值 | 描述 | +| --------- | ------------- | ------ | ------ | ------ | -------------------------------- | +| bypass_missing | boolean | 可选 | false | | User-Agent 不存在时是否绕过检查 | +| allowlist | array[string] | 可选 | | | 加入白名单的 User-Agent | +| denylist | array[string] | 可选 | | | 加入黑名单的 User-Agent | +| message | string | 可选 | Not allowed. | 长度限制:[1, 1024] | 在未允许的 User-Agent 访问的情况下返回的信息 | + +白名单或黑名单可以同时启用,此插件对 User-Agent 的检查先后顺序依次如下:白名单、黑名单。`message`可以由用户自定义。 + +## 如何启用 + +下面是一个示例,在指定的 route 上开启了 `ua-restriction` 插件: + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/index.html", + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + }, + "plugins": { + "ua-restriction": { + "bypass_missing": true, + "allowlist": [ + "my-bot1", + "(Baiduspider)/(\\d+)\\.(\\d+)" + ], + "denylist": [ + "my-bot2", + "(Twitterspider)/(\\d+)\\.(\\d+)" + ] + } + } +}' +``` + +当未允许的 User-Agent 访问时,默认返回`{"message":"Not allowed"}`。如果你想使用自定义的`message`,可以在插件部分进行配置: + +```json +"plugins": { + "ua-restriction": { + "denylist": [ + "my-bot2", + "(Twitterspider)/(\\d+)\\.(\\d+)" + ], + "message": "Do you want to do something bad?" + } +} +``` + +## 测试插件 + +通过正常的 UA 访问: + +```shell +$ curl http://127.0.0.1:9080/index.html --header 'User-Agent: YourApp/2.0.0' +HTTP/1.1 200 OK +``` + +通过爬虫 User-Agent 访问: + +```shell +$ curl http://127.0.0.1:9080/index.html --header 'User-Agent: Twitterspider/2.0' +HTTP/1.1 403 Forbidden +``` + +## 禁用插件 + +当你想去掉 `ua-restriction` 插件的时候,很简单,在插件的配置中把对应的 json 配置删除即可,无须重启服务,即刻生效: + +```shell +$ curl http://127.0.0.1:2379/v2/keys/apisix/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d value=' +{ + "uri": "/index.html", + "plugins": {}, + "upstream": { + "type": "roundrobin", + "nodes": { + "39.97.63.215:80": 1 + } + } +}' +``` + +现在就已移除 `ua-restriction` 插件,其它插件的开启和移除也类似。 diff --git a/t/admin/plugins.t b/t/admin/plugins.t index 61553a35e343..1bc0995b4e01 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -40,7 +40,7 @@ __DATA__ --- request GET /apisix/admin/plugins/list --- response_body_like eval -qr/\["client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/ +qr/\["client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/ --- no_error_log [error] diff --git a/t/plugin/ua-restriction.t b/t/plugin/ua-restriction.t new file mode 100644 index 000000000000..77c68748edea --- /dev/null +++ b/t/plugin/ua-restriction.t @@ -0,0 +1,741 @@ +# +# 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_shuffle(); +no_root_location(); + +add_block_preprocessor(sub { + my ($block) = @_; + + if (!$block->request) { + $block->set_value("request", "GET /t"); + } + + if (!$block->no_error_log && !$block->error_log) { + $block->set_value("no_error_log", "[error]\n[alert]"); + } +}); + +run_tests; + +__DATA__ + +=== TEST 1: set allowlist, denylist, bypass_missing and user-defined message +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.ua-restriction") + local conf = { + bypass_missing = true, + allowlist = { + "my-bot1", + "my-bot2" + }, + denylist = { + "my-bot1", + "my-bot2" + }, + message = "User-Agent Forbidden", + } + local ok, err = plugin.check_schema(conf) + if not ok then + ngx.say(err) + 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"} + + + +=== TEST 2: bypass_missing not boolean +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.ua-restriction") + local conf = { + bypass_missing = "foo", + } + local ok, err = plugin.check_schema(conf) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- response_body +property "bypass_missing" validation failed: wrong type: expected boolean, got string +done + + + +=== TEST 3: allowlist not array +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.ua-restriction") + local conf = { + allowlist = "my-bot1", + } + local ok, err = plugin.check_schema(conf) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- response_body +property "allowlist" validation failed: wrong type: expected array, got string +done + + + +=== TEST 4: denylist not array +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.ua-restriction") + local conf = { + denylist = 100, + } + local ok, err = plugin.check_schema(conf) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- response_body +property "denylist" validation failed: wrong type: expected array, got number +done + + + +=== TEST 5: message not string +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.ua-restriction") + local conf = { + message = 100, + } + local ok, err = plugin.check_schema(conf) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- response_body +property "message" validation failed: wrong type: expected string, got number +done + + + +=== TEST 6: set denylist +--- 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": { + "denylist": [ + "my-bot1", + "(Baiduspider)/(\\d+)\\.(\\d+)" + ] + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 7: hit route and user-agent in denylist +--- request +GET /hello +--- more_headers +User-Agent:my-bot1 +--- error_code: 403 +--- response_body +{"message":"Not allowed"} + + + +=== TEST 8: hit route and user-agent in denylist with multiple user-agent +--- request +GET /hello +--- more_headers +User-Agent:my-bot1 +User-Agent:my-bot2 +--- error_code: 403 +--- response_body +{"message":"Not allowed"} + + + +=== TEST 9: hit route and user-agent match denylist regex +--- request +GET /hello +--- more_headers +User-Agent:Baiduspider/3.0 +--- 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 +--- request +GET /hello +--- more_headers +User-Agent:Baiduspider/3.0 +--- error_code: 200 +--- response_body +hello world + + + +=== TEST 14: hit route and user-agent not in allowlist +--- request +GET /hello +--- more_headers +User-Agent:foo/bar +--- error_code: 200 +--- response_body +hello world + + + +=== TEST 15: set config: user-agent in both allowlist and denylist +--- 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": [ + "foo/bar", + "(Baiduspider)/(\\d+)\\.(\\d+)" + ], + "denylist": [ + "foo/bar", + "(Baiduspider)/(\\d+)\\.(\\d+)" + ] + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 16: hit route and user-agent in both allowlist and denylist, pass(part 1) +--- request +GET /hello +--- more_headers +User-Agent:foo/bar +--- error_code: 200 +--- response_body +hello world + + + +=== TEST 17: hit route and user-agent in both allowlist and denylist, pass(part 2) +--- request +GET /hello +--- more_headers +User-Agent:Baiduspider/1.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) +--- request +GET /hello +--- 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) +--- request +GET /hello +--- error_code: 200 +--- 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) +--- request +GET /hello +--- error_code: 403 +--- response_body +{"message":"Not allowed"} + + + +=== TEST 24: message that do not reach the minimum range +--- 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": { + "message": "" + } + } + }]] + ) + + ngx.say(body) + } + } +--- response_body_like eval +qr/string too short, expected at least 1, got 0/ + + + +=== TEST 25: exceeds the maximum limit of message +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local json = require("toolkit.json") + + local data = { + uri = "/hello", + upstream = { + type = "roundrobin", + nodes = { + ["127.0.0.1:1980"] = 1, + } + }, + plugins = { + ["ua-restriction"] = { + denylist = { + "my-bot1", + }, + message = ("-1Aa#"):rep(205) + } + } + } + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + json.encode(data) + ) + + ngx.say(body) + } + } +--- response_body_like eval +qr/string too long, expected at most 1024, got 1025/ + + + +=== TEST 26: set custom message +--- 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": { + "denylist": [ + "(Baiduspider)/(\\d+)\\.(\\d+)" + ], + "message": "Do you want to do something bad?" + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } + +--- response_body +passed + + + +=== TEST 27: test custom message +--- request +GET /hello +--- more_headers +User-Agent:Baiduspider/1.0 +--- error_code: 403 +--- response_body +{"message":"Do you want to do something bad?"} + + + +=== TEST 28: test remove ua-restriction, add denylist(part 1) +--- config + location /enable { + 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": { + "denylist": [ + "(Baiduspider)/(\\d+)\\.(\\d+)" + ] + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /enable +--- error_code: 200 +--- response_body +passed + + + +=== TEST 29: test remove ua-restriction, fail(part 2) +--- request +GET /hello +--- more_headers +User-Agent:Baiduspider/1.0 +--- error_code: 403 +--- response_body +{"message":"Not allowed"} + + + +=== TEST 30: test remove ua-restriction, remove plugin(part 3) +--- config + location /disable { + 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": { + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /disable +--- error_code: 200 +--- response_body +passed + + + +=== TEST 31: test remove ua-restriction, check spider User-Agent(part 4) +--- request +GET /hello +--- more_headers +User-Agent:Baiduspider/1.0 +--- response_body +hello world + + + +=== TEST 32: set disable=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", + "plugins": { + "ua-restriction": { + "denylist": [ + "foo" + ], + "disable": true + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed