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: support anonymous consumer #11792

41 changes: 41 additions & 0 deletions apisix/consumer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ function _M.plugin(plugin_name)
end


function _M.consumers_conf(plugin_name)
return _M.plugin(plugin_name)
end


-- attach chosen consumer to the ctx, used in auth plugin
function _M.attach_consumer(ctx, consumer, conf)
ctx.consumer = consumer
Expand Down Expand Up @@ -208,6 +213,18 @@ function _M.consumers_kv(plugin_name, consumer_conf, key_attr)
return consumers
end

function _M.find_consumer(plugin_name, key, key_value)
local consumer
local consumer_conf
consumer_conf = _M.plugin(plugin_name)
if not consumer_conf then
return nil, nil, "Missing related consumer"
end
local consumers = _M.consumers_kv(plugin_name, consumer_conf, key)
consumer = consumers[key_value]
return consumer, consumer_conf
end

local function check_consumer(consumer, key)
local data_valid
local err
Expand Down Expand Up @@ -251,5 +268,29 @@ function _M.init_worker()
end
end

local function get_anonymous_consumer_from_local_cache(name)
local anon_consumer_raw = consumers:get(name)

if not anon_consumer_raw or not anon_consumer_raw.value or
not anon_consumer_raw.value.id or not anon_consumer_raw.modifiedIndex then
return nil, nil, "failed to get anonymous consumer " .. name
end

-- make structure of anon_consumer similar to that of consumer_mod.consumers_kv's response
local anon_consumer = anon_consumer_raw.value
anon_consumer.consumer_name = anon_consumer_raw.value.id
anon_consumer.modifiedIndex = anon_consumer_raw.modifiedIndex

local anon_consumer_conf = {
conf_version = anon_consumer_raw.modifiedIndex
}

return anon_consumer, anon_consumer_conf
end


function _M.get_anonymous_consumer(name)
return get_anonymous_consumer_from_local_cache(name)
end

return _M
51 changes: 32 additions & 19 deletions apisix/plugins/basic-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ local ngx = ngx
local ngx_re = require("ngx.re")
local consumer = require("apisix.consumer")
local auth_utils = require("apisix.utils.auth")
local schema_def = require("apisix.schema_def")

local lrucache = core.lrucache.new({
ttl = 300, count = 512
Expand All @@ -33,6 +34,8 @@ local schema = {
default = false,
}
},
anonymous_consumer = schema_def.anonymous_consumer_schema,

}

local consumer_schema = {
Expand Down Expand Up @@ -121,48 +124,58 @@ local function extract_auth_header(authorization)

end


function _M.rewrite(conf, ctx)
core.log.info("plugin access phase, conf: ", core.json.delay_encode(conf))

local function find_consumer(ctx)
-- 1. extract authorization from header
local auth_header = core.request.header(ctx, "Authorization")
if not auth_header then
core.response.set_header("WWW-Authenticate", "Basic realm='.'")
return 401, { message = "Missing authorization in request" }
return nil, nil, "Missing authorization in request"
end

local username, password, err = extract_auth_header(auth_header)
if err then
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
return nil, nil, err
end
core.log.warn(err)
return 401, { message = "Invalid authorization in request" }
return nil, nil, "Invalid authorization in request"
end

-- 2. get user info from consumer plugin
local consumer_conf = consumer.plugin(plugin_name)
if not consumer_conf then
return 401, { message = "Missing related consumer" }
end

local consumers = consumer.consumers_kv(plugin_name, consumer_conf, "username")

-- 3. check user exists
local cur_consumer = consumers[username]
local cur_consumer, consumer_conf, err = consumer.find_consumer(plugin_name, "username",
username)
if not cur_consumer then
return 401, { message = "Invalid user authorization" }
core.log.warn("failed to find user: ", err or "invalid user")
return nil, nil, "Invalid user authorization"
end
core.log.info("consumer: ", core.json.delay_encode(cur_consumer))


-- 4. check the password is correct
if cur_consumer.auth_conf.password ~= password then
return 401, { message = "Invalid user authorization" }
return nil, nil, "Invalid user authorization"
end

return cur_consumer, consumer_conf, nil
end

function _M.rewrite(conf, ctx)
core.log.info("plugin access phase, conf: ", core.json.delay_encode(conf))

local cur_consumer, consumer_conf, err = find_consumer(ctx)
if not cur_consumer then
if not conf.anonymous_consumer then
return 401, { message = err }
end
cur_consumer, consumer_conf, err = consumer.get_anonymous_consumer(conf.anonymous_consumer)
if not cur_consumer then
core.log.error(err)
return 401, { message = "Invalid user authorization" }
end
end

-- 5. hide `Authorization` request header if `hide_credentials` is `true`
core.log.info("consumer: ", core.json.delay_encode(cur_consumer))

if conf.hide_credentials then
core.request.set_header(ctx, "Authorization", nil)
end
Expand Down
52 changes: 32 additions & 20 deletions apisix/plugins/hmac-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ local ngx_encode_base64 = ngx.encode_base64
local plugin_name = "hmac-auth"
local ALLOWED_ALGORITHMS = {"hmac-sha1", "hmac-sha256", "hmac-sha512"}
local resty_sha256 = require("resty.sha256")
local auth_utils = require("apisix.utils.auth")
local schema_def = require("apisix.schema_def")

local schema = {
type = "object",
Expand Down Expand Up @@ -62,6 +62,7 @@ local schema = {
default = false,
},
hide_credentials = {type = "boolean", default = false},
anonymous_consumer = schema_def.anonymous_consumer_schema,
},
}

Expand Down Expand Up @@ -187,6 +188,10 @@ end


