diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f844d3d3ffcc..9a95fb43f8ad 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,8 @@ + ### Summary diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6095128d3a75..c83367527502 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,8 @@ + ### Summary diff --git a/CHANGELOG.md b/CHANGELOG.md index 480fb7de0199..c071662c6de5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -157,7 +157,7 @@ repository will allow you to do both easily. directives. We have high hopes that this will remove the occasional need for custom Nginx configuration templates. [#4382](https://github.com/Kong/kong/pull/4382) -- :fireworks: New configuration properties allow for controling the behavior of +- :fireworks: New configuration properties allow for controlling the behavior of upstream keepalive connections. `nginx_http_upstream_keepalive_requests` and `nginx_http_upstream_keepalive_timeout` respectively control the maximum number of proxied requests and idle timeout of an upstream connection. @@ -295,7 +295,7 @@ bugfixes. There are no new features nor breaking changes. ##### Core -- Case sentitivity fix when clearing the Upgrade header. +- Case sensitivity fix when clearing the Upgrade header. [#4779](https://github.com/kong/kong/issues/4779) ### Performance diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b1b9a25c2ec2..0e556447559b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at support@mashape.com. All +reported by contacting the project team at support@konghq.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/kong/conf_loader.lua b/kong/conf_loader.lua index fa06ce898116..690b03362535 100644 --- a/kong/conf_loader.lua +++ b/kong/conf_loader.lua @@ -555,6 +555,7 @@ local function overrides(k, default_v, opts, file_conf, arg_conf) opts = opts or {} local value -- definitive value for this property + local escape -- whether to escape a value's octothorpes -- default values have lowest priority @@ -582,12 +583,24 @@ local function overrides(k, default_v, opts, file_conf, arg_conf) end log.debug('%s ENV found with "%s"', env_name, to_print) + value = env + escape = true end -- arg_conf have highest priority if arg_conf and arg_conf[k] ~= nil then value = arg_conf[k] + escape = true + end + + if escape and type(value) == "string" then + -- Escape "#" in env vars or overrides to avoid them being mangled by + -- comments stripping logic. + repeat + local s, n = string.gsub(value, [[([^\])#]], [[%1\#]]) + value = s + until n == 0 end return value, k diff --git a/kong/db/strategies/cassandra/init.lua b/kong/db/strategies/cassandra/init.lua index 0d12b556f29e..85086708e885 100644 --- a/kong/db/strategies/cassandra/init.lua +++ b/kong/db/strategies/cassandra/init.lua @@ -290,7 +290,7 @@ local function serialize_arg(field, arg) elseif field.type == "integer" then serialized_arg = cassandra.int(arg) - elseif field.type == "float" then + elseif field.type == "number" then serialized_arg = cassandra.float(arg) elseif field.type == "boolean" then @@ -1028,6 +1028,7 @@ do if not entity_ids then return {}, nil, nil end + local entity_index = 0 entity_count = entity_count or #entity_ids local entities = new_tab(entity_count, 0) -- TODO: send one query using IN @@ -1037,7 +1038,10 @@ do if err then return nil, err, err_t end - entities[i] = entity + if entity then + entity_index = entity_index + 1 + entities[entity_index] = entity + end end return entities, nil, nil end @@ -1151,8 +1155,8 @@ do clear_tab(current_entity_ids) current_entity_count = 0 for i, row in ipairs(rows) do - current_entity_ids[i] = row.entity_id current_entity_count = current_entity_count + 1 + current_entity_ids[current_entity_count] = row.entity_id end end end diff --git a/kong/plugins/jwt/handler.lua b/kong/plugins/jwt/handler.lua index 1ee01301a58a..f95b9ec126e5 100644 --- a/kong/plugins/jwt/handler.lua +++ b/kong/plugins/jwt/handler.lua @@ -102,7 +102,7 @@ local function set_consumer(consumer, credential, token) if credential then kong.ctx.shared.authenticated_jwt_token = token -- TODO: wrap in a PDK function? - ngx.ctx.authenticated_jwt_token = token -- backward compatibilty only + ngx.ctx.authenticated_jwt_token = token -- backward compatibility only if credential.username then set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) @@ -149,6 +149,8 @@ local function do_authentication(conf) local jwt_secret_key = claims[conf.key_claim_name] or header[conf.key_claim_name] if not jwt_secret_key then return false, { status = 401, message = "No mandatory '" .. conf.key_claim_name .. "' in claims" } + elseif jwt_secret_key == "" then + return false, { status = 401, message = "Invalid '" .. conf.key_claim_name .. "' in claims" } end -- Retrieve the secret diff --git a/spec/01-unit/01-db/01-schema/07-plugins_spec.lua b/spec/01-unit/01-db/01-schema/07-plugins_spec.lua index a06652f02821..d4c432510efa 100644 --- a/spec/01-unit/01-db/01-schema/07-plugins_spec.lua +++ b/spec/01-unit/01-db/01-schema/07-plugins_spec.lua @@ -1,3 +1,4 @@ +require "spec.helpers" -- initializes 'kong' global for plugins local Entity = require "kong.db.schema.entity" local typedefs = require "kong.db.schema.typedefs" local utils = require "kong.tools.utils" diff --git a/spec/01-unit/03-conf_loader_spec.lua b/spec/01-unit/03-conf_loader_spec.lua index 9de9ab192a55..cb26468798ec 100644 --- a/spec/01-unit/03-conf_loader_spec.lua +++ b/spec/01-unit/03-conf_loader_spec.lua @@ -229,6 +229,61 @@ describe("Configuration loader", function() local conf = assert(conf_loader("spec/fixtures/to-strip.conf")) assert.equal("test#123", conf.pg_password) end) + it("escapes unescaped octothorpes in environment variables", function() + finally(function() + helpers.unsetenv("KONG_PG_PASSWORD") + end) + helpers.setenv("KONG_PG_PASSWORD", "test#123") + local conf = assert(conf_loader()) + assert.equal("test#123", conf.pg_password) + + helpers.setenv("KONG_PG_PASSWORD", "test#12#3") + local conf = assert(conf_loader()) + assert.equal("test#12#3", conf.pg_password) + + helpers.setenv("KONG_PG_PASSWORD", "test##12##3#") + local conf = assert(conf_loader()) + assert.equal("test##12##3#", conf.pg_password) + end) + it("escapes unescaped octothorpes in custom_conf overrides", function() + local conf = assert(conf_loader(nil, { + pg_password = "test#123", + })) + assert.equal("test#123", conf.pg_password) + + local conf = assert(conf_loader(nil, { + pg_password = "test#12#3", + })) + assert.equal("test#12#3", conf.pg_password) + + local conf = assert(conf_loader(nil, { + pg_password = "test##12##3#", + })) + assert.equal("test##12##3#", conf.pg_password) + end) + it("does not modify existing escaped octothorpes in environment variables", function() + finally(function() + helpers.unsetenv("KONG_PG_PASSWORD") + end) + helpers.setenv("KONG_PG_PASSWORD", [[test\#123]]) + local conf = assert(conf_loader()) + assert.equal("test#123", conf.pg_password) + + helpers.setenv("KONG_PG_PASSWORD", [[test\#\#12\#\#3\#]]) + local conf = assert(conf_loader()) + assert.equal("test##12##3#", conf.pg_password) + end) + it("does not modify existing escaped octothorpes in custom_conf overrides", function() + local conf = assert(conf_loader(nil, { + pg_password = [[test\#123]], + })) + assert.equal("test#123", conf.pg_password) + + local conf = assert(conf_loader(nil, { + pg_password = [[test\#\#12\#\#3\#]], + })) + assert.equal("test##12##3#", conf.pg_password) + end) describe("dynamic directives", function() it("loads flexible prefix based configs from a file", function() diff --git a/spec/01-unit/12-plugins_order_spec.lua b/spec/01-unit/12-plugins_order_spec.lua index 2a24e82afd6b..33886d88d57a 100644 --- a/spec/01-unit/12-plugins_order_spec.lua +++ b/spec/01-unit/12-plugins_order_spec.lua @@ -1,3 +1,4 @@ +require "spec.helpers" -- initializes 'kong' global for plugins local conf_loader = require "kong.conf_loader" diff --git a/spec/01-unit/13-plugins_version_spec.lua b/spec/01-unit/13-plugins_version_spec.lua index 07d524978070..49101ec6e28b 100644 --- a/spec/01-unit/13-plugins_version_spec.lua +++ b/spec/01-unit/13-plugins_version_spec.lua @@ -1,3 +1,4 @@ +require "spec.helpers" -- initializes 'kong' global for plugins local conf_loader = require "kong.conf_loader" diff --git a/spec/03-plugins/16-jwt/03-access_spec.lua b/spec/03-plugins/16-jwt/03-access_spec.lua index 39c78a1d3e97..413d7352b91f 100644 --- a/spec/03-plugins/16-jwt/03-access_spec.lua +++ b/spec/03-plugins/16-jwt/03-access_spec.lua @@ -221,6 +221,22 @@ for _, strategy in helpers.each_strategy() do local json = cjson.decode(body) assert.same({ message = "No mandatory 'iss' in claims" }, json) end) + it("returns 401 if the claims do not contain a valid key to identify a secret", function() + PAYLOAD.iss = "" + local jwt = jwt_encoder.encode(PAYLOAD, "foo") + local authorization = "Bearer " .. jwt + local res = assert(proxy_client:send { + method = "GET", + path = "/request", + headers = { + ["Authorization"] = authorization, + ["Host"] = "jwt1.com", + } + }) + local body = assert.res_status(401, res) + local json = cjson.decode(body) + assert.same({ message = "Invalid 'iss' in claims" }, json) + end) it("returns 401 Unauthorized if the iss does not match a credential", function() PAYLOAD.iss = "123456789" local jwt = jwt_encoder.encode(PAYLOAD, jwt_secret.secret) diff --git a/spec/helpers.lua b/spec/helpers.lua index 4e94cdb3d03f..f51322828d3d 100644 --- a/spec/helpers.lua +++ b/spec/helpers.lua @@ -46,6 +46,13 @@ local http = require "resty.http" local nginx_signals = require "kong.cmd.utils.nginx_signals" local log = require "kong.cmd.utils.log" local DB = require "kong.db" +local ffi = require "ffi" + + +ffi.cdef [[ + int setenv(const char *name, const char *value, int overwrite); + int unsetenv(const char *name); +]] log.set_lvl(log.levels.quiet) -- disable stdout logs in tests @@ -1517,15 +1524,13 @@ local function kong_exec(cmd, env, pl_returns, env_vars) return exec(env_vars .. " " .. BIN_PATH .. " " .. cmd, pl_returns) end ---- Prepare the Kong environment. --- creates the workdirectory and deletes any existing one. +--- Prepares the Kong environment. +-- Creates the working directory if it does not exist. -- @param prefix (optional) path to the working directory, if omitted the test -- configuration will be used -- @name prepare_prefix local function prepare_prefix(prefix) - prefix = prefix or conf.prefix - exec("rm -rf " .. prefix .. "/*") - return pl_dir.makepath(prefix) + return pl_dir.makepath(prefix or conf.prefix) end --- Cleans the Kong environment. @@ -1690,11 +1695,15 @@ local function start_kong(env, tables, preserve_prefix, fixtures) end env = env or {} local prefix = env.prefix or conf.prefix - if not preserve_prefix then - local ok, err = prepare_prefix(prefix) - if not ok then return nil, err end + + -- note: set env var "KONG_TEST_DONT_CLEAN" !! the "_TEST" will be dropped + if not (preserve_prefix or os.getenv("KONG_DONT_CLEAN")) then + clean_prefix(prefix) end + local ok, err = prepare_prefix(prefix) + if not ok then return nil, err end + truncate_tables(db, tables) local nginx_conf = "" @@ -2005,6 +2014,12 @@ return { wait_pid(pid_path, timeout) end end, + setenv = function(env, value) + return ffi.C.setenv(env, value, 1) == 0 + end, + unsetenv = function(env) + return ffi.C.unsetenv(env) == 0 + end, make_yaml_file = make_yaml_file, }