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/apisix.git
The following commit(s) were added to refs/heads/master by this push: new e94a5b3 feature: `consumer` provides access to a collection of `service` (#2241) e94a5b3 is described below commit e94a5b3f584024744c7c602984f70fedd37a9f7e Author: Firstsawyou <52862365+firstsaw...@users.noreply.github.com> AuthorDate: Sat Sep 19 18:21:21 2020 +0800 feature: `consumer` provides access to a collection of `service` (#2241) * test: add more test cases. Co-authored-by: Yuansheng Wang <membp...@gmail.com> --- apisix/init.lua | 2 + apisix/plugins/consumer-restriction.lua | 33 +- t/plugin/consumer-restriction.t | 711 +++++++++++++++++++++++++++++++- 3 files changed, 735 insertions(+), 11 deletions(-) diff --git a/apisix/init.lua b/apisix/init.lua index 63275c1..9f8b38b 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -403,11 +403,13 @@ function _M.http_access_phase() api_ctx.conf_type = "route&service" api_ctx.conf_version = route.modifiedIndex .. "&" .. service.modifiedIndex api_ctx.conf_id = route.value.id .. "&" .. service.value.id + api_ctx.service_id = service.value.id else api_ctx.conf_type = "route" api_ctx.conf_version = route.modifiedIndex api_ctx.conf_id = route.value.id end + api_ctx.route_id = route.value.id local enable_websocket local up_id = route.value.upstream_id diff --git a/apisix/plugins/consumer-restriction.lua b/apisix/plugins/consumer-restriction.lua index 912e212..f80e096 100644 --- a/apisix/plugins/consumer-restriction.lua +++ b/apisix/plugins/consumer-restriction.lua @@ -20,6 +20,11 @@ local core = require("apisix.core") local schema = { type = "object", properties = { + type = { + type = "string", + enum = {"consumer_name", "service_id"}, + default = "consumer_name" + }, whitelist = { type = "array", items = {type = "string"}, @@ -29,7 +34,8 @@ local schema = { type = "array", items = {type = "string"}, minItems = 1 - } + }, + rejected_code = {type = "integer", minimum = 200, default = 403} }, oneOf = { {required = {"whitelist"}}, @@ -37,10 +43,8 @@ local schema = { } } - local plugin_name = "consumer-restriction" - local _M = { version = 0.1, priority = 2400, @@ -48,6 +52,15 @@ local _M = { schema = schema, } +local fetch_val_funcs = { + ["service_id"] = function(ctx) + return ctx.service_id + end, + ["consumer_name"] = function(ctx) + return ctx.consumer_id + end +} + local function is_include(value, tab) for k,v in ipairs(tab) do if v == value then @@ -57,6 +70,7 @@ local function is_include(value, tab) return false end + function _M.check_schema(conf) local ok, err = core.schema.check(schema, conf) @@ -67,26 +81,29 @@ function _M.check_schema(conf) return true end + function _M.access(conf, ctx) - if not ctx.consumer then - return 401, { message = "Missing authentication or identity verification." } + local value = fetch_val_funcs[conf.type](ctx) + if not value then + return 401, { message = "Missing authentication or identity verification."} end + core.log.info("value: ", value) local block = false if conf.blacklist and #conf.blacklist > 0 then - if is_include(ctx.consumer.username, conf.blacklist) then + if is_include(value, conf.blacklist) then block = true end end if conf.whitelist and #conf.whitelist > 0 then - if not is_include(ctx.consumer.username, conf.whitelist) then + if not is_include(value, conf.whitelist) then block = true end end if block then - return 403, { message = "The consumer is not allowed" } + return conf.rejected_code, { message = "The " .. conf.type .. " is forbidden." } end end diff --git a/t/plugin/consumer-restriction.t b/t/plugin/consumer-restriction.t index 57bbed3..69708ea 100644 --- a/t/plugin/consumer-restriction.t +++ b/t/plugin/consumer-restriction.t @@ -47,7 +47,7 @@ __DATA__ --- request GET /t --- response_body -{"whitelist":["jack1","jack2"]} +{"rejected_code":403,"type":"consumer_name","whitelist":["jack1","jack2"]} --- no_error_log [error] @@ -237,7 +237,7 @@ GET /hello Authorization: Basic amFjazIwMjA6MTIzNDU2 --- error_code: 403 --- response_body -{"message":"The consumer is not allowed"} +{"message":"The consumer_name is forbidden."} --- no_error_log [error] @@ -302,7 +302,7 @@ GET /hello Authorization: Basic amFjazIwMTk6MTIzNDU2 --- error_code: 403 --- response_body -{"message":"The consumer is not allowed"} +{"message":"The consumer_name is forbidden."} --- no_error_log [error] @@ -540,3 +540,708 @@ GET /hello hello world --- no_error_log [error] + + + +=== TEST 25: create service (id:1) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/services/1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "desc": "new service 001" + }]], + [[{ + "node": { + "value": { + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "desc": "new service 001" + }, + "key": "/apisix/services/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 26: add consumer with plugin hmac-auth and consumer-restriction, and set whitelist +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "jack", + "plugins": { + "hmac-auth": { + "access_key": "my-access-key", + "secret_key": "my-secret-key" + }, + "consumer-restriction": { + "type": "service_id", + "whitelist": [ "1" ], + "rejected_code": 401 + } + } + }]], + [[{ + "node": { + "value": { + "username": "jack", + "plugins": { + "hmac-auth": { + "access_key": "my-access-key", + "secret_key": "my-secret-key", + "algorithm": "hmac-sha256", + "clock_skew": 300 + }, + "consumer-restriction": { + "type": "service_id", + "whitelist": [ "1" ], + "rejected_code": 401 + } + } + } + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 27: Route binding `hmac-auth` plug-in and whitelist `service_id` +--- 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, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 1, + "uri": "/hello", + "plugins": { + "hmac-auth": {} + } + + }]], + [[{ + "node": { + "value": { + "methods": [ + "GET" + ], + "uri": "/hello", + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 1, + "plugins": { + "hmac-auth": {} + } + }, + "key": "/apisix/routes/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 28: verify: valid whitelist `service_id` +--- config +location /t { + content_by_lua_block { + local ngx_time = ngx.time + local core = require("apisix.core") + local t = require("lib.test_admin") + local hmac = require("resty.hmac") + local ngx_encode_base64 = ngx.encode_base64 + + local secret_key = "my-secret-key" + local timestamp = ngx_time() + local access_key = "my-access-key" + local custom_header_a = "asld$%dfasf" + local custom_header_b = "23879fmsldfk" + + local signing_string = "GET" .. "/hello" .. "" .. + access_key .. timestamp .. custom_header_a .. custom_header_b + + local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string) + core.log.info("signature:", ngx_encode_base64(signature)) + local headers = {} + headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature) + headers["X-HMAC-ALGORITHM"] = "hmac-sha256" + headers["X-HMAC-TIMESTAMP"] = timestamp + headers["X-HMAC-ACCESS-KEY"] = access_key + headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b" + headers["x-custom-header-a"] = custom_header_a + headers["x-custom-header-b"] = custom_header_b + + local code, body = t.test('/hello', + ngx.HTTP_GET, + "", + nil, + headers + ) + + ngx.status = code + ngx.say(body) + } +} +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 29: create service (id:2) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/services/2', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "desc": "new service 002" + }]], + [[{ + "node": { + "value": { + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "desc": "new service 002" + }, + "key": "/apisix/services/2" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 30: Route binding `hmac-auth` plug-in and invalid whitelist `service_id` +--- 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, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 2, + "uri": "/hello", + "plugins": { + "hmac-auth": {} + } + + }]], + [[{ + "node": { + "value": { + "methods": [ + "GET" + ], + "uri": "/hello", + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 2, + "plugins": { + "hmac-auth": {} + } + }, + "key": "/apisix/routes/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 31: verify: invalid whitelist `service_id` +--- config +location /t { + content_by_lua_block { + local ngx_time = ngx.time + local core = require("apisix.core") + local t = require("lib.test_admin") + local hmac = require("resty.hmac") + local ngx_encode_base64 = ngx.encode_base64 + + local secret_key = "my-secret-key" + local timestamp = ngx_time() + local access_key = "my-access-key" + local custom_header_a = "asld$%dfasf" + local custom_header_b = "23879fmsldfk" + + local signing_string = "GET" .. "/hello" .. "" .. + access_key .. timestamp .. custom_header_a .. custom_header_b + + local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string) + core.log.info("signature:", ngx_encode_base64(signature)) + local headers = {} + headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature) + headers["X-HMAC-ALGORITHM"] = "hmac-sha256" + headers["X-HMAC-TIMESTAMP"] = timestamp + headers["X-HMAC-ACCESS-KEY"] = access_key + headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b" + headers["x-custom-header-a"] = custom_header_a + headers["x-custom-header-b"] = custom_header_b + + local code, body = t.test('/hello', + ngx.HTTP_GET, + "", + nil, + headers + ) + if code >= 300 then + ngx.status = code + end + + ngx.say(body) + } +} +--- request +GET /t +--- error_code: 401 +--- response_body eval +qr/\{"message":"The service_id is forbidden."\}/ +--- no_error_log +[error] + + + +=== TEST 32: add consumer with plugin hmac-auth and consumer-restriction, and set blacklist +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "jack", + "plugins": { + "hmac-auth": { + "access_key": "my-access-key", + "secret_key": "my-secret-key" + }, + "consumer-restriction": { + "type": "service_id", + "blacklist": [ "1" ], + "rejected_code": 401 + } + } + }]], + [[{ + "node": { + "value": { + "username": "jack", + "plugins": { + "hmac-auth": { + "access_key": "my-access-key", + "secret_key": "my-secret-key", + "algorithm": "hmac-sha256", + "clock_skew": 300 + }, + "consumer-restriction": { + "type": "service_id", + "blacklist": [ "1" ], + "rejected_code": 401 + } + } + } + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 33: Route binding `hmac-auth` plug-in and blacklist `service_id` +--- 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, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 1, + "uri": "/hello", + "plugins": { + "hmac-auth": {} + } + + }]], + [[{ + "node": { + "value": { + "methods": [ + "GET" + ], + "uri": "/hello", + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 1, + "plugins": { + "hmac-auth": {} + } + }, + "key": "/apisix/routes/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 34: verify: valid blacklist `service_id` +--- config +location /t { + content_by_lua_block { + local ngx_time = ngx.time + local core = require("apisix.core") + local t = require("lib.test_admin") + local hmac = require("resty.hmac") + local ngx_encode_base64 = ngx.encode_base64 + + local secret_key = "my-secret-key" + local timestamp = ngx_time() + local access_key = "my-access-key" + local custom_header_a = "asld$%dfasf" + local custom_header_b = "23879fmsldfk" + + local signing_string = "GET" .. "/hello" .. "" .. + access_key .. timestamp .. custom_header_a .. custom_header_b + + local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string) + core.log.info("signature:", ngx_encode_base64(signature)) + local headers = {} + headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature) + headers["X-HMAC-ALGORITHM"] = "hmac-sha256" + headers["X-HMAC-TIMESTAMP"] = timestamp + headers["X-HMAC-ACCESS-KEY"] = access_key + headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b" + headers["x-custom-header-a"] = custom_header_a + headers["x-custom-header-b"] = custom_header_b + + local code, body = t.test('/hello', + ngx.HTTP_GET, + "", + nil, + headers + ) + + ngx.status = code + ngx.say(body) + } +} +--- request +GET /t +--- error_code: 401 +--- response_body eval +qr/\{"message":"The service_id is forbidden."\}/ +--- no_error_log +[error] + + +=== TEST 35: Route binding `hmac-auth` plug-in and invalid blacklist `service_id` +--- 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, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 2, + "uri": "/hello", + "plugins": { + "hmac-auth": {} + } + + }]], + [[{ + "node": { + "value": { + "methods": [ + "GET" + ], + "uri": "/hello", + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "service_id": 2, + "plugins": { + "hmac-auth": {} + } + }, + "key": "/apisix/routes/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 36: verify: invalid blacklist `service_id` +--- config +location /t { + content_by_lua_block { + local ngx_time = ngx.time + local core = require("apisix.core") + local t = require("lib.test_admin") + local hmac = require("resty.hmac") + local ngx_encode_base64 = ngx.encode_base64 + + local secret_key = "my-secret-key" + local timestamp = ngx_time() + local access_key = "my-access-key" + local custom_header_a = "asld$%dfasf" + local custom_header_b = "23879fmsldfk" + + local signing_string = "GET" .. "/hello" .. "" .. + access_key .. timestamp .. custom_header_a .. custom_header_b + + local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string) + core.log.info("signature:", ngx_encode_base64(signature)) + local headers = {} + headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature) + headers["X-HMAC-ALGORITHM"] = "hmac-sha256" + headers["X-HMAC-TIMESTAMP"] = timestamp + headers["X-HMAC-ACCESS-KEY"] = access_key + headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b" + headers["x-custom-header-a"] = custom_header_a + headers["x-custom-header-b"] = custom_header_b + + local code, body = t.test('/hello', + ngx.HTTP_GET, + "", + nil, + headers + ) + + ngx.status = code + ngx.say(body) + } +} +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 37: delete: route (id: 1) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t( '/apisix/admin/routes/1', ngx.HTTP_DELETE ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 38: delete: `service_id` is 1 +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t( '/apisix/admin/services/1', ngx.HTTP_DELETE ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 39: delete: `service_id` is 2 +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t( '/apisix/admin/services/2', ngx.HTTP_DELETE ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error]