141 lines
3.9 KiB
Lua
141 lines
3.9 KiB
Lua
local constants = require "kong.constants"
|
|
local groups = require "kong.plugins.acl.groups"
|
|
local kong_meta = require "kong.meta"
|
|
|
|
|
|
local setmetatable = setmetatable
|
|
local concat = table.concat
|
|
local error = error
|
|
local kong = kong
|
|
|
|
|
|
local EMPTY = require("kong.tools.table").EMPTY
|
|
local DENY = "DENY"
|
|
local ALLOW = "ALLOW"
|
|
|
|
|
|
local mt_cache = { __mode = "k" }
|
|
local config_cache = setmetatable({}, mt_cache)
|
|
|
|
|
|
local function get_to_be_blocked(config, groups, in_group)
|
|
local to_be_blocked
|
|
if config.type == DENY then
|
|
to_be_blocked = in_group
|
|
else
|
|
to_be_blocked = not in_group
|
|
end
|
|
|
|
if to_be_blocked == false then
|
|
-- we're allowed, convert 'false' to the header value, if needed
|
|
-- if not needed, set dummy value to save mem for potential long strings
|
|
to_be_blocked = config.hide_groups_header and "" or concat(groups, ", ")
|
|
end
|
|
|
|
return to_be_blocked
|
|
end
|
|
|
|
|
|
local ACLHandler = {}
|
|
|
|
|
|
ACLHandler.PRIORITY = 950
|
|
ACLHandler.VERSION = kong_meta.version
|
|
|
|
|
|
function ACLHandler:access(conf)
|
|
-- simplify our plugins 'conf' table
|
|
local config = config_cache[conf]
|
|
if not config then
|
|
local config_type = (conf.deny or EMPTY)[1] and DENY or ALLOW
|
|
|
|
config = {
|
|
hide_groups_header = conf.hide_groups_header,
|
|
type = config_type,
|
|
groups = config_type == DENY and conf.deny or conf.allow,
|
|
cache = setmetatable({}, mt_cache),
|
|
}
|
|
|
|
config_cache[conf] = config
|
|
end
|
|
|
|
local to_be_blocked
|
|
|
|
-- get the consumer/credentials
|
|
local consumer_id = groups.get_current_consumer_id()
|
|
if not consumer_id then
|
|
local authenticated_groups = groups.get_authenticated_groups()
|
|
if not authenticated_groups then
|
|
if kong.client.get_credential() then
|
|
return kong.response.error(403, "You cannot consume this service")
|
|
end
|
|
|
|
return kong.response.error(401)
|
|
end
|
|
|
|
local in_group = groups.group_in_groups(config.groups, authenticated_groups)
|
|
to_be_blocked = get_to_be_blocked(config, authenticated_groups, in_group)
|
|
|
|
else
|
|
local credential = kong.client.get_credential()
|
|
local authenticated_groups
|
|
if (not credential) or conf.always_use_authenticated_groups then
|
|
-- authenticated groups overrides anonymous groups
|
|
authenticated_groups = groups.get_authenticated_groups()
|
|
end
|
|
|
|
if authenticated_groups then
|
|
consumer_id = nil
|
|
|
|
local in_group = groups.group_in_groups(config.groups, authenticated_groups)
|
|
to_be_blocked = get_to_be_blocked(config, authenticated_groups, in_group)
|
|
|
|
else
|
|
-- get the consumer groups, since we need those as cache-keys to make sure
|
|
-- we invalidate properly if they change
|
|
local consumer_groups, err = groups.get_consumer_groups(consumer_id)
|
|
if err then
|
|
return error(err)
|
|
end
|
|
|
|
if not consumer_groups then
|
|
if config.type == DENY then
|
|
consumer_groups = EMPTY
|
|
|
|
else
|
|
if credential then
|
|
return kong.response.error(403, "You cannot consume this service")
|
|
end
|
|
|
|
return kong.response.error(401)
|
|
end
|
|
end
|
|
|
|
-- 'to_be_blocked' is either 'true' if it's to be blocked, or the header
|
|
-- value if it is to be passed
|
|
to_be_blocked = config.cache[consumer_groups]
|
|
if to_be_blocked == nil then
|
|
local in_group = groups.consumer_in_groups(config.groups, consumer_groups)
|
|
to_be_blocked = get_to_be_blocked(config, consumer_groups, in_group)
|
|
|
|
-- update cache
|
|
config.cache[consumer_groups] = to_be_blocked
|
|
end
|
|
end
|
|
end
|
|
|
|
if to_be_blocked == true then -- NOTE: we only catch the boolean here!
|
|
return kong.response.error(403, "You cannot consume this service")
|
|
end
|
|
|
|
if not conf.hide_groups_header and to_be_blocked then
|
|
kong.service.request.set_header(consumer_id and
|
|
constants.HEADERS.CONSUMER_GROUPS or
|
|
constants.HEADERS.AUTHENTICATED_GROUPS,
|
|
to_be_blocked)
|
|
end
|
|
end
|
|
|
|
|
|
return ACLHandler
|