Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(plugins) make plugins defensive against possible errors and nil headers #4006

Merged
merged 12 commits into from Nov 21, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions kong/init.lua
Expand Up @@ -769,6 +769,9 @@ function Kong.handle_error()
kong_resty_ctx.apply_ref()

local ctx = ngx.ctx

ctx.KONG_UNEXPECTED = true

if not ctx.plugins_for_request then
for _ in plugins_iterator(ctx, loaded_plugins, configured_plugins, true) do
-- just build list of plugins
Expand Down
12 changes: 9 additions & 3 deletions kong/pdk/response.lua
Expand Up @@ -72,7 +72,7 @@ local function new(self, major_version)
-- Returns the HTTP status code currently set for the downstream response (as
-- a Lua number).
--
-- If the request was proxied (as per `kong.service.get_source()`), the
-- If the request was proxied (as per `kong.response.get_source()`), the
-- return value will be that of the response from the Service (identical to
-- `kong.service.response.get_status()`).
--
Expand Down Expand Up @@ -233,11 +233,17 @@ local function new(self, major_version)
function _RESPONSE.get_source()
check_phase(header_body_log)

if ngx.ctx.KONG_PROXIED then
local ctx = ngx.ctx

if ctx.KONG_UNEXPECTED then
return "error"
end

if ctx.KONG_PROXIED then
return "service"
end

if ngx.ctx.KONG_EXITED then
if ctx.KONG_EXITED then
return "exit"
end

Expand Down
2 changes: 1 addition & 1 deletion kong/pdk/service/response.lua
Expand Up @@ -58,7 +58,7 @@ local function new(pdk, major_version)
-- @function kong.service.response.get_status
-- @phases `header_filter`, `body_filter`, `log`
-- @treturn number|nil the status code from the response from the Service, or `nil`
-- if the request was not proxied (i.e. `kong.service.get_source()` returned
-- if the request was not proxied (i.e. `kong.response.get_source()` returned
-- anything other than `"service"`.
-- @usage
-- kong.log.inspect(kong.service.response.get_status()) -- 418
Expand Down
2 changes: 1 addition & 1 deletion kong/plugins/acl/acls.lua
Expand Up @@ -16,13 +16,13 @@ local invalidate_cache = function(self, entity)
end

local cache_key = self:cache_key(consumer.id)

return singletons.cache:invalidate(cache_key)
end


local _ACLs = {}


function _ACLs:post_crud_event(operation, entity)
local _, err, err_t = invalidate_cache(self, entity)
if err then
Expand Down
4 changes: 2 additions & 2 deletions kong/plugins/acl/handler.lua
Expand Up @@ -22,7 +22,7 @@ local ACLHandler = BasePlugin:extend()


ACLHandler.PRIORITY = 950
ACLHandler.VERSION = "0.2.0"
ACLHandler.VERSION = "1.0.0"


function ACLHandler:new()
Expand Down Expand Up @@ -85,7 +85,7 @@ function ACLHandler:access(conf)
return kong.response.exit(403, { message = "You cannot consume this service" })
end

if not conf.hide_groups_header then
if not conf.hide_groups_header and to_be_blocked then
kong.service.request.set_header(constants.HEADERS.CONSUMER_GROUPS,
to_be_blocked)
end
Expand Down
35 changes: 29 additions & 6 deletions kong/plugins/basic-auth/access.lua
Expand Up @@ -116,18 +116,41 @@ local function load_consumer_into_memory(consumer_id, anonymous)
end

local function set_consumer(consumer, credential)
kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
local set_header = kong.service.request.set_header
local clear_header = kong.service.request.clear_header

if consumer and consumer.id then
set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
else
clear_header(constants.HEADERS.CONSUMER_ID)
end

if consumer and consumer.custom_id then
set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
else
clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID)
end

if consumer and consumer.username then
set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
else
clear_header(constants.HEADERS.CONSUMER_USERNAME)
end

kong.client.authenticate(consumer, credential)

if credential then
kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
kong.service.request.clear_header(constants.HEADERS.ANONYMOUS)
if credential.username then
set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
else
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
end

clear_header(constants.HEADERS.ANONYMOUS)

else
kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true)
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
set_header(constants.HEADERS.ANONYMOUS, true)
end
end

Expand Down
2 changes: 1 addition & 1 deletion kong/plugins/basic-auth/handler.lua
Expand Up @@ -18,7 +18,7 @@ end


BasicAuthHandler.PRIORITY = 1001
BasicAuthHandler.VERSION = "0.2.0"
BasicAuthHandler.VERSION = "1.0.0"


return BasicAuthHandler
23 changes: 14 additions & 9 deletions kong/plugins/correlation-id/handler.lua
Expand Up @@ -44,7 +44,7 @@ local CorrelationIdHandler = BasePlugin:extend()


CorrelationIdHandler.PRIORITY = 1
CorrelationIdHandler.VERSION = "0.2.0"
CorrelationIdHandler.VERSION = "1.0.0"


function CorrelationIdHandler:new()
Expand All @@ -63,27 +63,32 @@ function CorrelationIdHandler:access(conf)
CorrelationIdHandler.super.access(self)

-- Set header for upstream
local header_value = kong.request.get_header(conf.header_name)
if not header_value then
local correlation_id = kong.request.get_header(conf.header_name)
if not correlation_id then
-- Generate the header value
header_value = generators[conf.generator]()
kong.service.request.set_header(conf.header_name, header_value)
correlation_id = generators[conf.generator]()
if correlation_id then
kong.service.request.set_header(conf.header_name, correlation_id)
end
end

