From cdaf824996d2b499de4c72852c91733872137c9c Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Tue, 9 Jul 2019 15:11:35 +0200 Subject: [PATCH] try to read introspection_endpoint from discovery as fallback see #255 Signed-off-by: Stefan Bodewig --- ChangeLog | 1 + README.md | 7 ++++++ lib/resty/openidc.lua | 17 +++++++++++++- tests/spec/introspection_spec.lua | 38 +++++++++++++++++++++++++++++++ tests/spec/test_support.lua | 5 ++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 78271a0..05bfa70 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ - added unauth_action='deny' to reject unauthenticated requests rather than start the authorization code grant flow; see #271; based on suggested change by @nmaniwa +- read introspection_endpoint from discovery document when present; see #255 05/01/2019 - performance enhancement by caching the result of ngx.req.get_headers diff --git a/README.md b/README.md index cbdf485..8f4cbd7 100644 --- a/README.md +++ b/README.md @@ -490,7 +490,14 @@ http { access_by_lua ' local opts = { + -- sets the URI of the introspection endpoint introspection_endpoint="https://localhost:9031/oauth2/introspect", + + -- alternatively if your OAuth2 Provider provides a discovery document that contains the + -- introspection_endpoint claim you can leave the introspection_endpoint option + -- unset and instead use + -- discovery = "https://my-oauth2-provider/.well-known/oauth-authorization-server", + client_id="admin", client_secret="demo-password", ssl_verify = "no", diff --git a/lib/resty/openidc.lua b/lib/resty/openidc.lua index 337f970..4b03775 100644 --- a/lib/resty/openidc.lua +++ b/lib/resty/openidc.lua @@ -414,6 +414,10 @@ function openidc.call_token_endpoint(opts, endpoint, body, auth, endpoint_name, local ignore_body_on_success = ignore_body_on_success or false local ep_name = endpoint_name or 'token' + if not endpoint then + return nil, 'no endpoint URI for ' .. ep_name + end + local headers = { ["Content-Type"] = "application/x-www-form-urlencoded" } @@ -1603,7 +1607,18 @@ function openidc.introspect(opts) end -- call the introspection endpoint - json, err = openidc.call_token_endpoint(opts, opts.introspection_endpoint, body, opts.introspection_endpoint_auth_method, "introspection") + local introspection_endpoint = opts.introspection_endpoint + if not introspection_endpoint then + err = openidc_ensure_discovered_data(opts) + if err then + return nil, "opts.introspection_endpoint not said and " .. err + end + local endpoint = opts.discovery and opts.discovery.introspection_endpoint + if endpoint then + introspection_endpoint = endpoint + end + end + json, err = openidc.call_token_endpoint(opts, introspection_endpoint, body, opts.introspection_endpoint_auth_method, "introspection") if not json then diff --git a/tests/spec/introspection_spec.lua b/tests/spec/introspection_spec.lua index c5b1cde..a9efd8b 100644 --- a/tests/spec/introspection_spec.lua +++ b/tests/spec/introspection_spec.lua @@ -526,3 +526,41 @@ describe("when a request_decorator has been specified when calling the token end end) end) +describe("when introspection endpoint hasn't been specified", function() + test_support.start_server({ + remove_introspection_config_keys = { 'introspection_endpoint' } + }) + teardown(test_support.stop_server) + local jwt = test_support.trim(http.request("http://127.0.0.1/jwt")) + local _, status = http.request({ + url = "http://127.0.0.1/introspect", + headers = { authorization = "Bearer " .. jwt } + }) + it("the response is invalid", function() + assert.are.equals(401, status) + end) + it("an error has been logged", function() + assert.error_log_contains("Introspection error: no endpoint URI for introspection") + end) +end) + +describe("when introspection endpoint hasn't been specified but discovery doc provides introspection_endpoint claim", function() + test_support.start_server({ + remove_introspection_config_keys = { 'introspection_endpoint' }, + introspection_opts = { + discovery = { + introspection_endpoint = "http://127.0.0.1/introspection" + } + }, + }) + teardown(test_support.stop_server) + local jwt = test_support.trim(http.request("http://127.0.0.1/jwt")) + local _, status = http.request({ + url = "http://127.0.0.1/introspect", + headers = { authorization = "Bearer " .. jwt } + }) + it("the response is valid", function() + assert.are.equals(200, status) + end) +end) + diff --git a/tests/spec/test_support.lua b/tests/spec/test_support.lua index a6425ca..b420e15 100644 --- a/tests/spec/test_support.lua +++ b/tests/spec/test_support.lua @@ -450,6 +450,9 @@ local function write_config(out, custom_config) for _, k in ipairs(custom_config["remove_oidc_config_keys"] or {}) do oidc_config[k] = nil end + for _, k in ipairs(custom_config["remove_introspection_config_keys"] or {}) do + introspection_opts[k] = nil + end local config = DEFAULT_CONFIG_TEMPLATE :gsub("OIDC_CONFIG", serpent.block(oidc_config, {comment = false })) :gsub("TOKEN_HEADER", serpent.block(token_header, {comment = false })) @@ -501,6 +504,8 @@ end -- the introspection endpoint -- - remove_introspection_claims is an array of claims to remove from the introspection response -- - introspection_opts is a table containing options that are accepted by oidc.introspect +-- - remove_introspection_config_keys is an array of claims to remove from the introspection +-- configuration -- - token_response_expires_in value for the expires_in claim of the token response -- - token_response_contains_refresh_token whether to include a -- refresh token with the token response (a boolean in quotes, i.e. "true" or "false")