Skip to content

Commit

Permalink
restrict zero-pixel image logout to actual image requests
Browse files Browse the repository at this point in the history
should fix #521
  • Loading branch information
bodewig committed Aug 25, 2024
1 parent 9f3a4fc commit d284d71
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
08/25/2024
- don't return a zero-pixel image in logout for Firefox 128 and later
see #521

03/10/2023
- when looking for a bearer token an exception occured if the
Authorization header didn't contain any space character;
Expand Down
37 changes: 34 additions & 3 deletions lib/resty/openidc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,38 @@ local openidc_transparent_pixel = "\137\080\078\071\013\010\026\010\000\000\000\
"\002\007\001\002\154\028\049\113\000\000\000\000\073\069\078\068" ..
"\174\066\096\130"

local function request_prefers_png_over_html()
local headers = ngx.req.get_headers()
local header = get_first(headers['Accept'])
if not header then return false end

-- https://httpwg.org/specs/rfc9110.html#field.accept
local accepted = {}
local function append_accepted_type(media_range_and_quality)
local media_range, quality = media_range_and_quality:match("(.+)%s*;%s*q=%s*([^%s]+)")
if media_range and quality then
accepted[#accepted + 1] = {media_range=media_range, quality=tonumber(quality)}
else
accepted[#accepted + 1] = {media_range=media_range_and_quality, quality=1}
end
end
header:gsub("[^,]+", append_accepted_type)

table.sort(accepted, function(a1, a2)
return a1.quality > a2.quality
end)

for _, a in ipairs(accepted) do
if a.media_range:find("text/html") then
return false
end
if a.media_range:find("image/png") then
return true
end
end
return false
end

-- handle logout
local function openidc_logout(opts, session)
local session_token = session.data.enc_id_token
Expand Down Expand Up @@ -1308,9 +1340,8 @@ local function openidc_logout(opts, session)
end
end

local headers = ngx.req.get_headers()
local header = get_first(headers['Accept'])
if header and header:find("image/png") then
if request_prefers_png_over_html() then
-- support for Ping Federate's proprietary logout protocol
ngx.header["Cache-Control"] = "no-cache, no-store"
ngx.header["Pragma"] = "no-cache"
ngx.header["P3P"] = "CAO PSA OUR"
Expand Down
22 changes: 21 additions & 1 deletion tests/spec/logout_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ describe("when the configured logout uri is invoked with a non-image request", f
end)
end)

describe("when the configured logout uri is invoked with Firefox 128's default Accept", function()
test_support.start_server()
teardown(test_support.stop_server)
local _, _, cookie = test_support.login()
local _, status, headers = http.request({
url = "http://127.0.0.1/default/logout",
headers = { cookie = cookie, accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8" },
redirect = false
})
it("the response contains a default HTML-page", function()
assert.are.equals(200, status)
assert.are.equals("text/html", headers["content-type"])
-- TODO should there be a Cache-Control header?
end)
it("the session cookie has been revoked", function()
assert.truthy(string.match(headers["set-cookie"],
"session=; Expires=Thu, 01 Jan 1970 00:00:01 GMT.*"))
end)
end)

describe("when the configured logout uri is invoked with a png request", function()
-- TODO should this really take precedence over a configured end_session_endpoint?
test_support.start_server({
Expand All @@ -38,7 +58,7 @@ describe("when the configured logout uri is invoked with a png request", functio
headers = { cookie = cookie, accept = "image/png" },
redirect = false
})
it("the response contains a default HTML-page", function()
it("the response contains a default PNG image", function()
assert.are.equals(200, status)
assert.are.equals("image/png", headers["content-type"])
assert.are.equals("no-cache, no-store", headers["cache-control"])
Expand Down

0 comments on commit d284d71

Please sign in to comment.