Limited support for app-logout on SSO-logout

unstable
Y 2017-09-22 20:07:02 +02:00
parent 049ad9f48a
commit de20c91871
6 changed files with 96 additions and 8 deletions

View File

@ -164,6 +164,10 @@ Array of regular expressions to be matched against URLS **and** URIs and their r
2-level array containing usernames and their allowed URLs along with an App name (**example**: `{ "kload": { "kload.fr/myapp/": "My App" } }`)
#### logout
Associative array; when logging out of SSOwat, any existing cookie that is found as a key of this array triggers the associated logout URL. This only works on `http[s]://[*.]portal_domaini/`, though. (**example**: `{ "dcxd": "https://example.org/dotclear/admin/index.php?logout=1" }`)
#### default_language
Language code used by default in views (**default**: `en`)

View File

@ -42,6 +42,15 @@ end
ngx.header["X-SSO-WAT"] = "You've just been SSOed"
--
-- 0. LOGOUT if requested, but only if logged in
--
local logout_ck = ngx.var.cookie_SSOwFullLogout
if logout_ck and logout_ck ~= "" and hlp.is_logged_in() then
return hlp.logout()
end
--
-- 1. LOGIN
--

View File

@ -26,5 +26,8 @@
"example.org/myapp": "My other domain App",
"example.com/myapp2": "My second App"
}
},
"logout": {
"dcxd": "https://example.org/dotclear/admin/index.php?logout=1"
}
}

View File

@ -43,7 +43,7 @@ function get_config()
portal_scheme = "https",
portal_path = "/ssowat/",
local_portal_domain = "yunohost.local",
domains = { conf["portal_domain"], "yunohost.local" },
domains = { "yunohost.local", conf["portal_domain"] },
session_timeout = 60 * 60 * 24, -- one day
session_max_timeout = 60 * 60 * 24 * 7, -- one week
login_arg = "sso_login",
@ -53,6 +53,7 @@ function get_config()
ldap_enforce_crypt = true,
skipped_urls = {},
users = {},
logout = {},
ldap_attributes = {"uid", "givenname", "sn", "cn", "homedirectory", "mail", "maildrop"},
additional_headers = {["Remote-User"] = "uid"},
allow_mail_authentication = true,

8
headers.lua Normal file
View File

@ -0,0 +1,8 @@
-- Redirect to the SSO if logout is in progress
if ngx.ctx.SSOwFullLogout then
local next_cookie, back_url = ngx.ctx.SSOwFullLogout:match('^(.-)|(http.+)$')
ngx.log(ngx.DEBUG, "LOGOUT STEP DONE; next: "..next_cookie..", back to: "..back_url)
ngx.status = ngx.HTTP_TEMPORARY_REDIRECT
ngx.header['Set-Cookie'] = {next_cookie}
ngx.header.Location = back_url
end

View File

@ -55,6 +55,10 @@ function string.ends(String, End)
return End=='' or string.sub(String, -string.len(End)) == End
end
-- Escape special characters in a string
function string.pcre_escape(String)
return ngx.re.gsub(String, '([]({+?\\*.})[])', '\\$1')
end
-- Find a string by its translate key in the right language
function t(key)
@ -177,7 +181,8 @@ function delete_cookie()
ngx.header["Set-Cookie"] = {
"SSOwAuthUser="..cookie_str,
"SSOwAuthHash="..cookie_str,
"SSOwAuthExpire="..cookie_str
"SSOwAuthExpire="..cookie_str,
"SSOwFullLogout="..cookie_str
}
end
end
@ -883,18 +888,76 @@ end
-- It deletes session cached information to invalidate client side cookie
-- information.
function logout()
conf = config.get_config()
-- We need this call since we are in a POST request
local args = ngx.req.get_uri_args()
-- Delete user cookie if logged in (that should always be the case)
if is_logged_in() then
delete_cookie()
cache:delete("session_"..authUser)
cache:delete(authUser.."-"..conf["ldap_identifier"]) -- Ugly trick to reload cache
flash("info", t("logged_out"))
-- Login if not logged in (that should always be the case)
if not is_logged_in() then
return redirect(conf.portal_url)
end
-- Loop over session cookies.
-- For now, this will only work for domains under that of SSOwat.
-- The SSOwFullLogout cookie always contains the next cookie to check.
local cur_logout_step = ngx.var.cookie_SSOwFullLogout or '*'
local url_re = "^(?:https?://(?:[^/]+\\.)?"..string.pcre_escape(conf['portal_domain'])..")?/"
local sess_ck
local sess_ck_val
local logout_url
local read_next_and_proceed = false
local cookie_str = "; Domain=."..conf['portal_domain']..
"; Path=/"..
"; Expires="..os.date("%a, %d %b %Y %X UTC;", ngx.req.start_time() + 60)
for sess_ck, logout_url in pairs(conf['logout']) do
ngx.log(ngx.DEBUG, "LOGOUT step="..cur_logout_step..", evaluate="..sess_ck)
-- Run a logout URL, but point to the next, to avoid a loop
if read_next_and_proceed then
ngx.ctx.SSOwFullLogout = "SSOwFullLogout="..sess_ck..cookie_str..'|'..conf.portal_url
ngx.log(ngx.DEBUG, "LOGOUT pass: "..req_data['request_uri'])
return pass()
-- A cookie must be checked; do so
elseif cur_logout_step == '*' or cur_logout_step == sess_ck then
if ngx.re.match(logout_url, url_re) then
-- Not the right URI for this cookie; redirect
if string.gsub(logout_url, '^https?://[^/]+/', '/') ~= req_data['request_uri'] then
ngx.header["Set-Cookie"] = {"SSOwFullLogout="..sess_ck..cookie_str}
ngx.log(ngx.DEBUG, "LOGOUT visit: "..logout_url)
return redirect(logout_url)
end
sess_ck_val = ngx.var["cookie_"..sess_ck]
-- The cookie must be deleted
if sess_ck_val and sess_ck_val ~= "" then
read_next_and_proceed = true
-- No cookie; check next
else
ngx.log(ngx.DEBUG, "LOGOUT skip")
cur_logout_step = '*'
end
else
-- This URL is not handled :-(
ngx.log(ngx.DEBUG, "LOGOUT unhandled")
cur_logout_step = '*'
end
end
end
if read_next_and_proceed then
ngx.ctx.SSOwFullLogout = "SSOwFullLogout=0"..cookie_str..'|'..conf.portal_url
ngx.log(ngx.DEBUG, "LOGOUT pass: "..req_data['request_uri'])
return pass()
end
delete_cookie()
cache:delete("session_"..authUser)
cache:delete(authUser.."-"..conf["ldap_identifier"]) -- Ugly trick to reload cache
flash("info", t("logged_out"))
-- Redirect to portal anyway
return redirect(conf.portal_url)
end