246 lines
6.4 KiB
Lua
246 lines
6.4 KiB
Lua
local json = require("cjson.safe")
|
|
local id = require("ssso_identity")
|
|
local nginx = require("ssso_nginx")
|
|
|
|
local known_private_re = {}
|
|
local known_sites = {}
|
|
|
|
local function load_sites(prefix)
|
|
local f, site
|
|
local ls = assert(io.popen("/bin/ls -f1Nb \"" .. prefix .. "/sites\"/*.json", "r"), "popen is required")
|
|
for name in ls:lines() do
|
|
f = assert(io.open(name, "r"), "File " .. name .. " cannot be read")
|
|
site = assert(json.decode(f:read("*all")))
|
|
f:close()
|
|
table.insert(known_sites, name)
|
|
for _, pat in ipairs(site.patterns) do
|
|
if not pat.public then
|
|
for _, r in ipairs(pat.lua_regex) do
|
|
table.insert(known_private_re, r)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
ls:close()
|
|
end
|
|
|
|
local function is_known_private(req_data)
|
|
for _, r in ipairs(known_private_re) do
|
|
if req_data:matches(r) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function handle_request(req_data, auth)
|
|
if auth then
|
|
for _, site in ipairs(auth.ok) do
|
|
for _, r in ipairs(site.r) do
|
|
if req_data:matches(r) then
|
|
for _, a in ipairs(site.a) do
|
|
if a[1] == "C" then
|
|
nginx.add_cookie(a[2], auth:format(a[3]))
|
|
elseif a[1] == "H" then
|
|
nginx.add_header(a[2], auth:format(a[3]))
|
|
end
|
|
end
|
|
return nginx.forward_request(req_data)
|
|
end
|
|
end
|
|
end
|
|
for _, r in ipairs(auth.ko) do
|
|
if req_data:matches(r) then
|
|
return nginx.redirect_to_login(req_data, 403)
|
|
end
|
|
end
|
|
return nginx.forward_request(req_data)
|
|
elseif is_known_private(req_data) then
|
|
return nginx.redirect_to_login(req_data, 401)
|
|
else
|
|
return nginx.forward_request(req_data)
|
|
end
|
|
end
|
|
|
|
local function format_pattern(pattern)
|
|
local a_type
|
|
local ok = {
|
|
r = pattern.lua_regex or {},
|
|
a = {},
|
|
}
|
|
for _, action in ipairs(pattern.actions or {}) do
|
|
if action.type == "header" then
|
|
a_type = "H"
|
|
elseif action.type == "cookie" then
|
|
a_type = "C"
|
|
else
|
|
a_type = nil
|
|
end
|
|
if a_type then
|
|
table.insert(ok.a, {a_type, action.name, action.value})
|
|
end
|
|
end
|
|
return ok
|
|
end
|
|
|
|
local class__profile = {}
|
|
setmetatable(class__profile, {__index = id.class__identity})
|
|
|
|
function class__profile:build(delegate_identity, ok_list, ko_list)
|
|
local profile = {
|
|
delegate = delegate_identity,
|
|
ok = ok_list,
|
|
ko = ko_list,
|
|
}
|
|
setmetatable(profile, {__index = self})
|
|
return profile
|
|
end
|
|
|
|
function class__profile:build_from_lists(user, password, name, email, ok_list, ko_list)
|
|
local delegate_identity = id.class__identity:build(user, password, name, email)
|
|
return self:build(delegate_identity, ok_list, ko_list)
|
|
end
|
|
|
|
function class__profile:build_from_conf(user, password, name, email)
|
|
local f, site, go_on
|
|
local ok_list = {}
|
|
local ko_list = {}
|
|
local delegate_identity = id.class__identity:build(user, password, name, email)
|
|
for _, known in ipairs(known_sites) do
|
|
f = io.open(known, "r")
|
|
if f then
|
|
site = json.decode(f:read("*all"))
|
|
f:close()
|
|
for _, pat in ipairs(site.patterns) do
|
|
go_on = true
|
|
for _, denied in ipairs(pat.deny or {}) do
|
|
if denied == user then
|
|
go_on = false
|
|
for _, re in ipairs(pat.lua_regex) do
|
|
table.insert(ko_list, re)
|
|
end
|
|
break
|
|
end
|
|
end
|
|
if go_on then
|
|
if pat.public then
|
|
local ok = format_pattern(pat)
|
|
table.insert(ok_list, ok)
|
|
else
|
|
for _, allowed in ipairs(pat.allow or {}) do
|
|
if allowed == "*" or allowed == user then
|
|
local ok = format_pattern(pat)
|
|
table.insert(ok_list, ok)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return self:build(delegate_identity, ok_list, ko_list)
|
|
end
|
|
|
|
function class__profile:email()
|
|
return self.delegate:email()
|
|
end
|
|
|
|
function class__profile:name()
|
|
return self.delegate:name()
|
|
end
|
|
|
|
function class__profile:user()
|
|
return self.delegate:user()
|
|
end
|
|
|
|
function class__profile:format(template)
|
|
return self.delegate:format(template)
|
|
end
|
|
|
|
function class__profile:serialize()
|
|
local ser_s = ""
|
|
for _, site in ipairs(self.ok or {}) do
|
|
for _, r in ipairs(site.r) do
|
|
ser_s = ser_s .. r .. "\029"
|
|
end
|
|
for _, a in ipairs(site.a) do
|
|
ser_s = ser_s .. a[1] .. a[2] .. "=" .. a[3] .. "\028"
|
|
end
|
|
ser_s = ser_s .. "\031"
|
|
end
|
|
for _, r in ipairs(self.ko or {}) do
|
|
ser_s = ser_s .. r .. "\030"
|
|
end
|
|
return ser_s .. "\026" .. self.delegate:serialize()
|
|
end
|
|
|
|
function class__profile:deserialize(ser)
|
|
local ok_list = {}
|
|
local ko_list = {}
|
|
ser = ser:gsub("^(.-)\026", function (ser_sites)
|
|
ser_sites = ser_sites:gsub("(.-)\031", function (ser_ok)
|
|
local ok = {
|
|
r = {},
|
|
a = {},
|
|
}
|
|
ser_ok = ser_ok:gsub("(.-)\029", function(r) table.insert(ok.r, r); return "" end)
|
|
ser_ok:gsub("(.)([^=]-)=(.-)\028", function(t, n, v) table.insert(ok.a, {t, n, v}) end)
|
|
table.insert(ok_list, ok)
|
|
return ""
|
|
end)
|
|
ser_sites = ser_sites:gsub("(.-)\030", function (ko)
|
|
table.insert(ko_list, ko)
|
|
return ""
|
|
end)
|
|
return ""
|
|
end)
|
|
local delegate_identity = id.class__identity:deserialize(ser)
|
|
return self:build(delegate_identity, ok_list, ko_list)
|
|
end
|
|
|
|
function class__profile:authorized_links()
|
|
local links = {}
|
|
local f, site, go_on
|
|
local user = self:user()
|
|
for _, name in ipairs(known_sites) do
|
|
f = io.open(name, "r")
|
|
if f then
|
|
site = json.decode(f:read("*all"))
|
|
f:close()
|
|
for _, pat in ipairs(site.patterns) do
|
|
go_on = true
|
|
for _, denied in ipairs(pat.deny or {}) do
|
|
if denied == user then
|
|
go_on = false
|
|
break
|
|
end
|
|
end
|
|
if go_on then
|
|
if pat.public then
|
|
for link, label in pairs(pat.portal or {}) do
|
|
table.insert(links, {link = link, label = label})
|
|
end
|
|
else
|
|
for _, allowed in ipairs(pat.allow or {}) do
|
|
if allowed == "*" or allowed == user then
|
|
for link, label in pairs(pat.portal or {}) do
|
|
table.insert(links, {link = link, label = label})
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return links
|
|
end
|
|
|
|
return {
|
|
class__profile = class__profile,
|
|
handle_request = handle_request,
|
|
load_sites = load_sites,
|
|
}
|