Enhance auth.lua with OpenID Connect login flow, token validation using introspection, session handling, and improved error responses.
This commit is contained in:
71
auth.lua
71
auth.lua
@@ -1,4 +1,6 @@
|
|||||||
local openidc = require("resty.openidc")
|
local openidc = require("resty.openidc")
|
||||||
|
local http = require("resty.http")
|
||||||
|
local cjson = require("cjson")
|
||||||
|
|
||||||
local client_secret = os.getenv("KEYCLOAK_CLIENT_SECRET")
|
local client_secret = os.getenv("KEYCLOAK_CLIENT_SECRET")
|
||||||
if not client_secret then
|
if not client_secret then
|
||||||
@@ -7,46 +9,57 @@ if not client_secret then
|
|||||||
end
|
end
|
||||||
|
|
||||||
local opts = {
|
local opts = {
|
||||||
|
redirect_uri_path = "/redirect_uri",
|
||||||
discovery = "https://kc.boomlab.party/realms/rhein-sw/.well-known/openid-configuration",
|
discovery = "https://kc.boomlab.party/realms/rhein-sw/.well-known/openid-configuration",
|
||||||
client_id = "demo-sso",
|
client_id = "demo-sso",
|
||||||
client_secret = client_secret,
|
client_secret = client_secret,
|
||||||
|
scope = "openid email profile",
|
||||||
ssl_verify = "no"
|
ssl_verify = "no"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Extract token from session or request
|
-- Step 1: login flow
|
||||||
local session = require("resty.session").start()
|
local auth_res, auth_err = openidc.authenticate(opts)
|
||||||
local access_token = session.data.access_token
|
if auth_err then
|
||||||
|
|
||||||
if not access_token then
|
|
||||||
-- fallback: try Authorization header
|
|
||||||
local auth_header = ngx.var.http_Authorization
|
|
||||||
if auth_header and auth_header:find("Bearer ") == 1 then
|
|
||||||
access_token = auth_header:sub(8)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not access_token then
|
|
||||||
ngx.status = 401
|
|
||||||
ngx.say("Missing access token")
|
|
||||||
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Introspect the token
|
|
||||||
local res, err = openidc.introspect(opts, access_token)
|
|
||||||
|
|
||||||
if err then
|
|
||||||
ngx.status = 403
|
ngx.status = 403
|
||||||
ngx.say("Token introspection failed: " .. err)
|
ngx.say("Authentication failed: " .. auth_err)
|
||||||
ngx.exit(ngx.HTTP_FORBIDDEN)
|
ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not res.active then
|
-- Step 2: get token from session or result
|
||||||
|
local session = require("resty.session").start()
|
||||||
|
local access_token = session.data.access_token or auth_res.access_token
|
||||||
|
|
||||||
|
if not access_token then
|
||||||
ngx.status = 401
|
ngx.status = 401
|
||||||
ngx.say("Session expired or revoked")
|
ngx.say("Access token not available")
|
||||||
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Optionally set headers for upstream
|
-- Step 3: validate token on each request via introspection
|
||||||
ngx.req.set_header("X-User", res.username or "")
|
local httpc = http.new()
|
||||||
ngx.req.set_header("X-Email", res.email or "")
|
local res, err = httpc:request_uri("https://kc.boomlab.party/realms/rhein-sw/protocol/openid-connect/token/introspect", {
|
||||||
ngx.status = 204
|
method = "POST",
|
||||||
|
body = "token=" .. access_token .. "&client_id=" .. opts.client_id .. "&client_secret=" .. opts.client_secret,
|
||||||
|
headers = {
|
||||||
|
["Content-Type"] = "application/x-www-form-urlencoded"
|
||||||
|
},
|
||||||
|
ssl_verify = false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not res or res.status ~= 200 then
|
||||||
|
ngx.status = 500
|
||||||
|
ngx.say("Failed to introspect token: " .. (err or (res and res.body or "unknown error")))
|
||||||
|
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
||||||
|
end
|
||||||
|
|
||||||
|
local token_info = cjson.decode(res.body)
|
||||||
|
if not token_info.active then
|
||||||
|
local session = require("resty.session").start()
|
||||||
|
session:destroy()
|
||||||
|
return openidc.authenticate(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Step 4: allow proxying the request
|
||||||
|
ngx.req.set_header("X-User", auth_res.user.preferred_username or "")
|
||||||
|
ngx.req.set_header("X-Email", auth_res.user.email or "")
|
||||||
|
-- Don't return anything here — let NGINX continue to proxy the request
|
||||||
|
|||||||
Reference in New Issue
Block a user