dockerfiles/proxy/access_by_openidc.lua (77 lines of code) (raw):
local cjson = require("cjson")
-- configs
local opts = {
claim_groups = ngx.var.oidc_claim_groups or "https://sso.mozilla.com/claim/groups",
client_id = ngx.var.oidc_client_id,
discovery = ngx.var.oidc_discovery or "https://auth.mozilla.auth0.com/.well-known/openid-configuration",
logout_path = ngx.var.oidc_logout_path,
redirect_uri = ngx.var.oidc_redirect_uri,
scope = ngx.var.oidc_scope or "openid email profile",
token_endpoint_auth_method = "client_secret_post",
}
-- we support the old client secret flow, as well as the PKCE flow as
-- recommended in OAuth 2.1, if oidc_client_secret isn't set, assume PKCE
if ngx.var.oidc_client_secret then
opts.client_secret = ngx.var.oidc_client_secret
else
opts.use_pkce = true
end
if ngx.var.oidc_hd then
opts.authorization_params = {hd=ngx.var.oidc_hd}
end
-- call authenticate for OpenID Connect user authentication
local res, err, target, session = require("resty.openidc").authenticate(opts)
session:close() -- explicitly close session to prevent timeouts around locking
if err then
ngx.status = 500
ngx.say(err)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
-- require hd matches if specified
if ngx.var.oidc_hd and res.id_token.hd ~= ngx.var.oidc_hd then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- if at least one email or group is specified, require user is in one of them
local validate_user, valid_user
for _, email in (ngx.var.oidc_emails or ""):gmatch("([^,]+),?") do
validate_user = true
if res.user.email == email then
valid_user = true
break
end
end
for _, group in (ngx.var.oidc_groups or ""):gmatch("([^,]+),?") do
validate_user = true
for _, usergroup in res.user.groups do
if usergroup == group then
valid_user = true
break
end
end
end
if validate_user and not valid_user then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- delete OIDC* headers from the request
for key, _ in pairs(ngx.req.get_headers()) do
if key:sub(1,4):upper() == "OIDC" then
ngx.req.clear_header(key)
end
end
-- set headers with user info
ngx.req.set_header("REMOTE-USER", res.id_token.user_id)
ngx.req.set_header("OIDC-CLAIM-ACCESS-TOKEN", res.access_token)
local function build_headers(t, name)
for k,v in pairs(t) do
k = k:gsub("_", "-")
-- unpack tables
if type(v) == "table" then
local j = cjson.encode(v)
ngx.req.set_header("OIDC-CLAIM-"..name..k, j)
else
ngx.req.set_header("OIDC-CLAIM-"..name..k, tostring(v))
end
end
end
build_headers(res.id_token, "ID-TOKEN-")
build_headers(res.user, "USER-PROFILE-")
-- Flat groups, useful for some RP's that won't read JSON
local usergroup
if res.user.groups then
usergroup = res.user.groups
else
usergroup = res.user[opts.claim_groups]
end
if type(usergroup) == "table" then
ngx.req.set_header("REMOTE-GROUPS", table.concat(usergroup, ","))
end