local function validate(ctx, conf, params)
if not params then
return nil
end

if not params.keyId or not params.signature then
return nil, "keyId or signature missing"
end
Expand Down Expand Up @@ -321,34 +326,41 @@ local function retrieve_hmac_fields(ctx)
return hmac_params
end


function _M.rewrite(conf, ctx)
local function find_consumer(conf, ctx)
local params,err = retrieve_hmac_fields(ctx)
if err then
err = "client request can't be validated: " .. err
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
end
core.log.warn(err)
return 401, {message = err}
core.log.warn("client request can't be validated: ", err)
return nil, nil, "client request can't be validated: " .. err
end

if conf.hide_credentials then
core.request.set_header("Authorization", nil)
end
local validated_consumer, err = validate(ctx, conf, params)
if not validated_consumer then
err = "client request can't be validated: " .. (err or "Invalid signature")
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
core.log.warn("client request can't be validated: ", err or "Invalid signature")
return nil, nil, "client request can't be validated: " .. err
end

local consumers_conf = consumer.consumers_conf(plugin_name)
return validated_consumer, consumers_conf, err
end

function _M.rewrite(conf, ctx)
local cur_consumer, consumers_conf, err = find_consumer(conf, ctx)
if not cur_consumer then
if not conf.anonymous_consumer then
return 401, { message = err }
end
cur_consumer, consumers_conf, err = consumer.get_anonymous_consumer(conf.anonymous_consumer)
if not cur_consumer then
core.log.error(err)
return 401, { message = "Invalid user authorization" }
end
core.log.warn(err)
return 401, {message = "client request can't be validated"}
end

local consumer_conf = consumer.plugin(plugin_name)
consumer.attach_consumer(ctx, validated_consumer, consumer_conf)
core.log.info("hit hmac-auth rewrite")
if conf.hide_credentials then
core.request.set_header("Authorization", nil)
end

consumer.attach_consumer(ctx, cur_consumer, consumers_conf)
end


Expand Down
44 changes: 32 additions & 12 deletions apisix/plugins/jwt-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ local table_insert = table.insert
local table_concat = table.concat
local ngx_re_gmatch = ngx.re.gmatch
local plugin_name = "jwt-auth"

local schema_def = require("apisix.schema_def")

local schema = {
type = "object",
Expand All @@ -55,6 +55,7 @@ local schema = {
default = "key",
minLength = 1,
},
anonymous_consumer = schema_def.anonymous_consumer_schema,
},
}

Expand Down Expand Up @@ -231,52 +232,53 @@ local function get_auth_secret(auth_conf)
end
end

function _M.rewrite(conf, ctx)

local function find_consumer(conf, ctx)
-- fetch token and hide credentials if necessary
local jwt_token, err = fetch_jwt_token(conf, ctx)
if not jwt_token then
core.log.info("failed to fetch JWT token: ", err)
return 401, {message = "Missing JWT token in request"}
return nil, nil, "Missing JWT token in request"
end

local jwt_obj = jwt:load_jwt(jwt_token)
core.log.info("jwt object: ", core.json.delay_encode(jwt_obj))
if not jwt_obj.valid then
err = "JWT token invalid: " .. jwt_obj.reason
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
return nil, nil, err
end
core.log.warn(err)
return 401, {message = "JWT token invalid"}
return nil, nil, "JWT token invalid"
end

local key_claim_name = conf.key_claim_name
local user_key = jwt_obj.payload and jwt_obj.payload[key_claim_name]
if not user_key then
return 401, {message = "missing user key in JWT token"}
return nil, nil, "missing user key in JWT token"
end

local consumer_conf = consumer_mod.plugin(plugin_name)
if not consumer_conf then
return 401, {message = "Missing related consumer"}
return nil, nil, "Missing related consumer"
end

local consumers = consumer_mod.consumers_kv(plugin_name, consumer_conf, "key")

local consumer = consumers[user_key]
if not consumer then
return 401, {message = "Invalid user key in JWT token"}
return nil, nil, "Invalid user key in JWT token"
end
core.log.info("consumer: ", core.json.delay_encode(consumer))

local auth_secret, err = get_auth_secret(consumer.auth_conf)
if not auth_secret then
err = "failed to retrieve secrets, err: " .. err
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
return nil, nil, err
end
core.log.error(err)
return 503, {message = "failed to verify jwt"}
return nil, nil, "failed to verify jwt"
end
local claim_specs = jwt:get_default_validation_options(jwt_obj)
claim_specs.lifetime_grace_period = consumer.auth_conf.lifetime_grace_period
Expand All @@ -287,12 +289,30 @@ function _M.rewrite(conf, ctx)
if not jwt_obj.verified then
err = "failed to verify jwt: " .. jwt_obj.reason
if auth_utils.is_running_under_multi_auth(ctx) then
return 401, err
return nil, nil, "failed to verify jwt"
end
core.log.warn(err)
return 401, {message = "failed to verify jwt"}
return nil, nil, "failed to verify jwt"
end

return consumer, consumer_conf
end

function _M.rewrite(conf, ctx)
local consumer, consumer_conf, err = find_consumer(conf, ctx)
if not consumer then
if not conf.anonymous_consumer then
return 401, { message = err }
end
consumer, consumer_conf, err = consumer_mod.get_anonymous_consumer(conf.anonymous_consumer)
if not consumer then
core.log.error(err)
return 401, { message = "Invalid user authorization"}
end
end

core.log.info("consumer: ", core.json.delay_encode(consumer))

consumer_mod.attach_consumer(ctx, consumer, consumer_conf)
core.log.info("hit jwt-auth rewrite")
end
Expand Down
Loading
Loading