From 9989110f972bfb6662cb83ea92647519d91bdf74 Mon Sep 17 00:00:00 2001 From: Madhawa Gunasekara Date: Mon, 23 Oct 2023 14:25:27 +0200 Subject: [PATCH 1/5] add multi-auth plugin --- apisix/plugins/multi-auth.lua | 89 ++++++++++ conf/config-default.yaml | 1 + docs/en/latest/plugins/multi-auth.md | 140 +++++++++++++++ t/admin/plugins.t | 1 + t/debug/debug-mode.t | 1 + t/plugin/multi-auth.t | 244 +++++++++++++++++++++++++++ 6 files changed, 476 insertions(+) create mode 100644 apisix/plugins/multi-auth.lua create mode 100644 docs/en/latest/plugins/multi-auth.md create mode 100644 t/plugin/multi-auth.t diff --git a/apisix/plugins/multi-auth.lua b/apisix/plugins/multi-auth.lua new file mode 100644 index 000000000000..c7322942d62c --- /dev/null +++ b/apisix/plugins/multi-auth.lua @@ -0,0 +1,89 @@ +-- +-- 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 core = require("apisix.core") + +local schema = { + type = "object", + title = "work with route or service object", + properties = { + auth_plugins = { type = "array", minItems = 2 }, + hide_credentials = { + type = "boolean", + default = false, + } + }, + required = { "auth_plugins" }, +} + + +local plugin_name = "multi-auth" + +local _M = { + version = 0.1, + priority = 2600, + type = 'auth', + name = plugin_name, + schema = schema +} + +function _M.check_schema(conf) + local ok, err = core.schema.check(schema, conf) + if not ok then + return false, err + end + + local auth_plugins = conf.auth_plugins + for k, auth_plugin in pairs(auth_plugins) do + for key, value in pairs(auth_plugin) do + local auth = require("apisix.plugins." .. key) + if auth == nil then + return false, key .. " plugin did not found" + else + if auth.type ~= 'auth' then + return false, key .. " plugin is not supported" + end + end + end + end + + return true +end + +function _M.rewrite(conf, ctx) + local auth_plugins = conf.auth_plugins + local status_code + for k, auth_plugin in pairs(auth_plugins) do + for key, value in pairs(auth_plugin) do + local auth = require("apisix.plugins." .. key) + local auth_code, b = auth.rewrite(value, ctx) + status_code = auth_code + if auth_code == nil then + core.log.debug("Authentication is successful" .. key .. " plugin") + goto authenticated + else + core.log.warn("Authentication is failed" .. key .. " plugin, code: " .. auth_code) + end + end + end + + :: authenticated :: + if status_code ~= nil then + return 401, { message = "Authorization Failed" } + end +end + +return _M diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 4e257f4d4335..8717d1398b3f 100755 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -457,6 +457,7 @@ plugins: # plugin list (sorted by priority) - uri-blocker # priority: 2900 - request-validation # priority: 2800 - chaitin-waf # priority: 2700 + - multi-auth # priority: 2600 - openid-connect # priority: 2599 - cas-auth # priority: 2597 - authz-casbin # priority: 2560 diff --git a/docs/en/latest/plugins/multi-auth.md b/docs/en/latest/plugins/multi-auth.md new file mode 100644 index 000000000000..1dd84c43d2af --- /dev/null +++ b/docs/en/latest/plugins/multi-auth.md @@ -0,0 +1,140 @@ +--- +title: basic-auth +keywords: + - Apache APISIX + - API Gateway + - Plugin + - Multi Auth + - multi-auth +description: This document contains information about the Apache APISIX multi-auth Plugin. +--- + + + +## Description + +The `multi-auth` Plugin is used to add multiple authentication methods to a Route or a Service. Plugins with type 'auth' are supported. + +## Attributes + +For Route: + +| Name | Type | Required | Default | Description | +|-------------|-------|----------|---------|-----------------------------------------------------------------------------------------| +| auth_plugin | array | True | - | Add supporting auth plugin configuration. | + +## Enable Plugin + +To enable the Plugin, you have to create a Consumer object with multiple authentication configurations: + +```shell +curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "username": "foo", + "plugins": { + "basic-auth": { + "username": "foo", + "password": "bar" + }, + "key-auth": { + "key": "auth-one" + } + } +}' +``` + +You can also use the [APISIX Dashboard](/docs/dashboard/USER_GUIDE) to complete the operation through a web UI. + +Once you have created a Consumer object, you can then configure a Route or a Service to authenticate requests: + +```shell +curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "plugins": { + "multi-auth":{ + "auth_plugins":[ + { + "basic-auth":{ } + }, + { + "key-auth":{ + "query":"apikey", + "hide_credentials":true, + "header":"apikey" + } + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } +}' +``` + +## Example usage + +After you have configured the Plugin as mentioned above, you can make a request to the Route as shown below: + +```shell +curl -i -ufoo:bar http://127.0.0.1:9080/hello +``` + +```shell +curl http://127.0.0.2:9080/hello -H 'apikey: auth-one' -i +``` + +``` +HTTP/1.1 200 OK +... +hello, world +``` + +If the request is not authorized, an error will be thrown: + +```shell +HTTP/1.1 401 Unauthorized +... +{"message":"Authorization Failed"} +``` + +## Delete Plugin + +To remove the `multi-auth` Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect. + +```shell +curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "plugins": {}, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } +}' +``` diff --git a/t/admin/plugins.t b/t/admin/plugins.t index e7bcf09e97b4..68206bf3d76d 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -75,6 +75,7 @@ csrf uri-blocker request-validation chaitin-waf +multi-auth openid-connect cas-auth authz-casbin diff --git a/t/debug/debug-mode.t b/t/debug/debug-mode.t index 5d645e8e62ec..f2bdbb2c9a75 100644 --- a/t/debug/debug-mode.t +++ b/t/debug/debug-mode.t @@ -53,6 +53,7 @@ loaded plugin and sort by priority: 3000 name: ip-restriction loaded plugin and sort by priority: 2990 name: referer-restriction loaded plugin and sort by priority: 2900 name: uri-blocker loaded plugin and sort by priority: 2800 name: request-validation +loaded plugin and sort by priority: 2600 name: multi-auth loaded plugin and sort by priority: 2599 name: openid-connect loaded plugin and sort by priority: 2555 name: wolf-rbac loaded plugin and sort by priority: 2530 name: hmac-auth diff --git a/t/plugin/multi-auth.t b/t/plugin/multi-auth.t new file mode 100644 index 000000000000..fc4e492aa542 --- /dev/null +++ b/t/plugin/multi-auth.t @@ -0,0 +1,244 @@ +# +# 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. +# +BEGIN { + $ENV{VAULT_TOKEN} = "root"; +} + +use t::APISIX 'no_plan'; + +repeat_each(2); +no_long_string(); +no_root_location(); +no_shuffle(); +run_tests; + +__DATA__ + +=== TEST 1: add consumer with basic-auth and key-auth plugins +--- 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": "foo", + "plugins": { + "basic-auth": { + "username": "foo", + "password": "bar" + }, + "key-auth": { + "key": "auth-one" + } + } + }]] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed + + + +=== TEST 2: enable multi auth plugin using admin api +--- 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": { + "multi-auth": { + "auth_plugins": [ + { + "basic-auth": {} + }, + { + "key-auth": { + "query": "apikey", + "hide_credentials": true, + "header": "apikey" + } + }, + { + "jwt-auth": { + "cookie": "jwt", + "query": "jwt", + "hide_credentials": true, + "header": "authorization" + } + } + ] + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed + + + +=== TEST 3: verify, missing authorization +--- request +GET /hello +--- error_code: 401 +--- response_body +{"message":"Authorization Failed"} + + + +=== TEST 4: verify basic +--- request +GET /hello +--- more_headers +Authorization: Basic Zm9vOmJhcg== +--- response_body +hello world +--- error_log +find consumer foo + + + +=== TEST 5: verify key +--- request +GET /hello +--- more_headers +apikey: auth-one +--- response_body +hello world + + + +=== TEST 6: verify, invalid basic credentials +--- request +GET /hello +--- more_headers +Authorization: Basic YmFyOmJhcgo= +--- error_code: 401 +--- response_body +{"message":"Authorization Failed."} + + + +=== TEST 7: verify, invalid api key +--- request +GET /hello +--- more_headers +apikey: auth-two +--- error_code: 401 +--- response_body +{"message":"Authorization Failed."} + + + +=== TEST 8: enable multi auth plugin using admin api +--- 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": { + "multi-auth": { } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- error_code: 400 +--- response_body +{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" is required"} + + + +=== TEST 9: enable multi auth plugin using admin api +--- 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": { + "multi-auth": { + "auth_plugins": [ + { + "basic-auth": {} + } + ] + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- error_code: 400 +--- response_body +{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" validation failed: expect array to have at least 2 items"} From 31b26551ea397ada3a2afadd982eade212f7d875 Mon Sep 17 00:00:00 2001 From: Madhawa Gunasekara Date: Sun, 12 Nov 2023 19:39:55 +0100 Subject: [PATCH 2/5] fix code checks --- apisix/plugins/multi-auth.lua | 2 +- docs/en/latest/config.json | 3 ++- docs/en/latest/getting-started/key-authentication.md | 1 + docs/zh/latest/getting-started/key-authentication.md | 1 + t/admin/plugins.t | 2 +- t/plugin/multi-auth.t | 8 ++++---- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apisix/plugins/multi-auth.lua b/apisix/plugins/multi-auth.lua index c7322942d62c..82e6e594ac13 100644 --- a/apisix/plugins/multi-auth.lua +++ b/apisix/plugins/multi-auth.lua @@ -69,7 +69,7 @@ function _M.rewrite(conf, ctx) for k, auth_plugin in pairs(auth_plugins) do for key, value in pairs(auth_plugin) do local auth = require("apisix.plugins." .. key) - local auth_code, b = auth.rewrite(value, ctx) + local auth_code = auth.rewrite(value, ctx) status_code = auth_code if auth_code == nil then core.log.debug("Authentication is successful" .. key .. " plugin") diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json index e1c8391f275b..05f63bd63fed 100644 --- a/docs/en/latest/config.json +++ b/docs/en/latest/config.json @@ -111,7 +111,8 @@ "plugins/authz-casbin", "plugins/ldap-auth", "plugins/opa", - "plugins/forward-auth" + "plugins/forward-auth", + "plugins/multi-auth" ] }, { diff --git a/docs/en/latest/getting-started/key-authentication.md b/docs/en/latest/getting-started/key-authentication.md index 725bcd3527b9..f6e8a8383f0f 100644 --- a/docs/en/latest/getting-started/key-authentication.md +++ b/docs/en/latest/getting-started/key-authentication.md @@ -28,6 +28,7 @@ APISIX has a flexible plugin extension system and a number of existing plugins f - [LDAP](https://apisix.apache.org/docs/apisix/plugins/ldap-auth/) - [Open Policy Agent (OPA)](https://apisix.apache.org/docs/apisix/plugins/opa/) - [Forward Authentication](https://apisix.apache.org/docs/apisix/plugins/forward-auth/) +- [Multiple Authentications](https://apisix.apache.org/docs/apisix/plugins/multi-auth/) In this tutorial, you will create a _consumer_ with _key authentication_, and learn how to enable and disable key authentication. diff --git a/docs/zh/latest/getting-started/key-authentication.md b/docs/zh/latest/getting-started/key-authentication.md index ddcce9029db0..022f020ae909 100644 --- a/docs/zh/latest/getting-started/key-authentication.md +++ b/docs/zh/latest/getting-started/key-authentication.md @@ -28,6 +28,7 @@ APISIX 拥有灵活的插件扩展系统,目前有很多可用于用户身份 - [LDAP](https://apisix.apache.org/zh/docs/apisix/plugins/ldap-auth/) - [Open Policy Agent (OPA)](https://apisix.apache.org/zh/docs/apisix/plugins/opa/) - [Forward Authentication](https://apisix.apache.org/zh/docs/apisix/plugins/forward-auth/) +- [Multiple Authentications](https://apisix.apache.org/docs/apisix/plugins/multi-auth/) 本教程中,你将创建一个带有 _密钥验证_ 插件的 _消费者_,并学习如何启用和停用身份验证插件。 diff --git a/t/admin/plugins.t b/t/admin/plugins.t index 68206bf3d76d..e7b736fd959c 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -312,7 +312,7 @@ qr/\{"metadata_schema":\{"properties":\{"ikey":\{"minimum":0,"type":"number"\}," } } --- response_body eval -qr/\[\{"name":"wolf-rbac","priority":2555\},\{"name":"ldap-auth","priority":2540\},\{"name":"hmac-auth","priority":2530\},\{"name":"basic-auth","priority":2520\},\{"name":"jwt-auth","priority":2510\},\{"name":"key-auth","priority":2500\}\]/ +qr/\[\{"name":"multi-auth","priority":2600\},\{"name":"wolf-rbac","priority":2555\},\{"name":"ldap-auth","priority":2540\},\{"name":"hmac-auth","priority":2530\},\{"name":"basic-auth","priority":2520\},\{"name":"jwt-auth","priority":2510\},\{"name":"key-auth","priority":2500\}\]/ diff --git a/t/plugin/multi-auth.t b/t/plugin/multi-auth.t index fc4e492aa542..72360f5d1bc1 100644 --- a/t/plugin/multi-auth.t +++ b/t/plugin/multi-auth.t @@ -154,7 +154,7 @@ GET /hello Authorization: Basic YmFyOmJhcgo= --- error_code: 401 --- response_body -{"message":"Authorization Failed."} +{"message":"Authorization Failed"} @@ -165,7 +165,7 @@ GET /hello apikey: auth-two --- error_code: 401 --- response_body -{"message":"Authorization Failed."} +{"message":"Authorization Failed"} @@ -200,7 +200,7 @@ apikey: auth-two GET /t --- error_code: 400 --- response_body -{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" is required"} +{"error_msg":"failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" is required"} @@ -241,4 +241,4 @@ GET /t GET /t --- error_code: 400 --- response_body -{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" validation failed: expect array to have at least 2 items"} +{"error_msg":"failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" validation failed: expect array to have at least 2 items"} From 0a1d23c57953cdc71e1305ca58152c7da1e07ec7 Mon Sep 17 00:00:00 2001 From: Madhawa Gunasekara Date: Sun, 12 Nov 2023 20:58:46 +0100 Subject: [PATCH 3/5] fix test failures --- apisix/plugins/multi-auth.lua | 8 +++----- docs/en/latest/plugins/multi-auth.md | 6 +++--- t/plugin/multi-auth.t | 8 ++++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/apisix/plugins/multi-auth.lua b/apisix/plugins/multi-auth.lua index 82e6e594ac13..e9a7b6b7c2fe 100644 --- a/apisix/plugins/multi-auth.lua +++ b/apisix/plugins/multi-auth.lua @@ -15,16 +15,14 @@ -- limitations under the License. -- local core = require("apisix.core") +local require = require +local pairs = pairs local schema = { type = "object", title = "work with route or service object", properties = { - auth_plugins = { type = "array", minItems = 2 }, - hide_credentials = { - type = "boolean", - default = false, - } + auth_plugins = { type = "array", minItems = 2 } }, required = { "auth_plugins" }, } diff --git a/docs/en/latest/plugins/multi-auth.md b/docs/en/latest/plugins/multi-auth.md index 1dd84c43d2af..7ac218198835 100644 --- a/docs/en/latest/plugins/multi-auth.md +++ b/docs/en/latest/plugins/multi-auth.md @@ -36,9 +36,9 @@ The `multi-auth` Plugin is used to add multiple authentication methods to a Rout For Route: -| Name | Type | Required | Default | Description | -|-------------|-------|----------|---------|-----------------------------------------------------------------------------------------| -| auth_plugin | array | True | - | Add supporting auth plugin configuration. | +| Name | Type | Required | Default | Description | +|--------------|-------|----------|---------|--------------------------------------------| +| auth_plugins | array | True | - | Add supporting auth plugins configuration. | ## Enable Plugin diff --git a/t/plugin/multi-auth.t b/t/plugin/multi-auth.t index 72360f5d1bc1..b128d3f4142e 100644 --- a/t/plugin/multi-auth.t +++ b/t/plugin/multi-auth.t @@ -199,8 +199,8 @@ apikey: auth-two --- request GET /t --- error_code: 400 ---- response_body -{"error_msg":"failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" is required"} +--- response_body_like eval +qr/\{"error_msg":"failed to check the configuration of plugin multi-auth err: property \\"auth_plugins\\" is required"\}/ @@ -240,5 +240,5 @@ GET /t --- request GET /t --- error_code: 400 ---- response_body -{"error_msg":"failed to check the configuration of plugin multi-auth err: property \"auth_plugins\" validation failed: expect array to have at least 2 items"} +--- response_body_like eval +qr/\{"error_msg":"failed to check the configuration of plugin multi-auth err: property \\"auth_plugins\\" validation failed: expect array to have at least 2 items"\}/ From 264ff152c6f58f5ab4d1d98961899f9b30aee997 Mon Sep 17 00:00:00 2001 From: Madhawa Gunasekara Date: Tue, 14 Nov 2023 16:28:10 +0100 Subject: [PATCH 4/5] add test cases --- apisix/plugins/multi-auth.lua | 20 +-- docs/en/latest/plugins/multi-auth.md | 14 ++- t/plugin/multi-auth.t | 182 ++++++++++++++++++++++++++- 3 files changed, 198 insertions(+), 18 deletions(-) diff --git a/apisix/plugins/multi-auth.lua b/apisix/plugins/multi-auth.lua index e9a7b6b7c2fe..779dcd6bc3f1 100644 --- a/apisix/plugins/multi-auth.lua +++ b/apisix/plugins/multi-auth.lua @@ -46,13 +46,13 @@ function _M.check_schema(conf) local auth_plugins = conf.auth_plugins for k, auth_plugin in pairs(auth_plugins) do - for key, value in pairs(auth_plugin) do - local auth = require("apisix.plugins." .. key) + for auth_plugin_name, auth_plugin_conf in pairs(auth_plugin) do + local auth = require("apisix.plugins." .. auth_plugin_name) if auth == nil then - return false, key .. " plugin did not found" + return false, auth_plugin_name .. " plugin did not found" else if auth.type ~= 'auth' then - return false, key .. " plugin is not supported" + return false, auth_plugin_name .. " plugin is not supported" end end end @@ -65,15 +65,17 @@ function _M.rewrite(conf, ctx) local auth_plugins = conf.auth_plugins local status_code for k, auth_plugin in pairs(auth_plugins) do - for key, value in pairs(auth_plugin) do - local auth = require("apisix.plugins." .. key) - local auth_code = auth.rewrite(value, ctx) + for auth_plugin_name, auth_plugin_conf in pairs(auth_plugin) do + local auth = require("apisix.plugins." .. auth_plugin_name) + -- returns 401 HTTP status code if authentication failed, otherwise nothing returns. + local auth_code = auth.rewrite(auth_plugin_conf, ctx) status_code = auth_code if auth_code == nil then - core.log.debug("Authentication is successful" .. key .. " plugin") + core.log.debug("Authentication is successful" .. auth_plugin_name .. " plugin") goto authenticated else - core.log.warn("Authentication is failed" .. key .. " plugin, code: " .. auth_code) + core.log.warn("Authentication is failed" .. auth_plugin_name .. " plugin, code: " + .. auth_code) end end end diff --git a/docs/en/latest/plugins/multi-auth.md b/docs/en/latest/plugins/multi-auth.md index 7ac218198835..703fac19ae2f 100644 --- a/docs/en/latest/plugins/multi-auth.md +++ b/docs/en/latest/plugins/multi-auth.md @@ -1,5 +1,5 @@ --- -title: basic-auth +title: multi-auth keywords: - Apache APISIX - API Gateway @@ -30,15 +30,15 @@ description: This document contains information about the Apache APISIX multi-au ## Description -The `multi-auth` Plugin is used to add multiple authentication methods to a Route or a Service. Plugins with type 'auth' are supported. +The `multi-auth` Plugin is used to add multiple authentication methods to a Route or a Service. It supports plugins of type 'auth'. You can combine different authentication methods using "or" relationship with `multi-auth` plugin. If you want to use multiple methods in an "and" relationship, apply specific authentication plugins directly to the route or service. ## Attributes For Route: -| Name | Type | Required | Default | Description | -|--------------|-------|----------|---------|--------------------------------------------| -| auth_plugins | array | True | - | Add supporting auth plugins configuration. | +| Name | Type | Required | Default | Description | +|--------------|-------|----------|---------|-----------------------------------------------------------------------| +| auth_plugins | array | True | - | Add supporting auth plugins configuration. expects at least 2 plugins | ## Enable Plugin @@ -98,10 +98,14 @@ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 After you have configured the Plugin as mentioned above, you can make a request to the Route as shown below: +request with basic-auth + ```shell curl -i -ufoo:bar http://127.0.0.1:9080/hello ``` +request with key-auth + ```shell curl http://127.0.0.2:9080/hello -H 'apikey: auth-one' -i ``` diff --git a/t/plugin/multi-auth.t b/t/plugin/multi-auth.t index b128d3f4142e..c1e0be54d7b7 100644 --- a/t/plugin/multi-auth.t +++ b/t/plugin/multi-auth.t @@ -125,7 +125,7 @@ GET /hello -=== TEST 4: verify basic +=== TEST 4: verify basic-auth --- request GET /hello --- more_headers @@ -137,7 +137,7 @@ find consumer foo -=== TEST 5: verify key +=== TEST 5: verify key-auth --- request GET /hello --- more_headers @@ -169,7 +169,7 @@ apikey: auth-two -=== TEST 8: enable multi auth plugin using admin api +=== TEST 8: enable multi auth plugin using admin api, without any auth_plugins configuration --- config location /t { content_by_lua_block { @@ -204,7 +204,7 @@ qr/\{"error_msg":"failed to check the configuration of plugin multi-auth err: pr -=== TEST 9: enable multi auth plugin using admin api +=== TEST 9: enable multi auth plugin using admin api, with auth_plugins configuration but with one authorization plugin --- config location /t { content_by_lua_block { @@ -242,3 +242,177 @@ GET /t --- error_code: 400 --- response_body_like eval qr/\{"error_msg":"failed to check the configuration of plugin multi-auth err: property \\"auth_plugins\\" validation failed: expect array to have at least 2 items"\}/ + + + +=== TEST 10: create public API route (jwt-auth sign) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + "plugins": { + "public-api": {} + }, + "uri": "/apisix/plugin/jwt/sign" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed + + + +=== TEST 11: add consumer with username and jwt-auth plugins +--- 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": { + "jwt-auth": { + "key": "user-key", + "secret": "my-secret-key" + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed + + + +=== TEST 12: sign / verify jwt-auth +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', + ngx.HTTP_GET + ) + + if code > 200 then + ngx.status = code + ngx.say(err) + return + end + + local code, _, res = t('/hello?jwt=' .. sign, + ngx.HTTP_GET + ) + + ngx.status = code + ngx.print(res) + } + } +--- request +GET /t +--- response_body +hello world + + + +=== TEST 13: verify multi-auth with plugin config will cause the conf_version change +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + + local code, err = t('/apisix/admin/plugin_configs/1', + ngx.HTTP_PUT, + [[{ + "desc": "Multiple Authentication", + "plugins": { + "multi-auth": { + "auth_plugins": [ + { + "basic-auth": {} + }, + { + "key-auth": { + "query": "apikey", + "hide_credentials": true, + "header": "apikey" + } + }, + { + "jwt-auth": { + "cookie": "jwt", + "query": "jwt", + "hide_credentials": true, + "header": "authorization" + } + } + ] + } + } + }]] + ) + if code > 300 then + ngx.log(ngx.ERR, err) + return + end + + local code, err = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "uri": "/hello", + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "plugin_config_id": 1 + }]] + ) + if code > 300 then + ngx.log(ngx.ERR, err) + return + end + ngx.sleep(0.1) + + local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', + ngx.HTTP_GET + ) + + if code > 200 then + ngx.status = code + ngx.say(err) + return + end + + local code, _, res = t('/hello?jwt=' .. sign, + ngx.HTTP_GET + ) + + ngx.status = code + ngx.print(res) + } + } +--- request +GET /t +--- response_body +hello world From 6ff04c1c920602827f382988f468fa95572757b1 Mon Sep 17 00:00:00 2001 From: Madhawa Gunasekara Date: Wed, 15 Nov 2023 16:22:17 +0100 Subject: [PATCH 5/5] fix review comments --- apisix/plugins/multi-auth.lua | 6 +++--- t/plugin/multi-auth.t | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/apisix/plugins/multi-auth.lua b/apisix/plugins/multi-auth.lua index 779dcd6bc3f1..5c6a825791d7 100644 --- a/apisix/plugins/multi-auth.lua +++ b/apisix/plugins/multi-auth.lua @@ -67,14 +67,14 @@ function _M.rewrite(conf, ctx) for k, auth_plugin in pairs(auth_plugins) do for auth_plugin_name, auth_plugin_conf in pairs(auth_plugin) do local auth = require("apisix.plugins." .. auth_plugin_name) - -- returns 401 HTTP status code if authentication failed, otherwise nothing returns. + -- returns 401 HTTP status code if authentication failed, otherwise returns nothing. local auth_code = auth.rewrite(auth_plugin_conf, ctx) status_code = auth_code if auth_code == nil then - core.log.debug("Authentication is successful" .. auth_plugin_name .. " plugin") + core.log.debug(auth_plugin_name .. " succeed to authenticate the request") goto authenticated else - core.log.warn("Authentication is failed" .. auth_plugin_name .. " plugin, code: " + core.log.debug(auth_plugin_name .. " failed to authenticate the request, code: " .. auth_code) end end diff --git a/t/plugin/multi-auth.t b/t/plugin/multi-auth.t index c1e0be54d7b7..78ec19481b4a 100644 --- a/t/plugin/multi-auth.t +++ b/t/plugin/multi-auth.t @@ -14,10 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -BEGIN { - $ENV{VAULT_TOKEN} = "root"; -} - use t::APISIX 'no_plan'; repeat_each(2);