diff --git a/apisix/plugins/basic-auth.lua b/apisix/plugins/basic-auth.lua index 5d3f46a94201..47e70c07b44d 100644 --- a/apisix/plugins/basic-auth.lua +++ b/apisix/plugins/basic-auth.lua @@ -43,7 +43,10 @@ local consumer_schema = { title = "work with consumer object", properties = { username = { type = "string" }, - password = { type = "string" }, + password = { + type = "string", + minLength = 1, + }, }, encrypt_fields = {"password"}, required = {"username", "password"}, @@ -148,6 +151,13 @@ local function find_consumer(ctx) return nil, nil, "Invalid user authorization" end + -- RFC 8265 section 4.1: a password MUST NOT be zero-length. Fail closed + -- when the resolved password is empty, which also covers existing data + -- and $secret:// / $ENV:// references that resolve to "". + if password == "" or cur_consumer.auth_conf.password == "" then + return nil, nil, "Invalid user authorization" + end + if cur_consumer.auth_conf.password ~= password then return nil, nil, "Invalid user authorization" end diff --git a/t/plugin/basic-auth.t b/t/plugin/basic-auth.t index 2e19a2f6d7f1..23748ca7770d 100644 --- a/t/plugin/basic-auth.t +++ b/t/plugin/basic-auth.t @@ -708,3 +708,81 @@ Authorization: bASiC Zm9vOmJhcg== hello world --- error_log find consumer foo + + +=== TEST 40: consumer schema rejects empty password +--- config + location /t { + content_by_lua_block { + local core = require("apisix.core") + local plugin = require("apisix.plugins.basic-auth") + local ok, err = plugin.check_schema({username = 'foo', password = ''}, core.schema.TYPE_CONSUMER) + if ok then + ngx.say("unexpected: schema accepted empty password") + return + end + ngx.say(err or "rejected") + } + } +--- request +GET /t +--- response_body_like +property "password" validation failed +--- no_error_log +unexpected + + + +=== TEST 41: admin api rejects consumer with empty password +--- 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": "empty-pass", + "plugins": { + "basic-auth": { + "username": "empty-pass", + "password": "" + } + } + }]] + ) + if code < 400 then + ngx.status = 500 + ngx.say("unexpected: admin api accepted empty password") + return + end + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- error_code: 400 +--- response_body_like +property "password" validation failed +--- no_error_log +unexpected + + + +=== TEST 42: empty password in Authorization header is rejected +--- request +GET /hello +--- more_headers +Authorization: Basic Zm9vOg== +--- error_code: 401 + + + +=== TEST 43: whitespace-only password in Authorization header is rejected +--- request +GET /hello +--- more_headers +Authorization: Basic Zm9vOiA= +--- error_code: 401 +--- response_body +{"message":"Invalid user authorization"}