Skip to content

Commit

Permalink
suport OpenID Connect Front Channel Logout
Browse files Browse the repository at this point in the history
see #308

Signed-off-by: Stefan Bodewig <[email protected]>
  • Loading branch information
bodewig committed Aug 21, 2020
1 parent c28093f commit 615a053
Show file tree
Hide file tree
Showing 5 changed files with 429 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
endpoint if this has not been done before in order to detect the URI
of the userinfo endpoint

03/27/2020
- added a function that implements OpenID Connect Front Channel Logout

02/06/2020
- ability to disable keepalive from lua-resty-http
By disabling keepalive we disable the native connection pool,
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,43 @@ local res, err, target, session = require("resty.openidc").authenticate(opts)
session:close()
```

## Front-Channel Logout

The `front_channel_logout` function can be used as a content handler
to implement [OpenID Connect Front-Channel
Logout](https://openid.net/specs/openid-connect-frontchannel-1_0.html).

```nginx
...
location /fc-logout {
content_by_lua_block {
local opts = {
-- session_required = true,
-- If this parameter is not set or set to true, requests to
-- the front channel logout URI must include the iss and sid
-- parameters.
-- This also requires id_tokens to be stored inside of the session.
-- Default is true
-- opts.iss = '...',
-- if session_required is false the iss parameter can be
-- compared to a hard-coded iss value.
-- Default is nil
-- downstream_logout = { 'other-uri', 'yet-another-uri' }
-- can contain a table of URIs to be notified via new iframes
-- included inside of the response
-- Default is no downstream logout URIs at all
}
require("resty.openidc").front_channel_logout(opts)
}
}
```

The `front_channel_logout` accepts as an optional second argument a
table that is passed to `session.open` in order to read the existing
session.

## Sample Configuration for OAuth 2.0 JWT Token Validation

Sample `nginx.conf` configuration for verifying Bearer JWT Access Tokens against a pre-configured secret/key.
Expand Down
58 changes: 58 additions & 0 deletions lib/resty/openidc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1741,4 +1741,62 @@ function openidc.set_logging(new_log, new_levels)
WARN = new_levels.WARN and new_levels.WARN or ngx.WARN
end

function openidc.front_channel_logout(opts, session_opts)
local session, is_existing = r_session.open(session_opts)
local logout_success = true
log(DEBUG, 'Front-Channel Logout invoked')
if not is_existing then
log(WARN, 'no session present, nothing to do')
logout_success = false
else
if not session.started then
session:start()
end
local args = ngx.req.get_uri_args()
if not (args.sid and args.iss) then
log(DEBUG, 'Front-Channel Logout invoked without sid or iss')
if opts.session_required == nil or opts.session_required then
log(ERROR, 'deny logout as the required session information is missing')
logout_success = false
end
else
local id_token = session.data.id_token
if (opts.session_required == nil or opts.session_required) and not id_token then
log(ERROR, 'as id_token is not stored in session and session is required')
logout_success = false
end
if id_token and id_token.sid and id_token.sid ~= args.sid then
log(ERROR, 'Front-Channel Logout sid argument is different from sid stored in id_token')
logout_success = false
end
if id_token and id_token.iss and id_token.iss ~= args.iss then
log(ERROR, 'Front-Channel Logout iss argument is different from iss stored in id_token')
logout_success = false
end
if not id_token and opts and opts.iss and opts.iss ~= args.iss then
log(ERROR, 'Front-Channel Logout iss argument is different from iss stored in opts')
logout_success = false
end
end
end
ngx.header['Cache-Control'] = 'no-cache, no-store'
ngx.header['Pragma'] = 'no-cache'
ngx.header.content_type = 'text/html'
if logout_success then
log(DEBUG, 'Performing Front-Channel Logout')
session:destroy()
end
ngx.print('<html><body>')
if logout_success and opts.downstream_logout then
local downstream = type(opts.downstream_logout) == 'table' and opts.downstream_logout
or { opts.downstream_logout }
local _, d
for _, d in pairs(downstream) do
log(DEBUG, 'also notify ', d)
ngx.print('<iframe src="' .. d .. '">')
end
end
ngx.print('</body></html>')
end

return openidc
Loading

0 comments on commit 615a053

Please sign in to comment.