in apisix/plugins/openid-connect.lua [531:714]
function _M.rewrite(plugin_conf, ctx)
local conf = core.table.clone(plugin_conf)
if not (conf.timeout >= 1000 and conf.timeout % 1000 == 0) then
conf.timeout = conf.timeout * 1000
end
local path = ctx.var.request_uri
if not conf.redirect_uri then
local suffix = "/.apisix/redirect"
local uri = ctx.var.uri
if core.string.has_suffix(uri, suffix) then
conf.redirect_uri = uri
else
if string.sub(uri, -1, -1) == "/" then
conf.redirect_uri = string.sub(uri, 1, -2) .. suffix
else
conf.redirect_uri = uri .. suffix
end
end
core.log.debug("auto set redirect_uri: ", conf.redirect_uri)
end
if not conf.ssl_verify then
conf.ssl_verify = "no"
end
if path == (conf.logout_path or "/logout") then
local discovery, discovery_err = openidc.get_discovery_doc(conf)
if discovery_err then
core.log.error("OIDC access discovery url failed : ", discovery_err)
return 503
end
if conf.post_logout_redirect_uri and not discovery.end_session_endpoint then
conf.redirect_after_logout_uri = conf.post_logout_redirect_uri
end
end
local response, err, session, _
if conf.bearer_only or conf.introspection_endpoint or conf.public_key or conf.use_jwks then
local access_token, userinfo
response, err, access_token, userinfo = introspect(ctx, conf)
if err then
core.log.error("OIDC introspection failed: ", err)
return response
end
if response then
if conf.required_scopes then
local http_scopes = response.scope and split_scopes_by_space(response.scope) or {}
local is_authorized = required_scopes_present(conf.required_scopes, http_scopes)
if not is_authorized then
core.log.error("OIDC introspection failed: ", "required scopes not present")
local error_response = {
error = "required scopes " .. concat(conf.required_scopes, ", ") ..
" not present"
}
return 403, core.json.encode(error_response)
end
end
local audience_claim = core.table.try_read_attr(conf, "claim_validator",
"audience", "claim") or "aud"
local audience_value = response[audience_claim]
if core.table.try_read_attr(conf, "claim_validator", "audience", "required")
and not audience_value then
core.log.error("OIDC introspection failed: required audience (",
audience_claim, ") not present")
local error_response = { error = "required audience claim not present" }
return 403, core.json.encode(error_response)
end
if core.table.try_read_attr(conf, "claim_validator", "audience", "match_with_client_id")
and audience_value ~= nil then
local error_response = { error = "mismatched audience" }
local matched = false
if type(audience_value) == "table" then
for _, v in ipairs(audience_value) do
if conf.client_id == v then
matched = true
end
end
if not matched then
core.log.error("OIDC introspection failed: ",
"audience list does not contain the client id")
return 403, core.json.encode(error_response)
end
elseif conf.client_id ~= audience_value then
core.log.error("OIDC introspection failed: ",
"audience does not match the client id")
return 403, core.json.encode(error_response)
end
end
add_access_token_header(ctx, conf, access_token)
if userinfo and conf.set_userinfo_header then
core.request.set_header(ctx, "X-Userinfo",
ngx_encode_base64(core.json.encode(userinfo)))
end
end
end
if not response then
local unauth_action = conf.unauth_action
if unauth_action ~= "auth" then
unauth_action = "deny"
end
response, err, _, session = openidc.authenticate(conf, nil, unauth_action, conf.session)
if err then
if session then
session:close()
end
if err == "unauthorized request" then
if conf.unauth_action == "pass" then
return nil
end
return 401
end
core.log.error("OIDC authentication failed: ", err)
return 500
end
if response then
add_access_token_header(ctx, conf, response.access_token)
if response.id_token and conf.set_id_token_header then
local token = core.json.encode(response.id_token)
core.request.set_header(ctx, "X-ID-Token", ngx.encode_base64(token))
end
if response.user and conf.set_userinfo_header then
core.request.set_header(ctx, "X-Userinfo",
ngx_encode_base64(core.json.encode(response.user)))
end
if session.data.refresh_token and conf.set_refresh_token_header then
core.request.set_header(ctx, "X-Refresh-Token", session.data.refresh_token)
end
end
end
if session then
session:close()
end
end