215 lines
5.9 KiB
Lua
215 lines
5.9 KiB
Lua
local EMPTY = require("kong.tools.table").EMPTY
|
|
|
|
|
|
local kong = kong
|
|
local type = type
|
|
local mt_cache = { __mode = "k" }
|
|
local setmetatable = setmetatable
|
|
local consumer_groups_cache = setmetatable({}, mt_cache)
|
|
local consumer_in_groups_cache = setmetatable({}, mt_cache)
|
|
|
|
|
|
local function load_groups_into_memory(consumer_pk)
|
|
local groups
|
|
local len = 0
|
|
|
|
for row, err in kong.db.acls:each_for_consumer(consumer_pk) do
|
|
if err then
|
|
return nil, err
|
|
end
|
|
|
|
if not groups then
|
|
groups = {}
|
|
end
|
|
|
|
len = len + 1
|
|
groups[len] = row
|
|
end
|
|
|
|
if len == 0 then
|
|
return EMPTY
|
|
end
|
|
|
|
return groups
|
|
end
|
|
|
|
|
|
--- Returns the database records with groups the consumer belongs to
|
|
-- @param consumer_id (string) the consumer for which to fetch the groups it belongs to
|
|
-- @return table with group records (empty table if none), or nil+error
|
|
local function get_consumer_groups_raw(consumer_id)
|
|
local cache_key = kong.db.acls:cache_key(consumer_id)
|
|
local raw_groups, err = kong.cache:get(cache_key, nil,
|
|
load_groups_into_memory,
|
|
{ id = consumer_id })
|
|
if err then
|
|
return nil, err
|
|
end
|
|
|
|
if raw_groups and #raw_groups > 0 then
|
|
return raw_groups
|
|
end
|
|
|
|
-- use EMPTY to be able to use it as a cache key, since a new table would
|
|
-- immediately be collected again and not allow for negative caching.
|
|
return EMPTY
|
|
end
|
|
|
|
|
|
--- Returns a table with all group names a consumer belongs to.
|
|
-- The table will have an array part to iterate over, and a hash part
|
|
-- where each group name is indexed by itself. Eg.
|
|
-- {
|
|
-- [1] = "users",
|
|
-- [2] = "admins",
|
|
-- users = "users",
|
|
-- admins = "admins",
|
|
-- }
|
|
-- If there are no groups defined, it will return an empty table
|
|
-- @param consumer_id (string) the consumer for which to fetch the groups it belongs to
|
|
-- @return table with groups, nil or nil+error
|
|
local function get_consumer_groups(consumer_id)
|
|
local raw_groups, err = get_consumer_groups_raw(consumer_id)
|
|
if not raw_groups then
|
|
return nil, err
|
|
end
|
|
|
|
local groups = consumer_groups_cache[raw_groups]
|
|
if not groups then
|
|
if raw_groups == EMPTY then
|
|
consumer_groups_cache[raw_groups] = EMPTY
|
|
|
|
else
|
|
groups = {}
|
|
consumer_groups_cache[raw_groups] = groups
|
|
for i = 1, #raw_groups do
|
|
local group = raw_groups[i].group
|
|
groups[i] = group
|
|
groups[group] = group
|
|
end
|
|
end
|
|
end
|
|
|
|
if groups == EMPTY then
|
|
return nil
|
|
end
|
|
|
|
return groups
|
|
end
|
|
|
|
|
|
--- checks whether a consumer-group-list is part of a given list of groups.
|
|
-- @param groups_to_check (table) an array of group names. Note: since the
|
|
-- results will be cached by this table, always use the same table for the
|
|
-- same set of groups!
|
|
-- @param consumer_groups (table) list of consumer groups (result from
|
|
-- `get_consumer_groups`)
|
|
-- @return (boolean) whether the consumer is part of any of the groups.
|
|
local function consumer_in_groups(groups_to_check, consumer_groups)
|
|
-- 1st level cache on "groups_to_check"
|
|
local result1 = consumer_in_groups_cache[groups_to_check]
|
|
if result1 == nil then
|
|
result1 = setmetatable({}, mt_cache)
|
|
consumer_in_groups_cache[groups_to_check] = result1
|
|
end
|
|
|
|
-- 2nd level cache on "consumer_groups"
|
|
local result2 = result1[consumer_groups]
|
|
if result2 ~= nil then
|
|
return result2
|
|
end
|
|
|
|
-- not found, so validate and populate 2nd level cache
|
|
result2 = false
|
|
for i = 1, #groups_to_check do
|
|
if consumer_groups[groups_to_check[i]] then
|
|
result2 = true
|
|
break
|
|
end
|
|
end
|
|
|
|
result1[consumer_groups] = result2
|
|
|
|
return result2
|
|
end
|
|
|
|
|
|
--- Gets the currently identified consumer for the request.
|
|
-- Checks both consumer and if not found the credentials.
|
|
-- @return consumer_id (string), or alternatively `nil` if no consumer was
|
|
-- authenticated.
|
|
local function get_current_consumer_id()
|
|
return (kong.client.get_consumer() or EMPTY).id or
|
|
(kong.client.get_credential() or EMPTY).consumer_id
|
|
end
|
|
|
|
|
|
--- Returns a table with all group names.
|
|
-- The table will have an array part to iterate over, and a hash part
|
|
-- where each group name is indexed by itself. Eg.
|
|
-- {
|
|
-- [1] = "users",
|
|
-- [2] = "admins",
|
|
-- users = "users",
|
|
-- admins = "admins",
|
|
-- }
|
|
-- If there are no authenticated_groups defined, it will return nil
|
|
-- @return table with groups or nil
|
|
local function get_authenticated_groups()
|
|
local authenticated_groups = kong.ctx.shared.authenticated_groups
|
|
if type(authenticated_groups) ~= "table" then
|
|
authenticated_groups = ngx.ctx.authenticated_groups
|
|
if authenticated_groups == nil then
|
|
return nil
|
|
end
|
|
|
|
if type(authenticated_groups) ~= "table" then
|
|
kong.log.warn("invalid authenticated_groups, a table was expected")
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local groups = {}
|
|
for i = 1, #authenticated_groups do
|
|
groups[i] = authenticated_groups[i]
|
|
groups[authenticated_groups[i]] = authenticated_groups[i]
|
|
end
|
|
|
|
return groups
|
|
end
|
|
|
|
|
|
--- checks whether a group-list is part of a given list of groups.
|
|
-- @param groups_to_check (table) an array of group names.
|
|
-- @param groups (table) list of groups (result from
|
|
-- `get_authenticated_groups`)
|
|
-- @return (boolean) whether the authenticated group is part of any of the
|
|
-- groups.
|
|
local function group_in_groups(groups_to_check, groups)
|
|
for i = 1, #groups_to_check do
|
|
if groups[groups_to_check[i]] then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
local function warmup_groups_cache(consumer_id)
|
|
local cache_key = kong.db.acls:cache_key(consumer_id)
|
|
local _, err = kong.cache:get(cache_key, nil,
|
|
load_groups_into_memory,
|
|
{ id = consumer_id })
|
|
if err then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
|
|
return {
|
|
get_current_consumer_id = get_current_consumer_id,
|
|
get_consumer_groups = get_consumer_groups,
|
|
get_authenticated_groups = get_authenticated_groups,
|
|
consumer_in_groups = consumer_in_groups,
|
|
group_in_groups = group_in_groups,
|
|
warmup_groups_cache = warmup_groups_cache,
|
|
}
|