blob: d00aae131129e9a8bbb4618da4aaf0e3e69a7ca9 [file]
#
# 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';
no_long_string();
no_root_location();
add_block_preprocessor(sub {
my ($block) = @_;
if (! $block->request) {
$block->set_value("request", "GET /t");
if (!$block->response_body) {
$block->set_value("response_body", "passed\n");
}
}
});
run_tests;
__DATA__
=== TEST 1: mask query
--- 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": {
"data-mask": {
"request": [
{
"action": "remove",
"name": "password",
"type": "query"
},
{
"action": "replace",
"name": "token",
"type": "query",
"value": "*****"
},
{
"action": "regex",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "query",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"path": "mask-query.log.1"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 2: verify
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello?password=abc&token=xyz&card=1234-1234-1234-1234", ngx.HTTP_GET)
local fd, err = io.open("mask-query.log.1", "r")
if not fd then
core.log.error("failed to open file: ", err)
return
end
local line = fd:read()
local log = core.json.decode(line)
if log.request.querystring.password then
ngx.say("password arg mask failed: " .. log.request.querystring.password)
return
end
if log.request.querystring.token ~= "*****" then
ngx.say("token arg mask failed: " .. log.request.querystring.token)
return
end
if log.request.querystring.card ~= "1234-****-****-1234" then
ngx.say("card arg mask failed: " .. log.request.querystring.card)
return
end
if log.request.uri ~= "/hello?token=*****&card=1234-****-****-1234" and
log.request.uri ~= "/hello?card=1234-****-****-1234&token=*****" then
ngx.say("uri mask failed: " .. log.request.uri)
return
end
os.remove("mask-query.log.1")
ngx.say("success")
}
}
--- response_body
success
=== TEST 3: mask header
--- 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": {
"data-mask": {
"request": [
{
"action": "remove",
"name": "password",
"type": "header"
},
{
"action": "replace",
"name": "token",
"type": "header",
"value": "*****"
},
{
"action": "regex",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "header",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"path": "mask-header.log.2"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 4: verify
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local headers = {}
headers["password"] = "abc"
headers["token"] = "xyz"
headers["card"] = "1234-1234-1234-1234"
local code = t("/hello", ngx.HTTP_GET, "", nil, headers)
local fd, err = io.open("mask-header.log.2", "r")
if not fd then
core.log.error("failed to open file: ", err)
return
end
local line = fd:read()
local log = core.json.decode(line)
if log.request.headers.password then
ngx.say("password header mask failed: " .. log.request.headers.password)
return
end
if log.request.headers.token ~= "*****" then
ngx.say("token header mask failed: " .. log.request.headers.token)
return
end
if log.request.headers.card ~= "1234-****-****-1234" then
ngx.say("card header mask failed: " .. log.request.headers.card)
return
end
os.remove("mask-header.log.2")
ngx.say("success")
}
}
--- response_body
success
=== TEST 5: mask urlencoded body
--- 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": {
"data-mask": {
"request": [
{
"action": "remove",
"body_format": "urlencoded",
"name": "password",
"type": "body"
},
{
"action": "replace",
"body_format": "urlencoded",
"name": "token",
"type": "body",
"value": "*****"
},
{
"action": "regex",
"body_format": "urlencoded",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "body",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"include_req_body": true,
"path": "mask-urlencoded-body.log"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 6: verify
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello", ngx.HTTP_POST, "password=abc&token=xyz&card=1234-1234-1234-1234")
local fd, err = io.open("mask-urlencoded-body.log", "r")
if not fd then
core.log.error("failed to open file: ", err)
return
end
local line = fd:read()
local log = core.json.decode(line)
if log.request.body ~= "token=*****&card=1234-****-****-1234" and
log.request.body ~= "card=1234-****-****-1234&token=*****" then
ngx.say("urlencoded body mask failed: " .. log.request.body)
return
end
os.remove("mask-urlencoded-body.log")
ngx.say("success")
}
}
--- response_body
success
=== TEST 7: mask json body
--- 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": {
"data-mask": {
"request": [
{
"action": "remove",
"body_format": "json",
"name": "$.password",
"type": "body"
},
{
"action": "replace",
"body_format": "json",
"name": "users[*].token",
"type": "body",
"value": "*****"
},
{
"action": "regex",
"body_format": "json",
"name": "$.users[*].credit.card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "body",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"include_req_body": true,
"path": "mask-json-body.log"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 8: verify
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello",
ngx.HTTP_POST,
[[{
"password": "abc",
"users": [
{
"token": "xyz",
"credit": {
"card": "1234-1234-1234-1234"
}
},
{
"token": "xyz",
"credit": {
"card": "1234-1234-1234-1234"
}
}
]
}]]
)
local fd, err = io.open("mask-json-body.log", "r")
if not fd then
core.log.error("failed to open file: ", err)
return
end
local line = fd:read()
local log = core.json.decode(line)
local body = core.json.decode(log.request.body)
if body.password then
ngx.say("$.password mask failed: " .. body.password)
return
end
for _, user in ipairs(body.users) do
if user.token ~= "*****" then
ngx.say("$.users[*].token mask failed: " .. user.token)
return
end
if user.credit.card ~= "1234-****-****-1234" then
ngx.say("$.users[*].credit.card mask failed: " .. user.credit.card)
return
end
end
os.remove("mask-json-body.log")
ngx.say("success")
}
}
--- response_body
success
=== TEST 9: plugin within global rule should not throw error for missing body.
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"data-mask": {
"request": [
{
"action": "remove",
"name": "password",
"type": "query"
},
{
"action": "replace",
"name": "token",
"type": "query",
"value": "*****"
},
{
"action": "regex",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "query",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"path": "mask-query.log.4"
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 10: verify
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/random", ngx.HTTP_POST, "password=abc&token=xyz&card=1234-1234-1234-1234")
ngx.say("code: ", code)
}
}
--- response_body
code: 404
--- no_error_log
no request body found
=== TEST 11: create plugin with default value for `max_req_post_args`
--- 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": {
"data-mask": {
"request": [
{
"action": "regex",
"body_format": "urlencoded",
"name": "arg100",
"regex": "(\\d+)$",
"type": "body",
"value": "$1"
}
]
},
"file-logger": {
"include_req_body": true,
"path": "mask-urlencoded-body.log"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 12: verify default value for `max_req_post_args`
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local url_encoded = "arg1=1"
for i = 2, 110, 1 do
url_encoded = url_encoded .. "&arg" .. i .. "=" .. i
end
local code = t("/hello", ngx.HTTP_POST, url_encoded)
local fd, err = io.open("mask-urlencoded-body.log", "r")
if not fd then
core.log.error("failed to open file: ", err)
return
end
local line = fd:read()
local log = core.json.decode(line)
local match100, err = ngx.re.match(log.request.body, "arg100=100")
local match101, err = ngx.re.match(log.request.body, "arg101=101")
os.remove("mask-urlencoded-body.log")
if match100 and not match101 then
ngx.say("success")
return
end
ngx.say("failed: match100=" .. tostring(match100) .. ", match101=" .. tostring(match101))
}
}
--- response_body
success
=== TEST 13: create plugin with custom `max_req_post_args` value
--- 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": {
"data-mask": {
"request": [
{
"action": "regex",
"body_format": "urlencoded",
"name": "arg10",
"regex": "(\\d+)$",
"type": "body",
"value": "$1"
}
],
"max_req_post_args": 10
},
"file-logger": {
"include_req_body": true,
"path": "mask-urlencoded-body.log"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 14: verify number of args
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local url_encoded = "arg1=1"
for i = 2, 110, 1 do
url_encoded = url_encoded .. "&arg" .. i .. "=" .. i
end
local code = t("/hello", ngx.HTTP_POST, url_encoded)
local fd, err = io.open("mask-urlencoded-body.log", "r")
if not fd then
core.log.error("failed to open file: ", err)
return
end
local line = fd:read()
local log = core.json.decode(line)
local match10, err = ngx.re.match(log.request.body, "arg10=10")
local match11, err = ngx.re.match(log.request.body, "arg11=11")
os.remove("mask-urlencoded-body.log")
if match10 and not match11 then
ngx.say("success")
return
end
ngx.say("failed: match10=" .. tostring(match10) .. ", match11=" .. tostring(match11))
}
}
--- response_body
success
=== TEST 15: create route for access log masking test
--- 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": {
"data-mask": {
"request": [
{
"action": "remove",
"name": "password",
"type": "query"
},
{
"action": "replace",
"name": "token",
"type": "query",
"value": "*****"
}
]
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 16: verify access log masks sensitive query parameters
--- extra_yaml_config
nginx_config:
http:
access_log_format: main '$request_line';
--- request
GET /hello?password=secret&token=mytoken
--- access_log eval
qr/GET \/hello\?token=\*\*\*\*\* HTTP\/\d+\.\d+/