Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for anonymous usage to chain authentication plugins #103

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .github/ ISSUE_TEMPLATE.md

This file was deleted.

103 changes: 100 additions & 3 deletions kong/plugins/oidc/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,77 @@ local utils = require("kong.plugins.oidc.utils")
local filter = require("kong.plugins.oidc.filter")
local session = require("kong.plugins.oidc.session")

OidcHandler.PRIORITY = 1000
local constants = require "kong.constants"

local kong = kong

OidcHandler.PRIORITY = 1002

local function internal_server_error(err)
kong.log.err(err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
end

local function set_consumer(consumer, credential, token)
local set_header = kong.service.request.set_header
local clear_header = kong.service.request.clear_header

if consumer and consumer.id then
set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
else
clear_header(constants.HEADERS.CONSUMER_ID)
end

if consumer and consumer.custom_id then
set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
else
clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID)
end

if consumer and consumer.username then
set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
else
clear_header(constants.HEADERS.CONSUMER_USERNAME)
end

kong.client.authenticate(consumer, credential)

if credential then
if token.scope then
set_header("x-authenticated-scope", token.scope)
else
clear_header("x-authenticated-scope")
end

if token.authenticated_userid then
set_header("x-authenticated-userid", token.authenticated_userid)
else
clear_header("x-authenticated-userid")
end

clear_header(constants.HEADERS.ANONYMOUS) -- in case of auth plugins concatenation

else
set_header(constants.HEADERS.ANONYMOUS, true)
clear_header("x-authenticated-scope")
clear_header("x-authenticated-userid")
end

end

function OidcHandler:new()
OidcHandler.super.new(self, "oidc")
end

function OidcHandler:access(config)
OidcHandler.super.access(self)

if config.anonymous and kong.client.get_credential() then
-- we're already authenticated, and we're configured for using anonymous,
-- hence we're in a logical OR between auth methods and we're already done.
return
end

local oidcConfig = utils.get_options(config, ngx)

if filter.shouldProcessRequest(oidcConfig) then
Expand All @@ -38,6 +100,10 @@ function handle(oidcConfig)
response = make_oidc(oidcConfig)
if response then
if (response.user) then
local tmp_user = response.user
tmp_user.id = response.user.sub
tmp_user.username = response.user.preferred_username
set_consumer(tmp_user, nil, nil)
utils.injectUser(response.user)
end
if (response.access_token) then
Expand All @@ -58,7 +124,21 @@ function make_oidc(oidcConfig)
ngx.log(ngx.DEBUG, "Entering recovery page: " .. oidcConfig.recovery_page_path)
ngx.redirect(oidcConfig.recovery_page_path)
end
utils.exit(500, err, ngx.HTTP_INTERNAL_SERVER_ERROR)
if oidcConfig.anonymous then
-- get anonymous user
local consumer_cache_key = kong.db.consumers:cache_key(oidcConfig.anonymous)
local consumer, err = kong.cache:get(consumer_cache_key, nil,
load_consumer_into_memory,
oidcConfig.anonymous, true)
if err then
return internal_server_error(err)
end

set_consumer(consumer, nil, nil)

else
return kong.response.exit(err.status, err.message, err.headers)
end
end
return res
end
Expand All @@ -69,7 +149,22 @@ function introspect(oidcConfig)
if err then
if oidcConfig.bearer_only == "yes" then
ngx.header["WWW-Authenticate"] = 'Bearer realm="' .. oidcConfig.realm .. '",error="' .. err .. '"'
utils.exit(ngx.HTTP_UNAUTHORIZED, err, ngx.HTTP_UNAUTHORIZED)
if oidcConfig.anonymous then
-- get anonymous user
local consumer_cache_key = kong.db.consumers:cache_key(oidcConfig.anonymous)
local consumer, err = kong.cache:get(consumer_cache_key, nil,
load_consumer_into_memory,
oidcConfig.anonymous, true)
if err then
return internal_server_error(err)
end

set_consumer(consumer, nil, nil)

else
return kong.response.exit(err.status, err.message, err.headers)
end

end
return nil
end
Expand All @@ -79,5 +174,7 @@ function introspect(oidcConfig)
return nil
end

-- TESTING


return OidcHandler
57 changes: 37 additions & 20 deletions kong/plugins/oidc/schema.lua
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
local typedefs = require "kong.db.schema.typedefs"

local function validate_flows(config)

return true

end

return {
no_consumer = true,
name = "oidc",
fields = {
client_id = { type = "string", required = true },
client_secret = { type = "string", required = true },
discovery = { type = "string", required = true, default = "https://.well-known/openid-configuration" },
introspection_endpoint = { type = "string", required = false },
timeout = { type = "number", required = false },
introspection_endpoint_auth_method = { type = "string", required = false },
bearer_only = { type = "string", required = true, default = "no" },
realm = { type = "string", required = true, default = "kong" },
redirect_uri_path = { type = "string" },
scope = { type = "string", required = true, default = "openid" },
response_type = { type = "string", required = true, default = "code" },
ssl_verify = { type = "string", required = true, default = "no" },
token_endpoint_auth_method = { type = "string", required = true, default = "client_secret_post" },
session_secret = { type = "string", required = false },
recovery_page_path = { type = "string" },
logout_path = { type = "string", required = false, default = '/logout' },
redirect_after_logout_uri = { type = "string", required = false, default = '/' },
filters = { type = "string" }
}
{ consumer = typedefs.no_consumer },
{ config = {
type = "record",
fields = {
{ anonymous = { type = "string", uuid = true, legacy = true }, },
{client_id = { type = "string", required = true, default = "konglocal" }},
{client_secret = { type = "string", required = true, default = "kongapigateway" }},
{discovery = { type = "string", required = true, default = "https://cas.example.org:8453/cas/oidc/.well-known/openid-configuration" }},
{introspection_endpoint = { type = "string", required = false }},
{timeout = { type = "number", required = false }},
{introspection_endpoint_auth_method = { type = "string", required = false }},
{bearer_only = { type = "string", required = true, default = "no" }},
{realm = { type = "string", required = true, default = "kong" }},
{redirect_uri_path = { type = "string" }},
{scope = { type = "string", required = true, default = "openid" }},
{response_type = { type = "string", required = true, default = "code" }},
{ssl_verify = { type = "string", required = true, default = "no" }},
{token_endpoint_auth_method = { type = "string", required = true, default = "client_secret_post" }},
{session_secret = { type = "string", required = false }},
{recovery_page_path = { type = "string" }},
{logout_path = { type = "string", required = false, default = '/logout' }},
{redirect_after_logout_uri = { type = "string", required = false, default = '/' }},
{filters = { type = "string" }}
},
custom_validator = validate_flows,
},
},
},
}
1 change: 1 addition & 0 deletions kong/plugins/oidc/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ end

function M.get_options(config, ngx)
return {
anonymous = config.anonymous,
client_id = config.client_id,
client_secret = config.client_secret,
discovery = config.discovery,
Expand Down