Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apisix/plugins/basic-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ local core = require("apisix.core")
local ngx = ngx
local ngx_re = require("ngx.re")
local consumer = require("apisix.consumer")
local auth_utils = require("apisix.utils.auth")

local lrucache = core.lrucache.new({
ttl = 300, count = 512
})
Expand Down Expand Up @@ -132,6 +134,9 @@ function _M.rewrite(conf, ctx)

local username, password, err = extract_auth_header(auth_header)
if err then
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.warn(err)
return 401, { message = "Invalid authorization in request" }
end
Expand Down
15 changes: 12 additions & 3 deletions apisix/plugins/hmac-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ local ngx_encode_base64 = ngx.encode_base64
local plugin_name = "hmac-auth"
local ALLOWED_ALGORITHMS = {"hmac-sha1", "hmac-sha256", "hmac-sha512"}
local resty_sha256 = require("resty.sha256")
local auth_utils = require("apisix.utils.auth")

local schema = {
type = "object",
Expand Down Expand Up @@ -324,16 +325,24 @@ end
function _M.rewrite(conf, ctx)
local params,err = retrieve_hmac_fields(ctx)
if err then
core.log.warn("client request can't be validated: ", err)
return 401, {message = "client request can't be validated: " .. err}
err = "client request can't be validated: " .. err
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.warn(err)
return 401, {message = err}
end

if conf.hide_credentials then
core.request.set_header("Authorization", nil)
end
local validated_consumer, err = validate(ctx, conf, params)
if not validated_consumer then
core.log.warn("client request can't be validated: ", err or "Invalid signature")
err = "client request can't be validated: " .. (err or "Invalid signature")
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.warn(err)
return 401, {message = "client request can't be validated"}
end

Expand Down
19 changes: 16 additions & 3 deletions apisix/plugins/jwt-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ local jwt = require("resty.jwt")
local consumer_mod = require("apisix.consumer")
local resty_random = require("resty.random")
local new_tab = require ("table.new")
local auth_utils = require("apisix.utils.auth")

local ngx_encode_base64 = ngx.encode_base64
local ngx_decode_base64 = ngx.decode_base64
Expand Down Expand Up @@ -236,7 +237,11 @@ function _M.rewrite(conf, ctx)
local jwt_obj = jwt:load_jwt(jwt_token)
core.log.info("jwt object: ", core.json.delay_encode(jwt_obj))
if not jwt_obj.valid then
core.log.warn("JWT token invalid: ", jwt_obj.reason)
err = "JWT token invalid: " .. jwt_obj.reason
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.warn(err)
return 401, {message = "JWT token invalid"}
end

Expand All @@ -260,7 +265,11 @@ function _M.rewrite(conf, ctx)

local auth_secret, err = get_auth_secret(consumer.auth_conf)
if not auth_secret then
core.log.error("failed to retrieve secrets, err: ", err)
err = "failed to retrieve secrets, err: " .. err
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.error(err)
return 503, {message = "failed to verify jwt"}
end
local claim_specs = jwt:get_default_validation_options(jwt_obj)
Expand All @@ -270,7 +279,11 @@ function _M.rewrite(conf, ctx)
core.log.info("jwt object: ", core.json.delay_encode(jwt_obj))

if not jwt_obj.verified then
core.log.warn("failed to verify jwt: ", jwt_obj.reason)
err = "failed to verify jwt: " .. jwt_obj.reason
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.warn(err)
return 401, {message = "failed to verify jwt"}
end

Expand Down
17 changes: 14 additions & 3 deletions apisix/plugins/multi-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
local core = require("apisix.core")
local require = require
local pairs = pairs
local type = type

local schema = {
type = "object",
Expand Down Expand Up @@ -68,24 +69,34 @@ end
function _M.rewrite(conf, ctx)
local auth_plugins = conf.auth_plugins
local status_code
local errors = {}

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 returns nothing.
local auth_code = auth.rewrite(auth_plugin_conf, ctx)
local auth_code, err = auth.rewrite(auth_plugin_conf, ctx)
if type(err) == "table" then
err = err.message -- compat
end

status_code = auth_code
if auth_code == nil then
core.log.debug(auth_plugin_name .. " succeed to authenticate the request")
goto authenticated
else
core.log.debug(auth_plugin_name .. " failed to authenticate the request, code: "
.. auth_code)
core.table.insert(errors, auth_plugin_name ..
" failed to authenticate the request, code: "
.. auth_code .. ". error: " .. err)
end
end
end

:: authenticated ::
if status_code ~= nil then
for _, error in pairs(errors) do
core.log.warn(error)
end
return 401, { message = "Authorization Failed" }
end
end
Expand Down
24 changes: 24 additions & 0 deletions apisix/utils/auth.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--
-- 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 _M = {}

function _M.is_running_under_multi_auth(ctx)
return ctx._plugin_name == "multi-auth"
end

return _M
223 changes: 223 additions & 0 deletions t/plugin/multi-auth2.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
#
# 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();
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"
},
"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 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": {}
},
{
"jwt-auth": {}
},
{
"hmac-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
--- response_body
passed



=== TEST 3: invalid basic-auth credentials
--- request
GET /hello
--- more_headers
Authorization: Basic YmFyOmJhcgo=
--- error_code: 401
--- response_body
{"message":"Authorization Failed"}
--- error_log
basic-auth failed to authenticate the request, code: 401. error: Invalid user authorization
jwt-auth failed to authenticate the request, code: 401. error: JWT token invalid: invalid jwt string
hmac-auth failed to authenticate the request, code: 401. error: client request can't be validated: Authorization header does not start with 'Signature'



=== TEST 4: valid basic-auth creds
--- request
GET /hello
--- more_headers
Authorization: Basic Zm9vOmJhcg==
--- response_body
hello world
--- no_error_log
failed to authenticate the request



=== TEST 5: missing hmac auth authorization header
--- request
GET /hello
--- error_code: 401
--- response_body
{"message":"Authorization Failed"}
--- error_log
hmac-auth failed to authenticate the request, code: 401. error: client request can't be validated: missing Authorization header



=== TEST 6: hmac auth missing algorithm
--- request
GET /hello
--- more_headers
Authorization: Signature keyId="my-access-key",headers="@request-target date" ,signature="asdf"
Date: Thu, 24 Sep 2020 06:39:52 GMT
--- error_code: 401
--- response_body
{"message":"Authorization Failed"}
--- error_log
hmac-auth failed to authenticate the request, code: 401. error: client request can't be validated: algorithm missing



=== TEST 7: 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 8: test with expired jwt token
--- request
GET /hello
--- error_code: 401
--- response_body
{"message":"Authorization Failed"}
--- error_log
jwt-auth failed to authenticate the request, code: 401. error: failed to verify jwt: 'exp' claim expired at Tue, 23 Jul 2019 08:28:21 GMT
--- more_headers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.pPNVvh-TQsdDzorRwa-uuiLYiEBODscp9wv0cwD6c68



=== TEST 9: test with jwt token containing wrong signature
--- request
GET /hello
--- error_code: 401
--- response_body
{"message":"Authorization Failed"}
--- error_log
jwt-auth failed to authenticate the request, code: 401. error: failed to verify jwt: signature mismatch: fNtFJnNnJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs
--- more_headers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNnJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs



=== TEST 10: verify jwt-auth
--- request
GET /hello
--- more_headers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs
--- response_body
hello world
--- no_error_log
failed to authenticate the request
Loading