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

feat(pdk) add consumer, service, route handling #3916

Merged
merged 2 commits into from Nov 1, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+725 −218
Diff settings

Always

Just for now

@@ -179,6 +179,7 @@ build = {
["kong.pdk.service"] = "kong/pdk/service.lua",
["kong.pdk.service.request"] = "kong/pdk/service/request.lua",
["kong.pdk.service.response"] = "kong/pdk/service/response.lua",
["kong.pdk.router"] = "kong/pdk/router.lua",
["kong.pdk.request"] = "kong/pdk/request.lua",
["kong.pdk.response"] = "kong/pdk/response.lua",
["kong.pdk.table"] = "kong/pdk/table.lua",
@@ -12,10 +12,16 @@ local phase_checker = require "kong.pdk.private.phases"

local ngx = ngx
local tonumber = tonumber
local check_phase = phase_checker.check
local check_not_phase = phase_checker.check_not


local PHASES = phase_checker.phases
local AUTH_AND_LATER = phase_checker.new(PHASES.access,
PHASES.header_filter,
PHASES.body_filter,
PHASES.log)
local TABLE_OR_NIL = { ["table"] = true, ["nil"] = true }


local function new(self)
@@ -121,6 +127,78 @@ local function new(self)
end


---
-- Returns the credentials of the currently authenticated consumer.
-- If not set yet, it returns `nil`.
-- @function kong.client.get_credential
-- @phases access, header_filter, body_filter, log
-- @return the authenticated credential
-- @usage
-- local credential = kong.client.get_credential()
-- if credential then
-- consumer_id = credential.consumer_id
-- else
-- -- request not authenticated yet
-- end
function _CLIENT.get_credential()
check_phase(AUTH_AND_LATER)

return ngx.ctx.authenticated_credential
end


---
-- Returns the `consumer` entity of the currently authenticated consumer.
-- If not set yet, it returns `nil`.
-- @function kong.client.get_consumer
-- @phases access, header_filter, body_filter, log
-- @treturn table the authenticated consumer entity
-- @usage
-- local consumer = kong.client.get_consumer()
-- if consumer then
-- consumer_id = consumer.id
-- else
-- -- request not authenticated yet, or a credential
-- -- without a consumer (external auth)
-- end
function _CLIENT.get_consumer()
check_phase(AUTH_AND_LATER)

return ngx.ctx.authenticated_consumer
end


---
-- Sets the authenticated consumer and/or credential for the current request.
-- While both `consumer` and `credential` can be `nil`, it is required
-- that at least one of them exists. Otherwise this function will throw an
-- error.
-- @function kong.client.authenticate
-- @phases access
-- @tparam table|nil consumer The consumer to set. Note: if no
-- value is provided, then any existing value will be cleared!
-- @tparam table|nil credential The credential to set. Note: if
-- no value is provided, then any existing value will be cleared!
-- @usage
-- -- assuming `credential` and `consumer` have been set by some authentication code
-- kong.client.authenticate(consumer, credentials)
function _CLIENT.authenticate(consumer, credential)
check_phase(PHASES.access)

if not TABLE_OR_NIL[type(consumer)] then
error("consumer must be a table or nil", 2)
elseif not TABLE_OR_NIL[type(credential)] then
error("credential must be a table or nil", 2)
elseif credential == nil and consumer == nil then
error("either credential or consumer must be provided", 2)
end

This conversation was marked as resolved by Tieske

This comment has been minimized.

Copy link
@kikito

kikito Oct 31, 2018

Member

I am not 100% sure, but if both the consumer and the credentials are nil, isn't that an error? If yes, that needs to be tested and documented in the ldocs.

This comment has been minimized.

Copy link
@Tieske

Tieske Oct 31, 2018

Author Member

I removed the option, since it isn't used yet. Easy to relax later or add a clear_auth method or something similar.

local ctx = ngx.ctx
ctx.authenticated_consumer = consumer
ctx.authenticated_credential = credential
end


return _CLIENT
end

@@ -116,6 +116,11 @@
-- @redirect kong.response


--- Router module
-- @field kong.router
-- @redirect kong.router


--- Singletons
-- @section singletons

@@ -226,6 +231,7 @@ local MAJOR_VERSIONS = {
"service.request",
"service.response",
"response",
"router",
},
},

@@ -0,0 +1,70 @@
--- Router module
-- A set of functions to access the routing properties of the request.
--
-- @module kong.router


local phase_checker = require "kong.pdk.private.phases"


local ngx = ngx
local check_phase = phase_checker.check


local PHASES = phase_checker.phases
local ROUTER_PHASES = phase_checker.new(PHASES.access,
PHASES.header_filter,
PHASES.body_filter,
PHASES.log)

local function new(self)
local _ROUTER = {}


---
-- Returns the current `route` entity. The request was matched against this
-- route.
--
-- @function kong.router.get_route
-- @phases access, header_filter, body_filter, log
-- @treturn table the `route` entity.
-- @usage
-- if kong.router.get_route() then
-- -- routed by route & service entities
-- else
-- -- routed by a legacy API entity
-- end
function _ROUTER.get_route()
check_phase(ROUTER_PHASES)

return ngx.ctx.route
end


---
-- Returns the current `service` entity. The request will be targetted to this
-- upstream service.
--
-- @function kong.router.get_service
-- @phases access, header_filter, body_filter, log
-- @treturn table the `service` entity.
-- @usage
-- if kong.router.get_service() then
-- -- routed by route & service entities
-- else
-- -- routed by a legacy API entity
-- end
function _ROUTER.get_service()
check_phase(ROUTER_PHASES)

