diff --git a/README.md b/README.md index af3e6b3..e2f73cd 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ If you use YunoHost, you may want to edit the `/etc/ssowat/conf.json.persistent` ## Available parameters -These are the SSOwat's configuration parameters. Only `portal_domain` and `skipped_urls` are required, but it is recommended to know the others to fully understand what you can do with SSOwat. +These are the SSOwat's configuration parameters. Only `portal_domain` is required, but it is recommended to know the others to fully understand what you can do with SSOwat. #### portal_domain @@ -74,11 +74,11 @@ Domain of the authentication portal. It has to be a domain, IP addresses will no #### portal_path -URI of the authentication portal (**default**: `/ssowat`) +URI of the authentication portal (**default**: `/ssowat/`). This path **must** end with “`/`”. #### portal_port -Web port of the authentication portal (**default**: `443`) +Web port of the authentication portal (**default**: `443` for `https`, `80` for `http`) #### portal_scheme @@ -86,7 +86,7 @@ Whether authentication should use secure connection or not (**default**: `https` #### domains -List of handle domains (**default**: similar to `portal_domain`) +List of handled domains (**default**: similar to `portal_domain`) #### ldap_host @@ -104,6 +104,10 @@ LDAP user identifier (**default**: `uid`) User's attributes to fetch from LDAP (**default**: `["uid", "givenname", "sn", "cn", "homedirectory", "mail", "maildrop"]`) +#### ldap_enforce_crypt + +Let SSOwat re-encrypt weakly-encrypted LDAP passwords into the safer sha-512 (crypt) (**default**: `true`) + #### allow_mail_authentication Whether users can authenticate with their mail address (**default**: `true`) @@ -160,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`) diff --git a/access.lua b/access.lua index 0967eca..f51cc4a 100644 --- a/access.lua +++ b/access.lua @@ -6,6 +6,28 @@ -- request is handled: redirected, forbidden, bypassed or served. -- +-- Initialize and get configuration +local conf = config.get_config() + +-- Import helpers +local hlp = require "helpers" + +-- Store the request data +req_data = { + request_uri = ngx.var.request_uri, + uri = ngx.var.uri, + https = ngx.var.proxy_https or ngx.var.https, + host = ngx.var.host, + request_method = ngx.var.request_method, + http_referer = ngx.var.http_referer +} +if req_data["https"] and req_data["https"] ~= "" then + req_data["scheme"] = "https" +else + req_data["scheme"] = "http" +end +hlp.set_req_data(req_data) + -- Get the `cache` persistent shared table local cache = ngx.shared.cache @@ -16,16 +38,19 @@ if not srvkey then cache:add("srvkey", srvkey) end --- Initialize and get configuration -local conf = config.get_config() - --- Import helpers -local hlp = require "helpers" - -- Just a note for the client to know that he passed through the SSO 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 -- @@ -34,7 +59,7 @@ ngx.header["X-SSO-WAT"] = "You've just been SSOed" -- If the `sso_login` URI argument is set, try a cross-domain authentication -- with the token passed as argument -- -if ngx.var.host ~= conf["portal_domain"] and ngx.var.request_method == "GET" then +if req_data["host"] ~= conf["portal_domain"] and req_data["request_method"] == "GET" then uri_args = ngx.req.get_uri_args() if uri_args[conf.login_arg] then cda_key = uri_args[conf.login_arg] @@ -43,13 +68,13 @@ if ngx.var.host ~= conf["portal_domain"] and ngx.var.request_method == "GET" the -- a CDA key user = cache:get("CDA|"..cda_key) if user then - hlp.set_auth_cookie(user, ngx.var.host) - ngx.log(ngx.NOTICE, "Cross-domain authentication: "..user.." connected on "..ngx.var.host) + hlp.set_auth_cookie(user, req_data["host"]) + ngx.log(ngx.NOTICE, "Cross-domain authentication: "..user.." connected on "..req_data["host"]) cache:delete("CDA|"..cda_key) end uri_args[conf.login_arg] = nil - return hlp.redirect(ngx.var.uri..hlp.uri_args_string(uri_args)) + return hlp.redirect(req_data['request_uri']) end end @@ -62,20 +87,16 @@ end -- If the URL matches the portal URL, serve a portal file or proceed to a -- portal operation -- -if ngx.var.host == conf["portal_domain"] - and hlp.string.starts(ngx.var.uri, string.sub(conf["portal_path"], 1, -2)) +if req_data["host"] == conf["portal_domain"] + and hlp.string.starts(req_data['request_uri'], string.sub(conf["portal_path"], 1, -2)) then -- `GET` method will serve a portal file - if ngx.var.request_method == "GET" then - - -- Force portal scheme - if ngx.var.scheme ~= conf["portal_scheme"] then - return hlp.redirect(conf.portal_url) - end + if req_data["request_method"] == "GET" then -- Add a trailing `/` if not present - if ngx.var.uri.."/" == conf["portal_path"] then + if req_data['request_uri'].."/" == conf["portal_path"] then + ngx.log(ngx.DEBUG, "REDIRECT MISSING /") return hlp.redirect(conf.portal_url) end @@ -98,6 +119,7 @@ then if string.match(back_url, "(.*)\n") then hlp.flash("fail", hlp.t("redirection_error_invalid_url")) ngx.log(ngx.ERR, "Redirection url is invalid") + ngx.log(ngx.DEBUG, "REDIRECT \\N FOUND") return hlp.redirect(conf.portal_url) end @@ -124,7 +146,7 @@ then -- In case the `back_url` is not on the same domain than the -- current one, create a redirection with a CDA key - local ngx_host_escaped = ngx.var.host:gsub("-", "%%-") -- escape dash for pattern matching + local ngx_host_escaped = req_data["host"]:gsub("-", "%%-") -- escape dash for pattern matching if not string.match(back_url, "^http[s]?://"..ngx_host_escaped.."/") and not string.match(back_url, ".*"..conf.login_arg.."=%d+$") then local cda_key = hlp.set_cda_key() @@ -136,35 +158,43 @@ then back_url = back_url.."sso_login="..cda_key end + ngx.log(ngx.DEBUG, "REDIRECT BACK URL REQUESTED") return hlp.redirect(back_url) -- In case we want to serve portal login or assets for portal, just -- serve it elseif hlp.is_logged_in() - or ngx.var.uri == conf["portal_path"] - or (hlp.string.starts(ngx.var.uri, conf["portal_path"].."assets") - and (not ngx.var.http_referer - or hlp.string.starts(ngx.var.http_referer, conf.portal_url))) + or req_data['request_uri'] == conf["portal_path"] + or hlp.string.starts(req_data['request_uri'], conf["portal_path"].."?") + or (hlp.string.starts(req_data['request_uri'], conf["portal_path"].."assets") + and (not req_data["http_referer"] + or hlp.string.starts(req_data["http_referer"], conf.portal_url))) then - return hlp.serve(ngx.var.uri) + local uri = req_data['request_uri'] + local i, _ = string.find(uri, '?') + if i then + uri = string.sub(uri, 1, i-1) + end + return hlp.serve(uri) -- If all the previous cases have failed, redirect to portal else hlp.flash("info", hlp.t("please_login")) + ngx.log(ngx.DEBUG, "REDIRECT GET CATCHALL…") return hlp.redirect(conf.portal_url) end -- `POST` method is basically use to achieve editing operations - elseif ngx.var.request_method == "POST" then + elseif req_data["request_method"] == "POST" then -- CSRF protection, only proceed if we are editing from the same -- domain - if hlp.string.starts(ngx.var.http_referer, conf.portal_url) then - if hlp.string.ends(ngx.var.uri, conf["portal_path"].."password.html") - or hlp.string.ends(ngx.var.uri, conf["portal_path"].."edit.html") + if hlp.string.starts(req_data["http_referer"], conf.portal_url) then + if hlp.string.ends(req_data["uri"], conf["portal_path"].."password.html") + or hlp.string.ends(req_data["uri"], conf["portal_path"].."edit.html") then return hlp.edit_user() else @@ -173,6 +203,7 @@ then else -- Redirect to portal hlp.flash("fail", hlp.t("please_login_from_portal")) + ngx.log(ngx.DEBUG, "REDIRECT POST CATCHALL…") return hlp.redirect(conf.portal_url) end end @@ -191,17 +222,17 @@ function detect_redirection(redirect_url) or hlp.string.starts(redirect_url, "https://") then return hlp.redirect(redirect_url) elseif hlp.string.starts(redirect_url, "/") then - return hlp.redirect(ngx.var.scheme.."://"..ngx.var.host..redirect_url) + return hlp.redirect(req_data["scheme"].."://"..req_data["host"]..redirect_url) else - return hlp.redirect(ngx.var.scheme.."://"..redirect_url) + return hlp.redirect(req_data["scheme"].."://"..redirect_url) end end if conf["redirected_urls"] then for url, redirect_url in pairs(conf["redirected_urls"]) do - if url == ngx.var.host..ngx.var.uri..hlp.uri_args_string() - or url == ngx.var.scheme.."://"..ngx.var.host..ngx.var.uri..hlp.uri_args_string() - or url == ngx.var.uri..hlp.uri_args_string() then + if url == req_data["host"]..req_data['request_uri'] + or url == req_data["scheme"].."://"..req_data["host"]..req_data['request_uri'] + or url == req_data['request_uri'] then detect_redirection(redirect_url) end end @@ -209,9 +240,9 @@ end if conf["redirected_regex"] then for regex, redirect_url in pairs(conf["redirected_regex"]) do - if string.match(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), regex) - or string.match(ngx.var.scheme.."://"..ngx.var.host..ngx.var.uri..hlp.uri_args_string(), regex) - or string.match(ngx.var.uri..hlp.uri_args_string(), regex) then + if string.match(req_data["host"]..req_data['request_uri'], regex) + or string.match(req_data["scheme"].."://"..req_data["host"]..req_data['request_uri'], regex) + or string.match(req_data['request_uri'], regex) then detect_redirection(redirect_url) end end @@ -236,14 +267,14 @@ function is_protected() end for _, url in ipairs(conf["protected_urls"]) do - if hlp.string.starts(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), url) - or hlp.string.starts(ngx.var.uri..hlp.uri_args_string(), url) then + if hlp.string.starts(req_data["host"]..req_data['request_uri'], url) + or hlp.string.starts(req_data['request_uri'], url) then return true end end for _, regex in ipairs(conf["protected_regex"]) do - if string.match(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), regex) - or string.match(ngx.var.uri..hlp.uri_args_string(), regex) then + if string.match(req_data["host"]..req_data['request_uri'], regex) + or string.match(req_data['request_uri'], regex) then return true end end @@ -262,8 +293,8 @@ end if conf["skipped_urls"] then for _, url in ipairs(conf["skipped_urls"]) do - if (hlp.string.starts(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), url) - or hlp.string.starts(ngx.var.uri..hlp.uri_args_string(), url)) + if (hlp.string.starts(req_data["host"]..req_data['request_uri'], url) + or hlp.string.starts(req_data['request_uri'], url)) and not is_protected() then return hlp.pass() end @@ -272,8 +303,8 @@ end if conf["skipped_regex"] then for _, regex in ipairs(conf["skipped_regex"]) do - if (string.match(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), regex) - or string.match(ngx.var.uri..hlp.uri_args_string(), regex)) + if (string.match(req_data["host"]..req_data['request_uri'], regex) + or string.match(req_data['request_uri'], regex)) and not is_protected() then return hlp.pass() end @@ -291,18 +322,19 @@ end -- if hlp.is_logged_in() then - if string.match(ngx.var.uri, "^/ynhpanel.js$") then + if string.match(req_data['request_uri'], "^/ynhpanel.js$") then hlp.serve("/yunohost/sso/assets/js/ynhpanel.js") end - if string.match(ngx.var.uri, "^/ynhpanel.css$") then + if string.match(req_data['request_uri'], "^/ynhpanel.css$") then hlp.serve("/yunohost/sso/assets/css/ynhpanel.css") end - if string.match(ngx.var.uri, "^/ynhpanel.json$") then + if string.match(req_data['request_uri'], "^/ynhpanel.json$") then hlp.serve("/yunohost/sso/assets/js/ynhpanel.json") end -- If user has no access to this URL, redirect him to the portal if not hlp.has_access() then + ngx.log(ngx.DEBUG, "REDIRECT ACCESS DENIED") return hlp.redirect(conf.portal_url) end @@ -328,8 +360,8 @@ end if conf["unprotected_urls"] then for _, url in ipairs(conf["unprotected_urls"]) do - if (hlp.string.starts(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), url) - or hlp.string.starts(ngx.var.uri..hlp.uri_args_string(), url)) + if (hlp.string.starts(req_data["host"]..req_data['request_uri'], url) + or hlp.string.starts(req_data['request_uri'], url)) and not is_protected() then if hlp.is_logged_in() then hlp.set_headers() @@ -341,8 +373,8 @@ end if conf["unprotected_regex"] then for _, regex in ipairs(conf["unprotected_regex"]) do - if (string.match(ngx.var.host..ngx.var.uri..hlp.uri_args_string(), regex) - or string.match(ngx.var.uri..hlp.uri_args_string(), regex)) + if (string.match(req_data["host"]..req_data['request_uri'], regex) + or string.match(req_data['request_uri'], regex)) and not is_protected() then if hlp.is_logged_in() then hlp.set_headers() @@ -376,6 +408,7 @@ if auth_header then -- If user has no access to this URL, redirect him to the portal if not hlp.has_access(user) then + ngx.log(ngx.DEBUG, "REDIRECT BASIC AUTH OK") return hlp.redirect(conf.portal_url) end @@ -392,5 +425,6 @@ end -- hlp.flash("info", hlp.t("please_login")) -local back_url = ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.uri .. hlp.uri_args_string() +local back_url = req_data["scheme"] .. "://" .. req_data["host"] .. req_data['request_uri'] +ngx.log(ngx.DEBUG, "REDIRECT BY DEFAULT") return hlp.redirect(conf.portal_url.."?r="..ngx.encode_base64(back_url)) diff --git a/conf.json.example b/conf.json.example index 84e5118..d6f9e8b 100644 --- a/conf.json.example +++ b/conf.json.example @@ -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" } } diff --git a/config.lua b/config.lua index ab31ebd..597d0dc 100644 --- a/config.lua +++ b/config.lua @@ -33,7 +33,7 @@ function get_config() -- Else just take the persistent rule's value else conf[k] = v - end + end end end @@ -41,16 +41,21 @@ function get_config() -- Default configuration values default_conf = { portal_scheme = "https", - portal_path = "/ssowat", + 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", ldap_host = "localhost", ldap_group = "ou=users,dc=yunohost,dc=org", ldap_identifier = "uid", + 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, default_language = "en" } diff --git a/headers.lua b/headers.lua new file mode 100644 index 0000000..f173324 --- /dev/null +++ b/headers.lua @@ -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 diff --git a/helpers.lua b/helpers.lua index ea7f67b..7eb6b58 100644 --- a/helpers.lua +++ b/helpers.lua @@ -9,6 +9,14 @@ module('helpers', package.seeall) local cache = ngx.shared.cache local conf = config.get_config() +local req_data + +-- Local store for the request data, because: +-- - some data is cleared along the process but is still needed (eg. request_uri) +-- - repeatedly reading ngx.var or ngx.ctx is bad for memory usage and performance +function set_req_data(data) + req_data = data +end -- Read a FS stored file function read_file(file) @@ -47,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) @@ -169,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 @@ -225,7 +238,7 @@ end -- of the configuration file function has_access(user, url) user = user or authUser - url = url or ngx.var.host..ngx.var.uri + url = url or req_data["host"]..req_data['request_uri'] if not conf["users"][user] then conf = config.get_config() @@ -242,7 +255,7 @@ function has_access(user, url) -- Replace the original domain by a local one if you are connected from -- a non-global domain name. - if ngx.var.host == conf["local_portal_domain"] then + if req_data["host"] == conf["local_portal_domain"] then u = string.gsub(u, conf["original_portal_domain"], conf["local_portal_domain"]) end @@ -293,7 +306,9 @@ function authenticate(user, password) -- cache shared table in order to eventually reuse it later when updating -- profile information or just passing credentials to an application. if connected then - ensure_user_password_uses_strong_hash(connected, user, password) + if conf['ldap_enforce_crypt'] then + ensure_user_password_uses_strong_hash(connected, user, password) + end cache:add(user.."-password", password, conf["session_timeout"]) ngx.log(ngx.NOTICE, "Connected as: "..user) return user @@ -322,20 +337,13 @@ end -- Set the authentication headers in order to pass credentials to the -- application underneath. function set_headers(user) - - -- We definitely don't want to pass credentials on a non-encrypted - -- connection. - if ngx.var.scheme ~= "https" then - return redirect("https://"..ngx.var.host..ngx.var.uri..uri_args_string()) - end - local user = user or authUser -- If the password is not in cache or if the cache has expired, ask for -- logging. if not cache:get(user.."-password") then flash("info", t("please_login")) - local back_url = ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.uri .. uri_args_string() + local back_url = req_data["scheme"] .. "://" .. req_data["host"] .. req_data['request_uri'] return redirect(conf.portal_url.."?r="..ngx.encode_base64(back_url)) end @@ -545,14 +553,16 @@ function get_data_for(view) -- Add user's accessible URLs using the ACLs. -- It is typically used to build the app list. - for url, name in pairs(conf["users"][user]) do + if conf["users"][user] then + for url, name in pairs(conf["users"][user]) do - if ngx.var.host == conf["local_portal_domain"] then - url = string.gsub(url, conf["original_portal_domain"], conf["local_portal_domain"]) + if req_data["host"] == conf["local_portal_domain"] then + url = string.gsub(url, conf["original_portal_domain"], conf["local_portal_domain"]) + end + table.insert(sorted_apps, name) + table.sort(sorted_apps) + table.insert(data["app"], index_of(sorted_apps, name), { url = url, name = name }) end - table.insert(sorted_apps, name) - table.sort(sorted_apps) - table.insert(data["app"], index_of(sorted_apps, name), { url = url, name = name }) end end @@ -575,12 +585,13 @@ end -- if it's not the case, it migrates the password to this new hash algorithm function ensure_user_password_uses_strong_hash(ldap, user, password) local current_hashed_password = nil + conf = config.get_config() for dn, attrs in ldap:search { - base = "ou=users,dc=yunohost,dc=org", + base = conf['ldap_group'], scope = "onelevel", sizelimit = 1, - filter = "(uid="..user..")", + filter = "("..conf['ldap_identifier'].."="..user..")", attrs = {"userPassword"} } do current_hashed_password = attrs["userPassword"]:sub(0, 10) @@ -618,7 +629,7 @@ function edit_user() -- In case of a password modification -- TODO: split this into a new function - if string.ends(ngx.var.uri, "password.html") then + if string.ends(req_data["uri"], "password.html") then -- Check current password against the cached one if args.currentpassword @@ -654,7 +665,7 @@ function edit_user() -- In case of profile modification -- TODO: split this into a new function - elseif string.ends(ngx.var.uri, "edit.html") then + elseif string.ends(req_data["uri"], "edit.html") then -- Check that needed arguments exist if args.givenName and args.sn and args.mail then @@ -857,7 +868,7 @@ function login() local user = authenticate(args.user, args.password) if user then ngx.status = ngx.HTTP_CREATED - set_auth_cookie(user, ngx.var.host) + set_auth_cookie(user, req_data["host"]) else ngx.status = ngx.HTTP_UNAUTHORIZED flash("fail", t("wrong_username_password")) @@ -877,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 @@ -906,9 +975,9 @@ function pass() delete_redirect_cookie() -- When we are in the SSOwat portal, we need a default `content-type` - if string.ends(ngx.var.uri, "/") - or string.ends(ngx.var.uri, ".html") - or string.ends(ngx.var.uri, ".htm") + if string.ends(req_data["uri"], "/") + or string.ends(req_data["uri"], ".html") + or string.ends(req_data["uri"], ".htm") then ngx.header["Content-Type"] = "text/html" end