diff --git a/.github/ ISSUE_TEMPLATE.md b/.github/ ISSUE_TEMPLATE.md deleted file mode 100644 index cfa4ce28..00000000 --- a/.github/ ISSUE_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -1. Used Kong OIDC plugin version: - -2. Used Kong version: - -3. Kong OIDC plugin configuration: - -4. Used OIDC provider: - -5. Issue description: diff --git a/kong/plugins/oidc/handler.lua b/kong/plugins/oidc/handler.lua index 07f05af5..3f24e8a7 100644 --- a/kong/plugins/oidc/handler.lua +++ b/kong/plugins/oidc/handler.lua @@ -4,8 +4,63 @@ 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") @@ -13,6 +68,13 @@ 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 @@ -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 @@ -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 @@ -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 @@ -79,5 +174,7 @@ function introspect(oidcConfig) return nil end +-- TESTING + return OidcHandler diff --git a/kong/plugins/oidc/schema.lua b/kong/plugins/oidc/schema.lua index ffb55b37..2a3d5a38 100644 --- a/kong/plugins/oidc/schema.lua +++ b/kong/plugins/oidc/schema.lua @@ -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, + }, + }, + }, } diff --git a/kong/plugins/oidc/utils.lua b/kong/plugins/oidc/utils.lua index 3686bbf6..fee13016 100644 --- a/kong/plugins/oidc/utils.lua +++ b/kong/plugins/oidc/utils.lua @@ -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,