return ngx.ctx.service
end


return _ROUTER
end


return {
new = new,
}
@@ -133,22 +133,8 @@ end
-- @return consumer_id (string), or alternatively `nil` if no consumer was
-- authenticated.
local function get_current_consumer_id()
local ctx = kong.ctx.shared
if ctx.authenticated_consumer and ctx.authenticated_consumer.id then
return ctx.authenticated_consumer.id
elseif ctx.authenticated_credential and ctx.authenticated_credential.consumer_id then
return ctx.authenticated_credential.consumer_id
end

-- TODO: only for backward compability (may be removed later)
ctx = ngx.ctx
if ctx.authenticated_consumer and ctx.authenticated_consumer.id then
return ctx.authenticated_consumer.id
elseif ctx.authenticated_credential and ctx.authenticated_credential.consumer_id then
return ctx.authenticated_credential.consumer_id
end

return nil
return (kong.client.get_consumer() or EMPTY).id or
(kong.client.get_credential() or EMPTY).consumer_id
end


@@ -120,16 +120,9 @@ local function set_consumer(consumer, credential)
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 shared_ctx = kong.ctx.shared
local ngx_ctx = ngx.ctx -- TODO: for bc only

shared_ctx.authenticated_consumer = consumer
ngx_ctx.authenticated_consumer = consumer
kong.client.authenticate(consumer, credential)

if credential then
shared_ctx.authenticated_credential = credential
ngx_ctx.authenticated_credential = credential

kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
kong.service.request.clear_header(constants.HEADERS.ANONYMOUS)

@@ -183,20 +176,10 @@ end


function _M.execute(conf)
if conf.anonymous then
local shared_ctx = kong.ctx.shared
if shared_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local ngx_ctx = ngx.ctx -- TODO: for bc only
if ngx_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end
if conf.anonymous and kong.client.get_credential() then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local ok, err = do_authentication(conf)
@@ -1,6 +1,6 @@
local constants = require "kong.constants"
local sha256 = require "resty.sha256"
local hmac = require "openssl.hmac"
local openssl_hmac = require "openssl.hmac"
local utils = require "kong.tools.utils"


@@ -31,13 +31,13 @@ local hmac = {
return hmac_sha1(secret, data)
end,
["hmac-sha256"] = function(secret, data)
return hmac.new(secret, "sha256"):final(data)
return openssl_hmac.new(secret, "sha256"):final(data)
end,
["hmac-sha384"] = function(secret, data)
return hmac.new(secret, "sha384"):final(data)
return openssl_hmac.new(secret, "sha384"):final(data)
end,
["hmac-sha512"] = function(secret, data)
return hmac.new(secret, "sha512"):final(data)
return openssl_hmac.new(secret, "sha512"):final(data)
end,
}

@@ -251,16 +251,9 @@ local function set_consumer(consumer, credential)
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 shared_ctx = kong.ctx.shared
local ngx_ctx = ngx.ctx -- TODO: for bc only

shared_ctx.authenticated_consumer = consumer
ngx_ctx.authenticated_consumer = consumer
kong.client.authenticate(consumer, credential)

if credential then
shared_ctx.authenticated_credential = credential
ngx_ctx.authenticated_credential = credential

kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
kong.service.request.clear_header(constants.HEADERS.ANONYMOUS)

@@ -329,10 +322,11 @@ local function do_authentication(conf)
end

-- Retrieve consumer
local consumer_cache_key = kong.db.consumers:cache_key(credential.consumer.id)
local consumer, err = kong.cache:get(consumer_cache_key, nil,
load_consumer_into_memory,
credential.consumer.id)
local consumer_cache_key, consumer
consumer_cache_key = kong.db.consumers:cache_key(credential.consumer.id)
consumer, err = kong.cache:get(consumer_cache_key, nil,
load_consumer_into_memory,
credential.consumer.id)
if err then
kong.log.err(err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
@@ -348,20 +342,10 @@ local _M = {}


function _M.execute(conf)
if conf.anonymous then
local shared_ctx = kong.ctx.shared
if shared_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local ngx_ctx = ngx.ctx -- TODO: for bc only
if ngx_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end
if conf.anonymous and kong.client.get_credential() then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local ok, err = do_authentication(conf)
@@ -91,17 +91,11 @@ local function set_consumer(consumer, credential, token)
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 shared_ctx = kong.ctx.shared
local ngx_ctx = ngx.ctx -- TODO: for bc only

shared_ctx.authenticated_consumer = consumer
ngx_ctx.authenticated_consumer = consumer
kong.client.authenticate(consumer, credential)

if credential then
shared_ctx.authenticated_credential = credential
shared_ctx.authenticated_jwt_token = token
ngx_ctx.authenticated_credential = credential
ngx_ctx.authenticated_jwt_token = token
kong.ctx.shared.authenticated_jwt_token = token -- TODO: wrap in a PDK function?
ngx.ctx.authenticated_jwt_token = token -- backward compatibilty only

if credential.username then
kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username)
@@ -231,20 +225,10 @@ function JwtHandler:access(conf)
return
end

if conf.anonymous then
local shared_ctx = kong.ctx.shared
if shared_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local ngx_ctx = ngx.ctx -- TODO: for bc only
if ngx_ctx.authenticated_credential then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end
if conf.anonymous and kong.client.get_credential() then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local ok, err = do_authentication(conf)
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.