local ngx = require("ngx") local b64 = require("ssso_base64") local util = require("ssso_util") local conf = require("ssso_config") local function get_request() local vars = ngx.var local request = { referer = vars.http_referer, host = vars.host, method = vars.request_method, uri = vars.request_uri, } if request.referer == "" then request.referer = nil end local target, qp = request.uri, {} local qm, _ = target:find("%?") if qm then qp = ngx.decode_args(target:sub(qm + 1)) target = target:sub(1, qm - 1) end request["target"] = target request["query_params"] = qp local https = vars.proxy_https or vars.https if https and https ~= "" then request["scheme"] = "https" else request["scheme"] = "http" end return request end local function with_post_parameters(req_data) ngx.req.read_body() local args, _ = ngx.req.get_post_args() if args then for key, val in pairs(args) do req_data.query_params[key] = val end end return req_data end local function str_starts_with(str, begin) local i, _ = str:find(util.str_to_pattern(begin)) return 1 == i end local function get_basic_auth() local header = ngx.var.Authentication if (not header) or (#header < 7) or (not str_starts_with(header, "Basic ")) then return nil, nil end local text, _ = b64.decode_base64(header:sub(7)) if not text then ngx.log(ngx.DEBUG, "Invalid Authentication header: " .. header) return nil, nil end local colon colon, _ = text:find(":") if not colon then return nil, nil end local login, password = "", "" if colon > 1 then login = text:sub(1, colon - 1) end if colon < #text then password = text:sub(colon + 1, #text) end return login, password end local function get_jws_cookie() return ngx.var.cookie_SSSO_TOKEN end local function set_jws_cookie(jws, tslimit) ngx.header["Set-Cookie"] = "SSSO_TOKEN=" .. jws .. "; Path=/; Expires=" .. ngx.cookie_time(tslimit) .. "; Secure" end local function get_seconds_since_epoch() return math.floor(ngx.now()) end local function add_cookie(name, value) local cookie = name .. "=" .. value local old_cookie = ngx.var.http_cookie if old_cookie and old_cookie ~= "" then cookie = old_cookie .. "; " .. cookie end ngx.log(ngx.DEBUG, "Overriding request Cookie header: " .. cookie) ngx.req.set_header("Cookie", cookie) end local function add_header(name, value) ngx.log(ngx.DEBUG, "Setting request " .. name .. " header: " .. value) ngx.req.set_header(name, value) end local function has_method(req_data, method) return string.upper(method) == string.upper(req_data.method) end local function is(req_data, url) return req_data.target == url end local function matches(req_data, lua_pattern) return req_data.target:match(lua_pattern) end local function starts_with(req_data, prefix) return str_starts_with(req_data.target, prefix) end local function has_param(req_data, param, value) return req_data.query_params[param] ~= nil and (value == nil or req_data.query_params[param] == value) end local function answer_not_found(req_data) return ngx.exit(404) end local function answer_unexpected_error() ngx.log(ngx.ERROR, "Unexpected Simple-SSO error.") return ngx.exit(500) end local function redirect_to_page(uri) return ngx.redirect("https://" .. conf.get_sso_host() .. uri, 302) end local function redirect_to_login(req_data, status) return ngx.redirect("https://" .. conf.get_sso_host() .. conf.get_sso_prefix() .. "/login?back=" .. ngx.escape_uri(req_data.uri) .. "&cause=" .. tostring(status), 307) end local function redirect_to_portal() return ngx.redirect("https://" .. conf.get_sso_host() .. conf.get_sso_prefix() .. "/portal", 307) end local function return_contents(contents, mime_and_charset) ngx.header["Content-Type"] = mime_and_charset ngx.header["Content-Length"] = tostring(#contents) ngx.header["Cache-Control"] = "no-store,max-age=0" ngx.say(contents) -- TODO: CSRF return ngx.exit(200) end local function forward_request(req_data) return end return { add_cookie = add_cookie, add_header = add_header, answer_not_found = answer_not_found, forward_request = forward_request, get_basic_auth = get_basic_auth, get_jws_cookie = get_jws_cookie, get_request = get_request, get_seconds_since_epoch = get_seconds_since_epoch, has_method = has_method, has_param = has_param, is = is, matches = matches, redirect_to_login = redirect_to_login, redirect_to_page = redirect_to_page, redirect_to_portal = redirect_to_portal, return_contents = return_contents, set_jws_cookie = set_jws_cookie, starts_with = starts_with, answer_unexpected_error = answer_unexpected_error, with_post_parameters = with_post_parameters, }