if conf.echo_downstream then
-- For later use, to echo it back downstream
kong.ctx.plugin.correlationid_header_value = header_value
kong.ctx.plugin.correlation_id = correlation_id
end
end


function CorrelationIdHandler:header_filter(conf)
CorrelationIdHandler.super.header_filter(self)

local header_value = kong.ctx.plugin.correlationid_header_value
if not conf.echo_downstream then
return
end

if conf.echo_downstream and header_value then
kong.response.set_header(conf.header_name, header_value)
local correlation_id = kong.ctx.plugin.correlation_id
if correlation_id then
kong.response.set_header(conf.header_name, correlation_id)
end
end

Expand Down
19 changes: 10 additions & 9 deletions kong/plugins/cors/handler.lua
@@ -1,10 +1,11 @@
local BasePlugin = require "kong.plugins.base_plugin"


local re_find = ngx.re.find
local concat = table.concat
local tostring = tostring
local ipairs = ipairs
local kong = kong
local re_find = ngx.re.find
local concat = table.concat
local tostring = tostring
local ipairs = ipairs


local NO_CONTENT = 204
Expand All @@ -14,7 +15,7 @@ local CorsHandler = BasePlugin:extend()


CorsHandler.PRIORITY = 2000
CorsHandler.VERSION = "0.1.0"
CorsHandler.VERSION = "1.0.0"


local function configure_origin(conf)
Expand Down Expand Up @@ -75,7 +76,7 @@ local function configure_credentials(conf, allow_all)
end

if not allow_all then
set_header("Access-Control-Allow-Credentials", "true")
set_header("Access-Control-Allow-Credentials", true)
return
end

Expand All @@ -84,7 +85,7 @@ local function configure_credentials(conf, allow_all)
local req_origin = kong.request.get_header("origin")
if req_origin then
set_header("Access-Control-Allow-Origin", req_origin)
set_header("Access-Control-Allow-Credentials", "true")
set_header("Access-Control-Allow-Credentials", true)
set_header("Vary", "Origin")
end
end
Expand Down Expand Up @@ -116,7 +117,7 @@ function CorsHandler:access(conf)

local set_header = kong.response.set_header

if conf.headers then
if conf.headers and #conf.headers > 0 then
set_header("Access-Control-Allow-Headers", concat(conf.headers, ","))

else
Expand Down Expand Up @@ -150,7 +151,7 @@ function CorsHandler:header_filter(conf)
local allow_all = configure_origin(conf)
configure_credentials(conf, allow_all)

if conf.exposed_headers then
if conf.exposed_headers and #conf.exposed_headers > 0 then
kong.response.set_header("Access-Control-Expose-Headers",
concat(conf.exposed_headers, ","))
end
Expand Down
35 changes: 29 additions & 6 deletions kong/plugins/hmac-auth/access.lua
Expand Up @@ -247,18 +247,41 @@ end


local function set_consumer(consumer, credential)
kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
local set_header = kong.service.request.set_header
local clear_header = kong.service.request.clear_header

if consumer and consumer.id then
set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
else
clear_header(constants.HEADERS.CONSUMER_ID)
end

if consumer and consumer.custom_id then
set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
else
clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID)
end

if consumer and consumer.username then
set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
else
clear_header(constants.HEADERS.CONSUMER_USERNAME)
end

kong.client.authenticate(consumer, credential)

if credential then
kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
kong.service.request.clear_header(constants.HEADERS.ANONYMOUS)
if credential.username then
set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
else
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
end

clear_header(constants.HEADERS.ANONYMOUS)

else
kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true)
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
set_header(constants.HEADERS.ANONYMOUS, true)
end
end

Expand Down
2 changes: 1 addition & 1 deletion kong/plugins/hmac-auth/handler.lua
Expand Up @@ -18,7 +18,7 @@ end


HMACAuthHandler.PRIORITY = 1000
HMACAuthHandler.VERSION = "0.2.0"
HMACAuthHandler.VERSION = "1.0.0"


return HMACAuthHandler
34 changes: 26 additions & 8 deletions kong/plugins/jwt/handler.lua
Expand Up @@ -15,7 +15,7 @@ local JwtHandler = BasePlugin:extend()


JwtHandler.PRIORITY = 1005
JwtHandler.VERSION = "0.2.0"
JwtHandler.VERSION = "1.0.0"


--- Retrieve a JWT in a request.
Expand Down Expand Up @@ -87,9 +87,26 @@ end


local function set_consumer(consumer, credential, token)
kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
local set_header = kong.service.request.set_header
local clear_header = kong.service.request.clear_header

if consumer and consumer.id then
set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
else
clear_header(constants.HEADERS.CONSUMER_ID)
end

if consumer and consumer.custom_id then
set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
else
clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID)
end

if consumer and consumer.username then
set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
else
clear_header(constants.HEADERS.CONSUMER_USERNAME)
end

kong.client.authenticate(consumer, credential)

Expand All @@ -98,15 +115,16 @@ local function set_consumer(consumer, credential, token)
ngx.ctx.authenticated_jwt_token = token -- backward compatibilty only

if credential.username then
kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
else
kong.service.request.clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
end

kong.service.request.clear_header(constants.HEADERS.ANONYMOUS)
clear_header(constants.HEADERS.ANONYMOUS)

else
kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true)
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
set_header(constants.HEADERS.ANONYMOUS, true)
end
end

Expand Down