| # |
| # 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 |