103 lines
3.5 KiB
Lua
103 lines
3.5 KiB
Lua
-- The MIT License (MIT)
|
|
--
|
|
-- Copyright (c) 2018 Tim Düsterhus
|
|
--
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
-- of this software and associated documentation files (the "Software"), to deal
|
|
-- in the Software without restriction, including without limitation the rights
|
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
-- copies of the Software, and to permit persons to whom the Software is
|
|
-- furnished to do so, subject to the following conditions:
|
|
--
|
|
-- The above copyright notice and this permission notice shall be included in all
|
|
-- copies or substantial portions of the Software.
|
|
--
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
-- SOFTWARE.
|
|
|
|
local http = require("socket.http")
|
|
|
|
core.register_action("auth-request", { "http-req" }, function(txn, be, path)
|
|
txn:set_var("txn.auth_response_successful", false)
|
|
|
|
-- Check whether the given backend exists.
|
|
if core.backends[be] == nil then
|
|
txn:Alert("Unknown auth-request backend '" .. be .. "'")
|
|
txn:set_var("txn.auth_response_code", 500)
|
|
return
|
|
end
|
|
|
|
-- Check whether the given backend has servers that
|
|
-- are not `DOWN`.
|
|
local addr = nil
|
|
for name, server in pairs(core.backends[be].servers) do
|
|
local status = server:get_stats()['status']
|
|
if status == "no check" or status:find("UP") == 1 then
|
|
addr = server:get_addr()
|
|
break
|
|
end
|
|
end
|
|
if addr == nil then
|
|
txn:Warning("No servers available for auth-request backend: '" .. be .. "'")
|
|
txn:set_var("txn.auth_response_code", 500)
|
|
return
|
|
end
|
|
|
|
-- Transform table of request headers from haproxy's to
|
|
-- socket.http's format.
|
|
local headers = {}
|
|
for header, values in pairs(txn.http:req_get_headers()) do
|
|
if header ~= 'content-length' then
|
|
for i, v in pairs(values) do
|
|
if headers[header] == nil then
|
|
headers[header] = v
|
|
else
|
|
headers[header] = headers[header] .. ", " .. v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Make request to backend.
|
|
local b, c, h = http.request {
|
|
url = "http://" .. addr .. path,
|
|
headers = headers,
|
|
create = core.tcp,
|
|
-- Disable redirects, because DNS does not work here.
|
|
redirect = false,
|
|
-- We do not check body, so HEAD
|
|
method = "HEAD",
|
|
}
|
|
|
|
-- Check whether we received a valid HTTP response.
|
|
if b == nil then
|
|
txn:Warning("Failure in auth-request backend '" .. be .. "': " .. c)
|
|
txn:set_var("txn.auth_response_code", 500)
|
|
return
|
|
end
|
|
|
|
txn:set_var("txn.auth_response_code", c)
|
|
|
|
-- 2xx: Allow request.
|
|
if 200 <= c and c < 300 then
|
|
if h["remote-user"] then
|
|
txn:set_var("txn.auth_user", h["remote-user"])
|
|
end
|
|
if h["remote-groups"] then
|
|
txn:set_var("txn.auth_groups", h["remote-groups"])
|
|
end
|
|
txn:set_var("txn.auth_response_successful", true)
|
|
-- Don't allow other codes.
|
|
-- Codes with Location: Passthrough location at redirect.
|
|
elseif c == 301 or c == 302 or c == 303 or c == 307 or c == 308 then
|
|
txn:set_var("txn.auth_response_location", h["location"])
|
|
-- 401 / 403: Do nothing, everything else: log.
|
|
elseif c ~= 401 and c ~= 403 then
|
|
txn:Warning("Invalid status code in auth-request backend '" .. be .. "': " .. c)
|
|
end
|
|
end, 2) |